templates/header.html.twig line 1

Open in your IDE?
  1. <header class="header-profesional fixed-top">
  2.     <div class="container-xl">
  3.         <div class="header-content">
  4.             
  5.             {# Logo y marca - Lado izquierdo #}
  6.             <div class="header-brand">
  7.                 {# Botón hamburguesa solo móvil #}
  8.                 <button class="mobile-toggle d-lg-none" type="button" aria-label="Menú principal">
  9.                     <span class="toggle-bar"></span>
  10.                     <span class="toggle-bar"></span>
  11.                     <span class="toggle-bar"></span>
  12.                 </button>
  13.                 <a href="{{ path('home_index') }}" class="brand-link">
  14.                     <div class="brand-logo">
  15.                         <img src="{{ asset('images/logo-clinica.png') }}" 
  16.                              data-logo-light="{{ asset('images/logo-clinica.png') }}"
  17.                              data-logo-dark="{{ asset('images/logo-clinica-dark.png') }}"
  18.                              alt="ImagingPro - Centro de Diagnóstico" 
  19.                              class="logo-img">
  20.                     </div>
  21.                 </a>
  22.             </div>
  23.             {# Navegación principal - Centro #}
  24.             <nav class="header-nav d-none d-lg-flex">
  25.                 <ul class="nav-menu">
  26.                     <li class="nav-item">
  27.                         <a href="{{ path('home_index') }}" class="nav-link active">
  28.                             <i class="bi bi-house-door"></i>
  29.                             <span class="nav-text" data-lang="es">Inicio</span>
  30.                             <span class="nav-text" data-lang="en" style="display:none;">Home</span>
  31.                         </a>
  32.                     </li>
  33.                     <li class="nav-item">
  34.                         <a href="{{ path('home_index') }}#servicios" class="nav-link">
  35.                             <i class="bi bi-cpu-fill"></i>
  36.                             <span class="nav-text" data-lang="es">Servicios</span>
  37.                             <span class="nav-text" data-lang="en" style="display:none;">Services</span>
  38.                         </a>
  39.                     </li>
  40.                     <li class="nav-item">
  41.                         <a href="{{ path('home_index') }}#experiencia" class="nav-link">
  42.                             <i class="bi bi-heart-pulse"></i>
  43.                             <span class="nav-text" data-lang="es">Excelencia Médica</span>
  44.                             <span class="nav-text" data-lang="en" style="display:none;">Medical Excellence</span>
  45.                         </a>
  46.                     </li>
  47.                     <li class="nav-item">
  48.                         <a href="{{ path('home_index') }}#contacto" class="nav-link">
  49.                             <i class="bi bi-telephone"></i>
  50.                             <span class="nav-text" data-lang="es">Contacto</span>
  51.                             <span class="nav-text" data-lang="en" style="display:none;">Contact</span>
  52.                         </a>
  53.                     </li>
  54.                     <li class="nav-item">
  55.                         <a href="{{ path('home_index') }}#formas-medicas" class="nav-link">
  56.                             <i class="fa fa-file-medical"></i>
  57.                             <span class="nav-text" data-lang="es">Formas Médicas</span>
  58.                             <span class="nav-text" data-lang="en" style="display:none;">Medical Forms</span>
  59.                         </a>
  60.                     </li>
  61.                 </ul>
  62.             </nav>
  63.             {# Acciones - Lado derecho #}
  64.             <div class="header-actions">
  65.                 {# Selector de idioma circular moderno #}
  66.                 <div class="language-selector-wrapper">
  67.                     <button class="language-trigger" id="languageTrigger">
  68.                         <span class="current-language">
  69.                             <span class="language-flag"></span>
  70.                         </span>
  71.                         <i class="bi bi-chevron-down language-chevron"></i>
  72.                     </button>
  73.                     
  74.                     <div class="language-dropdown">
  75.                         <div class="language-option" data-lang="es">
  76.                             <span class="option-flag"></span>
  77.                             <div class="option-content">
  78.                                 <span class="option-name" data-lang="es">Español</span>
  79.                                 <span class="option-name" data-lang="en" style="display:none;">Spanish</span>
  80.                                 <span class="option-code">ES</span>
  81.                             </div>
  82.                             <i class="bi bi-check2 option-check"></i>
  83.                         </div>
  84.                         
  85.                         <div class="language-option" data-lang="en">
  86.                             <span class="option-flag"></span>
  87.                             <div class="option-content">
  88.                                 <span class="option-name" data-lang="es">Inglés</span>
  89.                                 <span class="option-name" data-lang="en" style="display:none;">English</span>
  90.                                 <span class="option-code">US</span>
  91.                             </div>
  92.                             <i class="bi bi-check2 option-check"></i>
  93.                         </div>
  94.                     </div>
  95.                 </div>
  96.                 {# Botón modo oscuro/claro #}
  97.                 <button class="theme-toggle" id="themeToggle" aria-label="Cambiar tema">
  98.                     <i class="bi bi-sun-fill theme-icon"></i>
  99.                 </button>
  100.                 {# Botón agendar cita #}
  101.                 <button class="btn-agendar btn-primary" data-bs-toggle="modal" data-bs-target="#agendarCitaModal">
  102.                     <i class="bi bi-calendar-check"></i>
  103.                     <span class="btn-text" data-lang="es">Agendar Cita</span>
  104.                     <span class="btn-text" data-lang="en" style="display:none;">Book Appointment</span>
  105.                 </button>
  106.                 {# Botón portal médico #}
  107.                 <a href="{{ path('app_login') }}" class="btn-portal btn-outline">
  108.                     <i class="bi bi-speedometer2"></i>
  109.                     <span class="btn-text" data-lang="es">Portal Médico</span>
  110.                     <span class="btn-text" data-lang="en" style="display:none;">Medical Portal</span>
  111.                 </a>
  112.             </div>
  113.         </div>
  114.     </div>
  115.     {# Panel lateral móvil #}
  116.     <div class="mobile-sidebar d-lg-none">
  117.         <div class="sidebar-header">
  118.             <div class="sidebar-brand">
  119.                 <div class="brand-logo">
  120.                     <img src="{{ asset('images/logo-clinica.png') }}" 
  121.                          data-logo-light="{{ asset('images/logo-clinica.png') }}"
  122.                          data-logo-dark="{{ asset('images/logo-clinica-dark.png') }}"
  123.                          alt="ImagingPro - Centro de Diagnóstico" 
  124.                          class="logo-img">
  125.                 </div>
  126.             </div>
  127.             <button class="sidebar-close">
  128.                 <i class="bi bi-x-lg"></i>
  129.             </button>
  130.         </div>
  131.         
  132.         <nav class="sidebar-nav">
  133.             <ul class="sidebar-menu">
  134.                 <li class="sidebar-item">
  135.                     <a href="{{ path('home_index') }}" class="sidebar-link active">
  136.                         <i class="bi bi-house-door-fill"></i>
  137.                         <span data-lang="es">Inicio</span>
  138.                         <span data-lang="en" style="display:none;">Home</span>
  139.                     </a>
  140.                 </li>
  141.                 <li class="sidebar-item">
  142.                     <a href="{{ path('home_index') }}#servicios" class="sidebar-link">
  143.                         <i class="bi bi-heart-pulse"></i>
  144.                         <span data-lang="es">Servicios Médicos</span>
  145.                         <span data-lang="en" style="display:none;">Medical Services</span>
  146.                     </a>
  147.                 </li>
  148.                 <li class="sidebar-item">
  149.                     <a href="{{ path('home_index') }}#experiencia" class="sidebar-link">
  150.                         <i class="bi bi-award"></i>
  151.                         <span data-lang="es">Excelencia Médica</span>
  152.                         <span data-lang="en" style="display:none;">Medical Excellence</span>
  153.                     </a>
  154.                 </li>
  155.                 <li class="sidebar-item">
  156.                     <a href="{{ path('home_index') }}#contacto" class="sidebar-link">
  157.                         <i class="bi bi-telephone"></i>
  158.                         <span data-lang="es">Contacto</span>
  159.                         <span data-lang="en" style="display:none;">Contact</span>
  160.                     </a>
  161.                 </li>
  162.                 <li class="sidebar-item">
  163.                     <a href="{{ path('home_index') }}#formas-medicas" class="sidebar-link">
  164.                         <i class="fa fa-file-medical"></i>
  165.                         <span data-lang="es">Formas Médicas</span>
  166.                         <span data-lang="en" style="display:none;">Medical Forms</span>
  167.                     </a>
  168.                 </li>
  169.                 <li class="sidebar-divider"></li>
  170.                 <li class="sidebar-item">
  171.                     <a href="{{ path('app_login') }}" class="sidebar-link">
  172.                         <i class="bi bi-speedometer2"></i>
  173.                         <span data-lang="es">Portal Médico</span>
  174.                         <span data-lang="en" style="display:none;">Medical Portal</span>
  175.                     </a>
  176.                 </li>
  177.             </ul>
  178.         </nav>
  179.         
  180.         <div class="sidebar-footer">
  181.             <button class="btn-agendar-sidebar" data-bs-toggle="modal" data-bs-target="#agendarCitaModal">
  182.                 <i class="bi bi-calendar-check"></i>
  183.                 <span data-lang="es">Agendar Cita Rápida</span>
  184.                 <span data-lang="en" style="display:none;">Quick Appointment</span>
  185.             </button>
  186.         </div>
  187.     </div>
  188.     
  189.     <div class="sidebar-overlay"></div>
  190. </header>
  191. <style>
  192. /* ========== SELECTOR DE IDIOMA CIRCULAR PROFESIONAL ========== */
  193. .language-selector-wrapper {
  194.     position: relative;
  195.     display: inline-block;
  196. }
  197. /* BOTÓN CIRCULAR ELEGANTE - SOLO BANDERA */
  198. .language-trigger {
  199.     display: flex;
  200.     align-items: center;
  201.     justify-content: center;
  202.     width: 35px;
  203.     height: 35px;
  204.     background: var(--bg-white);
  205.     border: 2px solid var(--border-light);
  206.     border-radius: 50%;
  207.     cursor: pointer;
  208.     transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  209.     color: var(--text-dark);
  210.     font-weight: 500;
  211.     position: relative;
  212.     box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  213.     padding: 0;
  214. }
  215. .language-trigger:hover {
  216.     background: var(--bg-light);
  217.     border-color: var(--primary-blue);
  218.     transform: translateY(-2px);
  219.     box-shadow: 0 4px 12px rgba(26, 75, 140, 0.15);
  220. }
  221. .language-trigger.active {
  222.     background: var(--bg-light);
  223.     border-color: var(--primary-blue);
  224.     box-shadow: 0 4px 12px rgba(26, 75, 140, 0.2);
  225. }
  226. .language-trigger.active .language-chevron {
  227.     transform: rotate(180deg);
  228.     color: var(--primary-blue);
  229. }
  230. .current-language {
  231.     display: flex;
  232.     align-items: center;
  233.     justify-content: center;
  234.     width: 100%;
  235.     height: 100%;
  236. }
  237. .language-flag {
  238.     width: 20px;
  239.     height: 15px;
  240.     background-size: cover;
  241.     background-position: center;
  242.     border-radius: 2px;
  243.     color: transparent;
  244.     display: inline-block;
  245. }
  246. .language-chevron {
  247.     position: absolute;
  248.     bottom: 2px;
  249.     right: 2px;
  250.     font-size: 0.6rem;
  251.     color: var(--text-light);
  252.     background: var(--bg-white);
  253.     border-radius: 50%;
  254.     width: 14px;
  255.     height: 14px;
  256.     display: none;
  257.     align-items: center;
  258.     justify-content: center;
  259.     transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  260.     box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  261.     border: 1px solid var(--border-light);
  262. }
  263. /* DROPDOWN COMPACTO Y ELEGANTE */
  264. .language-dropdown {
  265.     position: absolute;
  266.     top: 100%;
  267.     right: 0;
  268.     margin-top: 0.75rem;
  269.     background: var(--bg-white);
  270.     border: 1.5px solid var(--border-light);
  271.     border-radius: 16px;
  272.     box-shadow: 0 12px 32px rgba(0,0,0,0.18);
  273.     min-width: 140px;
  274.     opacity: 0;
  275.     visibility: hidden;
  276.     transform: translateY(-12px) scale(0.95);
  277.     transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  278.     z-index: 1000;
  279.     overflow: hidden;
  280.     backdrop-filter: blur(10px);
  281. }
  282. .language-selector-wrapper.active .language-dropdown {
  283.     opacity: 1;
  284.     visibility: visible;
  285.     transform: translateY(0) scale(1);
  286. }
  287. .language-option {
  288.     display: flex;
  289.     align-items: center;
  290.     gap: 0.75rem;
  291.     padding: 0.75rem 1rem;
  292.     background: none;
  293.     border: none;
  294.     cursor: pointer;
  295.     transition: all 0.2s ease;
  296.     color: var(--text-dark);
  297.     width: 100%;
  298.     text-align: left;
  299.     border-bottom: 1px solid var(--border-light);
  300. }
  301. .language-option:last-child {
  302.     border-bottom: none;
  303. }
  304. .language-option:hover {
  305.     background: var(--bg-light);
  306.     transform: translateX(4px);
  307. }
  308. .language-option.active {
  309.     background: var(--primary-blue);
  310.     color: white;
  311. }
  312. .language-option.active .option-code {
  313.     color: rgba(255, 255, 255, 0.8);
  314. }
  315. .language-option.active .option-check {
  316.     opacity: 1;
  317.     color: white;
  318. }
  319. .option-content {
  320.     display: flex;
  321.     flex-direction: column;
  322.     gap: 0.1rem;
  323.     flex: 1;
  324. }
  325. .option-flag {
  326.     width: 20px;
  327.     height: 15px;
  328.     background-size: cover;
  329.     background-position: center;
  330.     border-radius: 2px;
  331.     display: inline-block;
  332. }
  333. .option-name {
  334.     font-weight: 500;
  335.     font-size: 0.8rem;
  336.     line-height: 1.2;
  337. }
  338. .option-code {
  339.     font-size: 0.7rem;
  340.     color: var(--text-light);
  341.     font-weight: 600;
  342.     line-height: 1;
  343. }
  344. .option-check {
  345.     font-size: 0.75rem;
  346.     color: var(--primary-blue);
  347.     opacity: 0;
  348.     transition: all 0.2s ease;
  349.     flex-shrink: 0;
  350. }
  351. /* ========== VARIABLES PARA MODO OSCURO MEJORADAS ========== */
  352. :root {
  353.     /* Colores modo claro (default) */
  354.     --bg-white: #ffffff;
  355.     --bg-light: #f8f9fa;
  356.     --text-dark: #2d3748;
  357.     --text-light: #718096;
  358.     --border-light: #e2e8f0;
  359.     --primary-blue: #1a4b8c;
  360.     --primary-blue-dark: #0d3a6e;
  361.     --shadow: 0 2px 10px rgba(0,0,0,0.08);
  362.     --shadow-hover: 0 4px 20px rgba(0,0,0,0.12);
  363. }
  364. [data-theme="dark"] {
  365.     /* Colores modo oscuro - TEXTO MÁS VISIBLE */
  366.     --bg-white: #1a202c;
  367.     --bg-light: #2d3748;
  368.     --text-dark: #e2e8f0;  /* TEXTO BLANCO GRISÁCEO PARA MEJOR VISIBILIDAD */
  369.     --text-light: #a0aec0; /* Texto secundario visible */
  370.     --border-light: #4a5568;
  371.     --primary-blue: #63b3ed; /* Azul claro para elementos principales */
  372.     --primary-blue-dark: #4299e1;
  373.     --shadow: 0 2px 10px rgba(0,0,0,0.3);
  374.     --shadow-hover: 0 4px 20px rgba(0,0,0,0.4);
  375. }
  376. /* Modo oscuro mejorado para el selector de idioma */
  377. [data-theme="dark"] .language-trigger {
  378.     border-color: #4a5568;
  379.     background: #2d3748;
  380. }
  381. [data-theme="dark"] .language-trigger:hover {
  382.     border-color: var(--primary-blue);
  383.     background: #4a5568;
  384. }
  385. [data-theme="dark"] .language-chevron {
  386.     background: #4a5568;
  387.     color: #a0aec0;
  388.     border-color: #4a5568;
  389. }
  390. [data-theme="dark"] .language-dropdown {
  391.     background: #2d3748;
  392.     border-color: #4a5568;
  393.     box-shadow: 0 12px 32px rgba(0,0,0,0.4);
  394. }
  395. [data-theme="dark"] .language-option {
  396.     border-bottom-color: #4a5568;
  397. }
  398. [data-theme="dark"] .language-option:hover {
  399.     background: #4a5568;
  400. }
  401. /* ========== LOGO CON DEGRADADO SOLO EN MODO OSCURO ========== */
  402. .brand-logo {
  403.     width: 250px;
  404.     height: 110px;
  405.     display: flex;
  406.     align-items: center;
  407.     justify-content: center;
  408.     overflow: hidden;
  409. }
  410. /* ========== BOTÓN TOGGLE ========== */
  411. .theme-toggle {
  412.     background: none;
  413.     border: none;
  414.     padding: 0.5rem;
  415.     border-radius: 50%;
  416.     cursor: pointer;
  417.     display: flex;
  418.     align-items: center;
  419.     justify-content: center;
  420.     width: 40px;
  421.     height: 40px;
  422.     transition: all 0.3s ease;
  423.     color: var(--text-dark);
  424. }
  425. .theme-toggle:hover {
  426.     background: var(--bg-light);
  427.     transform: scale(1.1);
  428. }
  429. .theme-icon {
  430.     font-size: 1.1rem;
  431.     transition: all 0.3s ease;
  432. }
  433. /* ========== HEADER MÁS COMPACTO ========== */
  434. .header-profesional {
  435.     background: var(--bg-white);
  436.     box-shadow: var(--shadow);
  437.     border-bottom: 1px solid var(--border-light);
  438.     padding: 0.75rem 0;
  439.     transition: all 0.3s ease;
  440.     z-index: 1030;
  441. }
  442. /* CONTENEDOR PRINCIPAL - ESPACIO JUSTO */
  443. .header-content {
  444.     display: flex;
  445.     align-items: center;
  446.     justify-content: space-between;
  447.     gap: 1rem; /* Reducido para dar espacio al selector de idioma */
  448. }
  449. /* NAVEGACIÓN - ITEMS MÁS COMPACTOS */
  450. .nav-menu {
  451.     display: flex;
  452.     align-items: center;
  453.     gap: 0.25rem;
  454.     list-style: none;
  455.     margin: 0;
  456.     padding: 0;
  457.     flex-wrap: nowrap;
  458.     white-space: nowrap;
  459. }
  460. .nav-link {
  461.     display: flex;
  462.     align-items: center;
  463.     gap: 0.3rem;
  464.     padding: 0.5rem 0.8rem;
  465.     color: var(--text-dark); /* Texto visible en ambos modos */
  466.     text-decoration: none;
  467.     font-weight: 500;
  468.     border-radius: 6px;
  469.     transition: all 0.3s ease;
  470.     font-size: 0.85rem;
  471.     white-space: nowrap;
  472. }
  473. [data-theme="dark"] .nav-link {
  474.     color: var(--primary-blue);
  475. }    
  476. .nav-link i {
  477.     color: var(--primary-blue); /* ICONOS AZUL CLARO en ambos modos */
  478.     transition: all 0.3s ease;
  479. }
  480. /* HOVER: SE PONEN BLANCOS en modo oscuro */
  481. [data-theme="dark"] .nav-link:hover,
  482. [data-theme="dark"] .nav-link.active {
  483.     background: var(--primary-blue);
  484.     color: white !important; /* Texto blanco en hover */
  485.     transform: translateY(-1px);
  486. }
  487. [data-theme="dark"] .nav-link:hover i,
  488. [data-theme="dark"] .nav-link.active i {
  489.     color: white !important; /* Iconos blancos en hover */
  490. }
  491. /* Estilos normales para modo claro */
  492. .nav-link:hover,
  493. .nav-link.active {
  494.     background: var(--primary-blue);
  495.     color: white;
  496.     transform: translateY(-1px);
  497. }
  498. .nav-link:hover i,
  499. .nav-link.active i {
  500.     color: white;
  501. }
  502. /* BOTONES - MÁS COMPACTOS */
  503. .header-actions {
  504.     display: flex;
  505.     align-items: center;
  506.     gap: 0.5rem; /* Reducido para mejor acomodo */
  507.     flex-shrink: 0;
  508. }
  509. .btn-agendar,
  510. .btn-portal {
  511.     display: flex;
  512.     align-items: center;
  513.     gap: 0.3rem;
  514.     padding: 0.5rem 0.9rem;
  515.     border-radius: 6px;
  516.     font-weight: 600;
  517.     text-decoration: none;
  518.     transition: all 0.3s ease;
  519.     border: none;
  520.     font-size: 0.85rem;
  521.     white-space: nowrap;
  522. }
  523. .btn-agendar {
  524.     background: linear-gradient(135deg, var(--primary-blue), var(--primary-blue-dark));
  525.     color: white;
  526.     box-shadow: 0 2px 10px rgba(26, 75, 140, 0.3);
  527. }
  528. .btn-agendar:hover {
  529.     transform: translateY(-2px);
  530.     box-shadow: 0 4px 15px rgba(26, 75, 140, 0.4);
  531.     color: white;
  532. }
  533. .btn-portal {
  534.     background: transparent;
  535.     color: var(--primary-blue);
  536.     border: 2px solid var(--primary-blue);
  537. }
  538. .btn-portal:hover {
  539.     background: var(--primary-blue);
  540.     color: white;
  541.     transform: translateY(-1px);
  542. }
  543. .brand-link {
  544.     display: flex;
  545.     align-items: center;
  546.     justify-content: center;
  547.     text-decoration: none;
  548.     color: inherit;
  549.     transition: all 0.3s ease;
  550. }
  551. .brand-link:hover {
  552.     transform: translateY(-2px);
  553. }
  554. .logo-img {
  555.     width: 100%;
  556.     height: auto;
  557.     object-fit: contain;
  558. }
  559. .header-nav {
  560.     flex: 1;
  561.     display: flex;
  562.     justify-content: center;
  563. }
  564. .nav-item {
  565.     position: relative;
  566. }
  567. .mobile-toggle {
  568.     background: none;
  569.     border: none;
  570.     padding: 0.5rem;
  571.     cursor: pointer;
  572.     display: flex;
  573.     flex-direction: column;
  574.     gap: 4px;
  575.     width: 32px;
  576.     height: 32px;
  577.     justify-content: center;
  578. }
  579. .toggle-bar {
  580.     width: 100%;
  581.     height: 2px;
  582.     background: var(--primary-blue);
  583.     border-radius: 2px;
  584.     transition: all 0.3s ease;
  585. }
  586. /* ========== SIDEBAR MÓVIL MEJORADO ========== */
  587. .mobile-sidebar {
  588.     position: fixed;
  589.     top: 0;
  590.     left: -100%;
  591.     width: 320px;
  592.     height: 100vh;
  593.     background: var(--bg-white);
  594.     box-shadow: var(--shadow-hover);
  595.     transition: left 0.3s ease;
  596.     z-index: 1040;
  597.     display: flex;
  598.     flex-direction: column;
  599. }
  600. .mobile-sidebar.active {
  601.     left: 0;
  602. }
  603. .sidebar-header {
  604.     display: flex;
  605.     align-items: center;
  606.     justify-content: space-between;
  607.     padding: 1.5rem;
  608.     border-bottom: 1px solid var(--border-light);
  609. }
  610. .sidebar-close {
  611.     background: none;
  612.     border: none;
  613.     font-size: 1.25rem;
  614.     color: var(--text-light);
  615.     cursor: pointer;
  616.     padding: 0.25rem;
  617. }
  618. .sidebar-nav {
  619.     flex: 1;
  620.     padding: 1rem 0;
  621. }
  622. .sidebar-menu {
  623.     list-style: none;
  624.     margin: 0;
  625.     padding: 0;
  626. }
  627. .sidebar-item {
  628.     margin-bottom: 0.25rem;
  629. }
  630. .sidebar-link {
  631.     display: flex;
  632.     align-items: center;
  633.     gap: 1rem;
  634.     padding: 1rem 1.5rem;
  635.     color: var(--text-dark); /* Texto visible en ambos modos */
  636.     text-decoration: none;
  637.     font-weight: 500;
  638.     transition: all 0.3s ease;
  639.     border-left: 3px solid transparent;
  640. }
  641. .sidebar-link i {
  642.     color: var(--primary-blue); /* ICONOS AZUL CLARO en ambos modos */
  643.     transition: all 0.3s ease;
  644. }
  645. /* HOVER EN SIDEBAR: SE PONEN BLANCOS en modo oscuro */
  646. [data-theme="dark"] .sidebar-link:hover,
  647. [data-theme="dark"] .sidebar-link.active {
  648.     background: var(--primary-blue);
  649.     color: white !important;
  650.     border-left-color: white;
  651. }
  652. [data-theme="dark"] .sidebar-link:hover i,
  653. [data-theme="dark"] .sidebar-link.active i {
  654.     color: white !important;
  655. }
  656. /* Estilos normales para modo claro */
  657. .sidebar-link:hover,
  658. .sidebar-link.active {
  659.     background: var(--bg-light);
  660.     color: var(--primary-blue);
  661.     border-left-color: var(--primary-blue);
  662. }
  663. .sidebar-link:hover i,
  664. .sidebar-link.active i {
  665.     color: var(--primary-blue);
  666. }
  667. .sidebar-divider {
  668.     height: 1px;
  669.     background: var(--border-light);
  670.     margin: 1rem 0;
  671. }
  672. .sidebar-footer {
  673.     padding: 1.5rem;
  674.     border-top: 1px solid var(--border-light);
  675. }
  676. .btn-agendar-sidebar {
  677.     width: 100%;
  678.     display: flex;
  679.     align-items: center;
  680.     justify-content: center;
  681.     gap: 0.5rem;
  682.     padding: 1rem;
  683.     background: linear-gradient(135deg, var(--primary-blue), var(--primary-blue-dark));
  684.     color: white;
  685.     border: none;
  686.     border-radius: 8px;
  687.     font-weight: 600;
  688.     transition: all 0.3s ease;
  689. }
  690. .btn-agendar-sidebar:hover {
  691.     transform: translateY(-2px);
  692.     box-shadow: 0 4px 15px rgba(26, 75, 140, 0.4);
  693. }
  694. .sidebar-overlay {
  695.     position: fixed;
  696.     top: 0;
  697.     left: 0;
  698.     width: 100%;
  699.     height: 100%;
  700.     background: rgba(0,0,0,0.5);
  701.     z-index: 1035;
  702.     opacity: 0;
  703.     visibility: hidden;
  704.     transition: all 0.3s ease;
  705. }
  706. .sidebar-overlay.active {
  707.     opacity: 1;
  708.     visibility: visible;
  709. }
  710. /* Responsive */
  711. @media (max-width: 1199.98px) {
  712.     .header-nav {
  713.         flex: 0.8;
  714.     }
  715. }
  716. @media (max-width: 991.98px) {
  717.     .header-content {
  718.         gap: 1rem;
  719.     }
  720.     
  721.     .btn-text {
  722.         display: none;
  723.     }
  724.     
  725.     .language-trigger {
  726.         width: 40px;
  727.         height: 40px;
  728.     }
  729.     
  730.     .language-flag {
  731.         font-size: 1.2rem;
  732.     }
  733.     
  734.     .language-chevron {
  735.         width: 12px;
  736.         height: 12px;
  737.         font-size: 0.5rem;
  738.     }
  739. }
  740. @media (max-width: 767.98px) {
  741.     .btn-agendar,
  742.     .btn-portal {
  743.         display: none;
  744.     }
  745.     
  746.     .language-selector-wrapper {
  747.         order: -1;
  748.     }
  749. }
  750. @media (max-width: 575.98px) {
  751.     .header-profesional {
  752.         padding: 0.5rem 0;
  753.     }
  754.     
  755.     .mobile-sidebar {
  756.         width: 280px;
  757.     }
  758.     
  759.     .header-actions {
  760.         gap: 0.25rem;
  761.     }
  762.     
  763.     .language-trigger {
  764.         width: 36px;
  765.         height: 36px;
  766.     }
  767.     
  768.     .language-flag {
  769.         font-size: 1.1rem;
  770.     }
  771. }
  772. </style>
  773. <script>
  774. document.addEventListener('DOMContentLoaded', function() {
  775.     // ========== SELECTOR DE IDIOMA - CLIENTE MANDRA ==========
  776.     const languageTrigger = document.getElementById('languageTrigger');
  777.     const languageOptions = document.querySelectorAll('.language-option');
  778.     const currentLangFlag = languageTrigger.querySelector('.language-flag');
  779.     const languageWrapper = document.querySelector('.language-selector-wrapper');
  780.     
  781.     // Definir las banderas SVG
  782.     const flagES = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 480'%3E%3Cpath fill='%23c60b1e' d='M0 0h640v480H0z'/%3E%3Cpath fill='%23ffc400' d='M0 120h640v240H0z'/%3E%3C/svg%3E";
  783.     const flagUS = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 480'%3E%3Cpath fill='%23bd3d44' d='M0 0h640v480H0z'/%3E%3Cpath stroke='%23fff' stroke-width='37' d='M0 55.3h640M0 129h640M0 203h640M0 277h640M0 351h640'/%3E%3Cpath fill='%23192f5d' d='M0 0h364.8v258.5H0z'/%3E%3Cpath fill='%23fff' d='m71 7 7 21.5L98 16l-12 17.5 21-2.5-14.5 16 19.5-7-16 13 16.5 12.5-20-1 12 18L89 57l6.5 20.5-15-15-2 21.5-9-19-10 19-1.5-21.5-15 15L43 57 29.5 68.5l12-18-20 1L38 39 22 52l19.5 7L27 42.5 48 45 36 27.5 50 33 35.5 17 57 24.5 36 16l15 12.5L71 7z'/%3E%3C/svg%3E";
  784.     // 1. PRIMERO: Obtener idioma del CLIENTE (localStorage)
  785.     const clientLang = localStorage.getItem('language') || 'es';
  786.     console.log('🚀 Idioma del CLIENTE:', clientLang);
  787.     
  788.     // 2. INICIALIZAR con el idioma del cliente (NO siempre España)
  789.     initializeLanguageSelector(clientLang);
  790.     
  791.     // 3. INMEDIATAMENTE: Aplicar idioma del cliente
  792.     applyLanguage(clientLang);
  793.     
  794.     // 4. LUEGO: Sincronizar Symfony con el cliente (en segundo plano)
  795.     forceSymfonyLanguage(clientLang);
  796.     
  797.     // Toggle del dropdown
  798.     languageTrigger.addEventListener('click', function(e) {
  799.         e.stopPropagation();
  800.         languageWrapper.classList.toggle('active');
  801.     });
  802.     
  803.     // Cambiar idioma al seleccionar una opción
  804.     languageOptions.forEach(option => {
  805.         option.addEventListener('click', function() {
  806.             const lang = this.getAttribute('data-lang');
  807.             changeLanguage(lang);
  808.         });
  809.     });
  810.     
  811.     // Cerrar dropdown al hacer clic fuera
  812.     document.addEventListener('click', function(e) {
  813.         if (!languageWrapper.contains(e.target)) {
  814.             languageWrapper.classList.remove('active');
  815.         }
  816.     });
  817.     
  818.     // FUNCIÓN CORREGIDA: Inicializar con el idioma del cliente
  819.     function initializeLanguageSelector(lang) {
  820.         console.log('🎨 Inicializando banderas con idioma:', lang);
  821.         
  822.         // Bandera inicial del trigger según el idioma guardado
  823.         if (lang === 'es') {
  824.             currentLangFlag.style.backgroundImage = `url("${flagES}")`;
  825.         } else {
  826.             currentLangFlag.style.backgroundImage = `url("${flagUS}")`;
  827.         }
  828.         
  829.         // Configurar banderas de las opciones
  830.         languageOptions.forEach(option => {
  831.             const optionFlag = option.querySelector('.option-flag');
  832.             const optionLang = option.getAttribute('data-lang');
  833.             
  834.             // Configurar bandera según cada opción
  835.             if (optionLang === 'es') {
  836.                 optionFlag.style.backgroundImage = `url("${flagES}")`;
  837.             } else {
  838.                 optionFlag.style.backgroundImage = `url("${flagUS}")`;
  839.             }
  840.         });
  841.     }
  842.     
  843.     // FUNCIÓN PRINCIPAL: Cambiar idioma (CLIENTE MANDRA)
  844.     async function changeLanguage(lang) {
  845.         try {
  846.             console.log('🔥 FORZANDO idioma:', lang);
  847.             
  848.             // 1. GUARDAR en localStorage (cliente)
  849.             localStorage.setItem('language', lang);
  850.             
  851.             // 2. INICIALIZAR banderas con el nuevo idioma
  852.             initializeLanguageSelector(lang);
  853.             
  854.             // 3. APLICAR INMEDIATAMENTE en frontend
  855.             applyLanguage(lang);
  856.             
  857.             // 4. FORZAR a Symfony a aceptar nuestro idioma
  858.             await forceSymfonyLanguage(lang);
  859.             
  860.             console.log('✅ Idioma forzado exitosamente:', lang);
  861.             
  862.         } catch (error) {
  863.             console.error('❌ Error al forzar idioma:', error);
  864.             // IMPORTANTE: El frontend YA tiene el idioma correcto
  865.         } finally {
  866.             // Cerrar dropdown
  867.             languageWrapper.classList.remove('active');
  868.         }
  869.     }
  870.     
  871.     // FUNCIÓN AGGRESIVA: Forzar idioma en Symfony
  872.     async function forceSymfonyLanguage(lang) {
  873.         try {
  874.             const response = await fetch('/change-language', {
  875.                 method: 'POST',
  876.                 headers: {
  877.                     'Content-Type': 'application/json',
  878.                     'X-Requested-With': 'XMLHttpRequest'
  879.                 },
  880.                 body: JSON.stringify({ 
  881.                     language: lang,
  882.                     force: true,
  883.                     source: 'client_override'
  884.                 })
  885.             });
  886.             
  887.             if (!response.ok) {
  888.                 throw new Error('Symfony rechazó el idioma');
  889.             }
  890.             
  891.             const result = await response.json();
  892.             console.log('🔄 Symfony sincronizado:', result);
  893.             
  894.         } catch (error) {
  895.             console.warn('⚠️ Symfony no respondió, pero el frontend está ok');
  896.         }
  897.     }
  898.     
  899.     // FUNCIÓN MEJORADA: Aplicar idioma (SIN DEPENDER DE SYMFONY)
  900.     function applyLanguage(lang) {
  901.         console.log('🎯 APLICANDO idioma del CLIENTE:', lang);
  902.         
  903.         // 1. Bandera principal (ya está configurada en initializeLanguageSelector)
  904.         if (lang === 'es') {
  905.             languageTrigger.setAttribute('aria-label', 'Cambiar idioma a English');
  906.         } else {
  907.             languageTrigger.setAttribute('aria-label', 'Change language to Spanish');
  908.         }
  909.         
  910.         // 2. Actualizar textos del DROPDOWN
  911.         updateDropdownTexts(lang);
  912.         
  913.         // 3. Actualizar checkmarks en las opciones
  914.         languageOptions.forEach(option => {
  915.             const optionLang = option.getAttribute('data-lang');
  916.             if (optionLang === lang) {
  917.                 option.classList.add('active');
  918.             } else {
  919.                 option.classList.remove('active');
  920.             }
  921.         });
  922.         
  923.         // 4. Actualizar TODOS los textos de la página
  924.         document.querySelectorAll('[data-lang]').forEach(element => {
  925.             // Excluir elementos dentro del language selector
  926.             if (element.closest('.language-selector-wrapper')) {
  927.                 return;
  928.             }
  929.             
  930.             const elementLang = element.getAttribute('data-lang');
  931.             const isNavText = element.classList.contains('nav-text');
  932.             const isBtnText = element.classList.contains('btn-text');
  933.             
  934.             if (elementLang === lang) {
  935.                 element.style.display = isNavText || isBtnText ? 'inline' : 'block';
  936.             } else {
  937.                 element.style.display = 'none';
  938.             }
  939.         });
  940.         
  941.         // 5. Forzar atributo HTML
  942.         document.documentElement.lang = lang;
  943.         
  944.         // 6. Placeholders
  945.         updateDynamicPlaceholders(lang);
  946.         
  947.         console.log('✅ Idioma del CLIENTE aplicado exitosamente');
  948.     }
  949.     
  950.     // NUEVA FUNCIÓN: Actualizar textos del dropdown
  951.     function updateDropdownTexts(lang) {
  952.         languageOptions.forEach(option => {
  953.             const optionLang = option.getAttribute('data-lang');
  954.             const optionNames = option.querySelectorAll('.option-name');
  955.             
  956.             optionNames.forEach(optionName => {
  957.                 const nameLang = optionName.getAttribute('data-lang');
  958.                 if (nameLang === lang) {
  959.                     optionName.style.display = 'block';
  960.                 } else {
  961.                     optionName.style.display = 'none';
  962.                 }
  963.             });
  964.         });
  965.     }
  966.     
  967.     // Función para actualizar placeholders dinámicamente
  968.     function updateDynamicPlaceholders(lang) {
  969.         const placeholders = {
  970.             'es': {
  971.                 'firstName': 'Tu nombre',
  972.                 'lastName': 'Tus apellidos', 
  973.                 'age': 'Tu edad',
  974.                 'phone': '+15555555555',
  975.                 'email': 'ejemplo@dominio.com',
  976.                 'observaciones': 'Información adicional que consideres relevante'
  977.             },
  978.             'en': {
  979.                 'firstName': 'Your name',
  980.                 'lastName': 'Your last name',
  981.                 'age': 'Your age',
  982.                 'phone': '+15555555555',
  983.                 'email': 'example@domain.com',
  984.                 'observaciones': 'Additional information you consider relevant'
  985.             }
  986.         };
  987.         
  988.         const currentPlaceholders = placeholders[lang] || placeholders['es'];
  989.         
  990.         Object.keys(currentPlaceholders).forEach(fieldId => {
  991.             const element = document.getElementById(fieldId);
  992.             if (element) {
  993.                 element.placeholder = currentPlaceholders[fieldId];
  994.             }
  995.         });
  996.     }
  997.     
  998.     // ========== FUNCIONALIDAD: MODO OSCURO ==========
  999.     const themeToggle = document.getElementById('themeToggle');
  1000.     const themeIcon = themeToggle.querySelector('.theme-icon');
  1001.     const html = document.documentElement;
  1002.     
  1003.     // Verificar preferencia guardada
  1004.     const savedTheme = localStorage.getItem('theme') || 'light';
  1005.     
  1006.     // Aplicar tema al cargar
  1007.     applyTheme(savedTheme);
  1008.     
  1009.     // Toggle del tema
  1010.     themeToggle.addEventListener('click', function() {
  1011.         const currentTheme = html.getAttribute('data-theme') || 'light';
  1012.         const newTheme = currentTheme === 'light' ? 'dark' : 'light';
  1013.         applyTheme(newTheme);
  1014.         localStorage.setItem('theme', newTheme);
  1015.     });
  1016.     
  1017.     function applyTheme(theme) {
  1018.         html.setAttribute('data-theme', theme);
  1019.         
  1020.         if (theme === 'dark') {
  1021.             themeIcon.className = 'bi bi-moon-fill theme-icon';
  1022.             themeToggle.setAttribute('aria-label', 'Cambiar a modo claro');
  1023.         } else {
  1024.             themeIcon.className = 'bi bi-sun-fill theme-icon';
  1025.             themeToggle.setAttribute('aria-label', 'Cambiar a modo oscuro');
  1026.         }
  1027.         
  1028.         updateLogoForDarkMode();
  1029.     }
  1030.     
  1031.     function updateLogoForDarkMode() {
  1032.         const logos = document.querySelectorAll('.logo-img[data-logo-dark]');
  1033.         const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
  1034.         const isDarkMode = currentTheme === 'dark';
  1035.         
  1036.         logos.forEach(logo => {
  1037.             const darkSrc = logo.getAttribute('data-logo-dark');
  1038.             const lightSrc = logo.getAttribute('data-logo-light') || logo.src;
  1039.             
  1040.             if (isDarkMode && darkSrc) {
  1041.                 logo.src = darkSrc;
  1042.             } else if (lightSrc) {
  1043.                 logo.src = lightSrc;
  1044.             }
  1045.         });
  1046.     }
  1047.     
  1048.     updateLogoForDarkMode();
  1049.     
  1050.     // ========== FUNCIONALIDAD EXISTENTE DEL HEADER ==========
  1051.     const mobileToggle = document.querySelector('.mobile-toggle');
  1052.     const sidebarClose = document.querySelector('.sidebar-close');
  1053.     const mobileSidebar = document.querySelector('.mobile-sidebar');
  1054.     const sidebarOverlay = document.querySelector('.sidebar-overlay');
  1055.     
  1056.     mobileToggle?.addEventListener('click', function() {
  1057.         mobileSidebar.classList.add('active');
  1058.         sidebarOverlay.classList.add('active');
  1059.         document.body.style.overflow = 'hidden';
  1060.     });
  1061.     
  1062.     function closeSidebar() {
  1063.         mobileSidebar.classList.remove('active');
  1064.         sidebarOverlay.classList.remove('active');
  1065.         document.body.style.overflow = '';
  1066.     }
  1067.     
  1068.     sidebarClose?.addEventListener('click', closeSidebar);
  1069.     sidebarOverlay?.addEventListener('click', closeSidebar);
  1070.     
  1071.     document.querySelectorAll('.sidebar-link').forEach(link => {
  1072.         link.addEventListener('click', closeSidebar);
  1073.     });
  1074.     
  1075.     let lastScroll = 0;
  1076.     const header = document.querySelector('.header-profesional');
  1077.     
  1078.     window.addEventListener('scroll', function() {
  1079.         const currentScroll = window.pageYOffset;
  1080.         
  1081.         if (currentScroll <= 0) {
  1082.             header.style.transform = 'translateY(0)';
  1083.             return;
  1084.         }
  1085.         
  1086.         if (currentScroll > lastScroll && currentScroll > 100) {
  1087.             header.style.transform = 'translateY(-100%)';
  1088.         } else {
  1089.             header.style.transform = 'translateY(0)';
  1090.         }
  1091.         
  1092.         lastScroll = currentScroll;
  1093.     });
  1094. });
  1095. </script>