/* ==========================================================================
   CAVELI Grupo Médico — hoja de estilos única
   HTML + CSS + JS puro. Sin build, sin dependencias. (CLAUDE.md · REGLA 1)
   Mobile-first: los estilos base son para celular; las media queries suben.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Marca */
  --navy:        #0E2A4E;
  --teal:        #0A7E92;
  --cyan:        #34CEE2;
  --cyan-soft:   #7FD8E6;
  --whatsapp:    #25D366;
  --whatsapp-dk: #1EBE5B;

  /* Superficies */
  --bg:          #FBFCFD;
  --surface:     #ffffff;
  --surface-alt: #F4F8FB;
  --surface-hi:  #F4FBFD;
  --hairline:    #e0e8f0;
  --border:      #e5eaf1;
  --border-firm: #dbe4ee;

  /* Texto — todos verificados a contraste WCAG AA sobre su fondo */
  --text:        #0E2A4E;  /* 14.8:1 sobre blanco */
  --text-body:   #48607c;  /*  6.5:1 */
  --text-muted:  #5b7290;  /*  4.9:1 */
  --text-soft:   #5E7085;  /*  5.1:1 — sustituye #6b7d92, #7b8a9c y #93a0b0,
                                 que reprobaban AA (4.2:1, 3.5:1 y 2.9:1) */

  /* Texto sobre navy */
  --on-navy:      #ffffff;
  --on-navy-soft: #b9c9da;  /* 8.5:1 sobre --navy */
  --on-navy-dim:  #8fa4bb;  /* 5.6:1 sobre --navy */

  /* Tipografía */
  --font-display: 'Space Grotesk', system-ui, sans-serif;
  --font-body:    'IBM Plex Sans', system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, monospace;

  /* Escala tipográfica — cuatro medidas y ninguna más.

     La regla para elegir, si algún día se agrega un componente:
       · ¿Es el titular de la página?        → --fs-titulo    (hay uno por página)
       · ¿Es un encabezado de sección,
         tarjeta o ficha?                    → --fs-subtitulo
       · ¿Es texto que se lee corrido —
         párrafo, enlace, botón, dato?       → --fs-texto
       · ¿Es una etiqueta en mayúsculas,
         con tracking y en mono?             → --fs-micro

     Antes de esto había 24 tamaños distintos, diez de ellos dentro de un
     rango de 4.5px: nadie distingue 13.5 de 14, así que no eran decisiones
     sino accidentes. No agregar un quinto valor: si algo no encaja en los
     cuatro, se ajusta con peso, color o espaciado, no con otro tamaño.

     Los dos primeros son fluidos: el mínimo es el tamaño en celular, el
     máximo el del diseño en escritorio. */
  --fs-titulo:    clamp(2.15rem, 1.15rem + 4.4vw, 4.125rem);   /* 34 → 66px */
  --fs-subtitulo: clamp(1.25rem, 1.05rem + 1.0vw, 1.6875rem);  /* 20 → 27px */
  --fs-texto:     1rem;                                        /*      16px */
  --fs-micro:     0.75rem;                                     /*      12px */

  /* Ritmo */
  --pad-x:      20px;
  /* 40px y no 56 en celular: con diez secciones, esos 16px de más arriba y
     abajo sumaban 320px, casi media pantalla de puro aire. De tableta en
     adelante sí hay sitio y sube. */
  --section-y:  40px;
  --radius:     16px;
  --radius-lg:  18px;
  --wrap:       1240px;

  /* Movimiento */
  --ease:       cubic-bezier(.2, .8, .2, 1);
  --lift-shadow: 0 26px 54px -34px rgba(14, 42, 78, .55);
}

@media (min-width: 768px) {
  :root { --pad-x: 32px; --section-y: 72px; }
}
@media (min-width: 1100px) {
  :root { --pad-x: 44px; --section-y: 88px; }
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-texto);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: var(--text); text-decoration: none; }
a:hover { color: var(--teal); }

img { max-width: 100%; height: auto; }

h1, h2, h3, h4 { margin: 0; font-family: var(--font-display); }
p { margin: 0; }

::selection { background: #9be9f4; }

/* Foco visible y consistente — el original no tenía ninguno. */
:where(a, button, input, [tabindex]):focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Salta al contenido: aparece solo al tabular. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 100;
  padding: 12px 18px;
  background: var(--navy);
  color: #fff;
  border-radius: 10px;
  font-size: var(--fs-texto);
}
.skip-link:focus {
  left: 8px;
  color: #fff;
}

/* --------------------------------------------------------------------------
   3. Utilidades de composición
   -------------------------------------------------------------------------- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
}

.section { padding: var(--section-y) var(--pad-x); }
.section--flush-top { padding-top: 0; }
.section--tight    { padding-bottom: calc(var(--section-y) * .4); }

.stack        { display: flex; flex-direction: column; }
.stack-6      { gap: 6px; }
.stack-10     { gap: 10px; }
.stack-14     { gap: 14px; }
.stack-20     { gap: 20px; }
.stack-30     { gap: 30px; }

/* Encabezado de sección: título a la izquierda, enlace a la derecha.
   En celular el enlace baja debajo del título. */
.section-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
@media (min-width: 860px) {
  .section-head {
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
  }
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--teal);
}
.eyebrow--sm    { letter-spacing: .16em; }
.eyebrow--muted { color: var(--text-soft); }
.eyebrow--cyan  { color: var(--cyan-soft); }
.eyebrow--dim   { color: var(--on-navy-dim); }

/* Las tres eran tres tamaños distintos (38 / 30 / 27px) más tres pares de
   letter-spacing y line-height que no coincidían. Ahora son la misma medida.
   Se conservan los tres nombres para no reescribir el marcado de las cinco
   páginas: lo que las diferenciaba ya no existe, pero el HTML sigue válido. */
.title-lg,
.title-md,
.title-sm { font-size: var(--fs-subtitulo); letter-spacing: -.025em; line-height: 1.1; }

.lede {
  font-size: var(--fs-texto);
  line-height: 1.6;
  color: var(--text-muted);
  text-wrap: pretty;
}
.lede--wide { max-width: 720px; }

/* Mismo caso: eran 14px y 13.5px, medio píxel de diferencia. */
.body-sm,
.body-xs  { font-size: var(--fs-texto); line-height: 1.6; color: var(--text-soft); }

.link-mono {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--teal);
  white-space: nowrap;
}
.link-inline { font-size: var(--fs-texto); color: var(--teal); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   4. Rejillas
   -------------------------------------------------------------------------- */
.grid { display: grid; gap: 14px; }

.grid--2 { grid-template-columns: 1fr; }
.grid--3 { grid-template-columns: 1fr; }
.grid--4 { grid-template-columns: 1fr; }

@media (min-width: 600px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  .grid--3, .grid--4 { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1100px) {
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* Rejilla de "azulejos".

   Las divisorias NO se dibujan con un hueco de 1px entre celdas, que es lo
   habitual. Con anchos fraccionarios —a 1200px las columnas miden 276.75px—
   ese hueco cae en un subpíxel y el navegador se lo come: se perdía justo una
   divisoria de cada cuatro.

   En su lugar cada azulejo pinta su propia línea superior e izquierda con una
   sombra interior, que siempre se dibuja porque vive dentro de la caja del
   elemento. Eso resuelve las divisorias internas y, de paso, los bordes
   superior e izquierdo de la rejilla.

   Los bordes derecho e inferior van como `border` de verdad, no como sombra
   interior: una sombra interior del contenedor se pinta por debajo del fondo
   de los hijos y quedaría tapada. El borde no, porque `overflow:hidden`
   recorta a los hijos dentro del área de relleno. Así ningún lado se duplica. */
.tile-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  background: var(--surface);
  border-right: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  border-radius: var(--radius);
  overflow: hidden;
}
@media (min-width: 560px) { .tile-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 880px) { .tile-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1100px) {
  .tile-grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* Novedades tiene 4 tarjetas: se salta el escalón de 3 columnas, que dejaría
   dos celdas vacías mostrando el color de la separación. Va 1 → 2 → 4. */
.tile-grid--novedades { grid-template-columns: 1fr; }
@media (min-width: 560px)  { .tile-grid--novedades { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .tile-grid--novedades { grid-template-columns: repeat(4, 1fr); } }

.tile {
  background: var(--surface);
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  box-shadow: inset 1px 1px 0 0 var(--hairline);
  transition: background .3s ease, transform .45s var(--ease);
}
.tile__name { font-family: var(--font-display); font-size: var(--fs-subtitulo); }
.tile__meta { font-size: var(--fs-micro); color: var(--text-soft); }

/* --------------------------------------------------------------------------
   4b. Carrusel horizontal
   --------------------------------------------------------------------------
   Sustituye a la retícula en Especialidades. El motivo no es solo estético:
   son 11 tarjetas en una retícula de 4 columnas, así que sobraba una celda
   que había que tapar con un azulejo falso. Un riel no tiene esa aritmética.

   El mecanismo es scroll nativo con imantado; no hay librería ni un solo
   `setInterval`. El JS solo dibuja la barra de avance y apaga las flechas
   en los extremos: si fallara, el carrusel sigue funcionando con el dedo,
   el trackpad y el teclado.
   -------------------------------------------------------------------------- */
.carrusel { position: relative; }

/* Retícula y no flex, porque el riel lleva dos hileras en pantallas anchas.
   `grid-auto-flow: column` hace que las tarjetas llenen hacia abajo y luego
   avancen de columna, que es el orden de lectura correcto: la segunda queda
   debajo de la primera y no a su derecha.

   En celular se queda en una sola hilera. Dos hileras en 375px darían
   tarjetas de unos 150px de ancho, donde no cabe "Ginecología y obstetricia"
   ni partiéndola. */
/* El comportamiento de riel lo comparten dos casos: el carrusel de
   especialidades, que lo es siempre, y las retículas de sedes y novedades,
   que solo lo son en celular —ahí apilaban 2.7 y 1.0 pantallas de scroll—
   y de 768px en adelante vuelven a ser retículas normales. */
.carrusel__pista,
.riel-movil {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* Aire arriba y abajo para que la tarjeta ampliada no se recorte contra
     los bordes del contenedor de scroll. */
  padding-block: 6px;
  /* La barra de scroll del sistema se oculta: su trabajo lo hace la barra de
     avance, que es más discreta y no cambia de grosor entre navegadores. */
  scrollbar-width: none;
  /* Los extremos se difuminan, pero solo del lado donde queda recorrido.
     El ancho de cada lado lo escribe el JS en estas dos variables, así que
     al llegar al final el borde derecho vuelve a ser nítido. */
  mask-image: linear-gradient(90deg,
    transparent 0,
    #000 var(--fade-izq, 0px),
    #000 calc(100% - var(--fade-der, 0px)),
    transparent 100%);
  -webkit-mask-image: linear-gradient(90deg,
    transparent 0,
    #000 var(--fade-izq, 0px),
    #000 calc(100% - var(--fade-der, 0px)),
    transparent 100%);
}
.carrusel__pista::-webkit-scrollbar,
.riel-movil::-webkit-scrollbar { display: none; }
.carrusel__pista > *,
.riel-movil > * { scroll-snap-align: start; }

/* La distribución propia del carrusel de especialidades. */
.carrusel__pista {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: auto;
  grid-auto-columns: min(252px, 74vw);
  gap: 10px;
}

/* Sedes y novedades: retícula que en celular se recorre de lado.
   Una tarjeta por vista al 82% del ancho, con la siguiente asomando. */
@media (max-width: 767px) {
  .riel-movil {
    grid-auto-flow: column;
    grid-template-columns: none;
    grid-auto-columns: 82vw;
    gap: 12px;
  }
  /* Novedades es una retícula cosida con medianiles; suelta, cada azulejo
     necesita su propio borde. */
  .tile-grid--novedades.riel-movil { background: none; border: 0; border-radius: 0; }
  .tile-grid--novedades.riel-movil > .tile {
    box-shadow: none;
    border: 1px solid var(--hairline);
    border-radius: var(--radius);
  }
}
/* De tableta en adelante deja de ser riel y recupera su retícula. */
@media (min-width: 768px) {
  .riel-movil {
    overflow: visible;
    scroll-snap-type: none;
    padding-block: 0;
    mask-image: none;
    -webkit-mask-image: none;
  }
}

/* El anillo de foco va en el contenedor y no en la pista: la pista lleva una
   máscara que difumina sus bordes y se comería el anillo justo en los lados. */
.carrusel__pista:focus-visible,
.riel-movil:focus-visible { outline: none; }
.carrusel:has(.carrusel__pista:focus-visible),
.carrusel:has(.riel-movil:focus-visible) {
  outline: 3px solid var(--teal);
  outline-offset: 5px;
  border-radius: var(--radius);
}

@media (min-width: 768px) {
  .carrusel__pista {
    grid-template-rows: repeat(2, auto);
    grid-auto-columns: 252px;
  }
}

/* Las tarjetas dentro del riel dejan de ser celdas de una retícula y pasan a
   ser piezas sueltas: se cambia la costura interior por un borde propio.
   El ancho lo pone `grid-auto-columns`, no la tarjeta. */
.carrusel__pista > .tile {
  scroll-snap-align: start;
  box-shadow: none;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 13px 16px 14px;
  min-height: 74px;
  gap: 2px;
  justify-content: center;
}

/* El nombre baja de --fs-subtitulo (27px) a --fs-texto (16px). No es un tamaño
   nuevo: es uno de los cuatro que ya existen, así que la escala sigue intacta.
   A 27px no cabía un nombre largo en una tarjeta de este ancho sin partirse en
   tres líneas, y era la causa real del aire desperdiciado.
   Solo aplica dentro del riel: los azulejos de Novedades siguen a 27px. */
.carrusel__pista .tile__name {
  font-size: var(--fs-texto);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.015em;
}
.carrusel__pista .tile__meta { line-height: 1.45; }

/* En la retícula el azulejo se levanta 3px al pasar el cursor. Aquí no: estas
   tarjetas son informativas, no llevan a ningún lado, y el gesto de elevación
   promete un clic que no existe. Además pelearía con la escala del scroll,
   que también escribe en `transform`. Queda solo el cambio de fondo. */
@media (hover: hover) {
  .carrusel__pista > .tile:hover {
    background: var(--surface-hi);
    transform: none;
  }
}

/* Profundidad ligada al scroll. `animation-timeline: view()` ata el avance de
   la animación a la posición de cada tarjeta dentro del riel, sin JavaScript
   y sin escuchar el evento de scroll: lo resuelve el compositor, así que sigue
   al dedo sin perder fotogramas.

   Los porcentajes no son arbitrarios. El recorrido de `view()` va de "la
   tarjeta asoma por la derecha" (0%) a "termina de salir por la izquierda"
   (100%), y su duración total es el ancho del riel más el de la tarjeta. Con
   tarjetas de 252px: pegada al inicio el cálculo da ~83% en escritorio y ~57%
   en celular; pegada al final, ~17% y ~43%. La meseta de 12% a 88% cubre esos
   cuatro casos, de modo que en reposo las tarjetas visibles se ven completas y
   solo se encogen las que asoman cortadas por el borde. Si algún día cambia el
   ancho de tarjeta, hay que rehacer esta cuenta.

   Donde el navegador no lo soporte, el @supports deja el carrusel liso: mismo
   riel, mismo imantado, sin profundidad. No se rompe nada. */
@keyframes cav-carrusel-profundidad {
  0%        { opacity: .3; transform: scale(.88); }
  12%, 88%  { opacity: 1;  transform: scale(1); }
  100%      { opacity: .3; transform: scale(.88); }
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .carrusel__pista > .tile {
      animation: cav-carrusel-profundidad linear both;
      animation-timeline: view(inline);
    }
  }
}

/* Barra de avance. Se prefiere a los puntos porque son 11 tarjetas: once
   puntos son ruido y no se pueden apuntar con el dedo. */
.carrusel__progreso {
  margin-top: 18px;
  height: 3px;
  border-radius: 999px;
  background: var(--hairline);
  overflow: hidden;
}
.carrusel__barra {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--teal);
  /* Arranca ocupando todo el ancho y se recorta con scaleX, que es una
     transformación y no provoca recálculo de maquetación en cada fotograma. */
  transform-origin: left center;
  transform: scaleX(0);
}

/* Si todo cabe sin desplazamiento —una pantalla muy ancha, o menos tarjetas—
   los controles no tienen nada que controlar y estorban. */
.carrusel-sin-recorrido .carrusel__progreso,
.carrusel__flechas.carrusel-sin-recorrido { display: none; }

.section-head__extra {
  display: flex;
  align-items: center;
  gap: 18px;
}
.carrusel__flechas { display: flex; gap: 8px; }
.carrusel__flecha {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid var(--border-firm);
  border-radius: 999px;
  background: var(--surface);
  color: var(--navy);
  cursor: pointer;
  transition: background .25s ease, border-color .25s ease, opacity .25s ease;
}
.carrusel__flecha:disabled { opacity: .3; cursor: default; }
@media (hover: hover) {
  .carrusel__flecha:not(:disabled):hover {
    background: var(--surface-hi);
    border-color: var(--cyan);
  }
}
/* En táctil el gesto de deslizar es el idioma nativo y las flechas solo
   ocupan espacio. */
@media (hover: none) { .carrusel__flechas { display: none; } }

/* --------------------------------------------------------------------------
   5. Tarjetas
   -------------------------------------------------------------------------- */
.card {
  padding: 26px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: 9px;
  transition: transform .45s var(--ease), box-shadow .45s ease, border-color .35s ease;
}
.card--pad-lg { padding: 32px; gap: 16px; }
.card--grad   { background: linear-gradient(180deg, #fff, #F6FAFC); gap: 10px; }

/* --------------------------------------------------------------------------
   Foto de fondo al pasar el cursor
   --------------------------------------------------------------------------
   La foto vive en un pseudo-elemento, no en el `background` de la tarjeta.
   Así puede llevar encima su propio velo sin teñir también el texto, igual
   que el vídeo del hero lleva su `.hero__scrim`.

   Toda la regla va dentro de `@media (hover: hover)`: en un celular no hay
   cursor, la regla nunca aplica y **el navegador ni siquiera descarga la
   imagen**. Es deliberado — 144 KB no se gastan en una conexión de datos
   móviles por un efecto que ahí no existe.

   Se declara desde el inicio con opacidad cero en vez de asignar la imagen
   dentro del `:hover`. Si se pusiera en el `:hover`, la descarga empezaría
   en el momento de pasar el cursor y la foto entraría tarde y a tirones.
   -------------------------------------------------------------------------- */
.card--foto { position: relative; overflow: hidden; isolation: isolate; }

/* Qué foto le toca a cada tarjeta. La regla del efecto es una sola y lee
   `--foto`; agregar una tercera tarjeta es agregar aquí un renglón, no
   duplicar el bloque completo. Las rutas son relativas a esta hoja. */
.card--foto-cardio { --foto: url("../img/auscultacion.jpg"); }
.card--foto-hombre { --foto: url("../img/chequeo-hombre.jpg"); }

@media (hover: hover) {
  /* Una sola capa: la fotografía. Antes eran dos —la foto y encima un velo
     blanco al 96%— y el resultado era un crema lavado que borraba la imagen
     y se leía como una lámina blanca añadida sobre la tarjeta.

     Ahora la foto se disuelve sobre sí misma con una máscara: se desvanece
     hacia la izquierda, que es donde va el texto, y deja ver el blanco de la
     propia tarjeta. El contraste del texto sale del fondo de la tarjeta, no
     de una capa encima, así que no hay nada que "se agregue" después: la foto
     entra difuminándose y ahí termina el movimiento. */
  .card--foto::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    opacity: 0;
    transition: opacity .45s var(--ease);
    pointer-events: none;
    background: var(--foto) center / cover no-repeat;
  }
  /* Pareja en toda la tarjeta, sin máscara ni velo. El 32% sale de medir el
     percentil 5 de luminancia de ambas fotos —las zonas realmente oscuras—
     y comprobar que el texto navy encima se sostiene arriba de 4.5:1: da
     8.4:1 sobre la auscultación y 6.9:1 sobre la del baumanómetro. */
  .card--foto:hover::before,
  .card--foto:focus-within::before { opacity: .32; }

  /* Con foto detrás, el texto se oscurece a navy.

     No es capricho: el gris --text-soft de la descripción cae a 3.2:1 sobre
     la foto, y el teal de la volanta y del enlace está en 4.47:1 incluso
     sobre blanco puro, así que con cualquier imagen detrás reprueba. Bajar
     más la opacidad de la foto no los salva; oscurecer el texto sí. */
  .card--foto .eyebrow,
  .card--foto .body-sm,
  .card--foto .link-inline { transition: color .45s var(--ease); }

  .card--foto:hover .eyebrow,
  .card--foto:hover .body-sm,
  .card--foto:hover .link-inline,
  .card--foto:focus-within .eyebrow,
  .card--foto:focus-within .body-sm,
  .card--foto:focus-within .link-inline { color: var(--text); }

  /* El enlace pierde el teal que lo distinguía como enlace, así que se
     subraya para que siga leyéndose como tal. */
  .card--foto:hover .link-inline,
  .card--foto:focus-within .link-inline { text-decoration: underline; }

  .card--foto:hover { border-color: var(--cyan); }
}

/* En pantalla táctil no hay cursor, así que no hay nada sobre qué "pasar por
   encima". En vez de dejar estas dos tarjetas sin foto —que era lo que pasaba
   antes, porque toda la regla vivía dentro de (hover: hover)— la imagen se
   queda puesta.

   Se usa (hover: none) y no un ancho: lo que decide no es el tamaño de la
   pantalla sino si hay puntero. Una ventana de escritorio angosta sigue
   teniendo ratón y conserva el efecto al pasar el cursor.

   El texto va en navy de forma permanente por la misma razón que en el hover:
   el gris de la descripción y el teal del enlace no aguantan el contraste con
   una imagen detrás. */
@media (hover: none) {
  .card--foto::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    opacity: .32;
    pointer-events: none;
    background: var(--foto) center / cover no-repeat;
  }
  .card--foto .eyebrow,
  .card--foto .body-sm,
  .card--foto .link-inline { color: var(--text); }
  .card--foto .link-inline { text-decoration: underline; }
}

/* Con movimiento reducido se elimina la aparición al pasar el cursor, que es
   el cambio que la preferencia pide evitar. La versión táctil no se toca: ahí
   la foto está fija y una imagen quieta no es movimiento. */
@media (prefers-reduced-motion: reduce) and (hover: hover) {
  .card--foto::before { display: none; }
}
.card__title  { font-family: var(--font-display); font-size: var(--fs-subtitulo); line-height: 1.2; }

@media (min-width: 768px) { .card--pad-lg { padding: 36px; } }

/* --------------------------------------------------------------------------
   6. Los seis comportamientos de hover
   El archivo original repetía estos mismos efectos en 63 clases (.hv1 … .hv63).
   Aquí son seis, y solo se activan en dispositivos con puntero real.
   -------------------------------------------------------------------------- */
@media (hover: hover) {
  .u-lift:hover {
    transform: translateY(-5px);
    box-shadow: var(--lift-shadow);
    border-color: var(--cyan);
  }
  .tile:hover {
    background: var(--surface-hi);
    transform: translateY(-3px);
  }
  .nav__link:hover {
    background: rgba(14, 42, 78, .06);
  }
  .btn--search:hover {
    background: rgba(52, 206, 226, .26);
  }
  .btn--primary:hover {
    transform: translateY(-2px);
    background: var(--teal);
    box-shadow: 0 16px 30px -16px rgba(10, 126, 146, .8);
  }
  .sede-card:hover {
    background-color: rgba(255, 255, 255, .11);
    transform: translateY(-5px);
    border-color: rgba(127, 216, 230, .6);
  }
  .wa-float:hover { opacity: 1; background: var(--whatsapp-dk); }
}

/* --------------------------------------------------------------------------
   7. Botones y chips
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 22px;
  border: 1px solid transparent;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: var(--fs-texto);
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
  transition: transform .3s ease, background .3s ease, box-shadow .3s ease, border-color .3s ease;
}
.btn--primary { background: var(--navy); color: #fff; font-weight: 500; }
.btn--primary:hover { color: #fff; }
.btn--ghost   { background: var(--surface); color: var(--navy); border-color: #cfd9e4; }
.btn--white   { background: #fff; color: var(--navy); font-weight: 500; padding: 16px 26px; }
.btn--outline-light { background: transparent; color: #fff; border-color: rgba(255,255,255,.4); padding: 16px 26px; }
.btn--outline-light:hover { color: #fff; background: rgba(255,255,255,.08); }
.btn--search  {
  background: rgba(52, 206, 226, .14);
  border-color: rgba(10, 126, 146, .32);
  color: inherit;
  padding: 9px 14px 9px 12px;
  white-space: nowrap;
}
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: 10px; }
.btn-row--mt-auto { margin-top: auto; }

/* En celular los botones ocupan el ancho completo: son el objetivo táctil. */
@media (max-width: 559px) {
  .btn-row .btn { width: 100%; }
}

.chip {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-texto);
  padding: 9px 14px;
  border-radius: 999px;
  border: 1px solid var(--border-firm);
  background: #F7FAFC;
  transition: transform .45s var(--ease), box-shadow .45s ease, border-color .35s ease;
}
.chip--light {
  border-color: rgba(255, 255, 255, .3);
  background: transparent;
  color: #fff;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  padding: 8px 13px;
}
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }

/* --------------------------------------------------------------------------
   8. Encabezado del sitio
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 14px var(--pad-x);
  background: rgba(251, 252, 253, .78);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  border-bottom: 1px solid rgba(14, 42, 78, .08);
  color: #3d5875;
  transition: padding .28s ease, background .28s ease, box-shadow .28s ease,
              color .28s ease, border-color .28s ease;
}
@media (min-width: 1100px) { .site-header { padding: 20px var(--pad-x); } }

/* Estado "encogido" tras hacer scroll — lo aplica app.js */
.site-header.is-scrolled {
  padding-block: 9px;
  background: rgba(251, 252, 253, .92);
  box-shadow: 0 10px 30px -26px rgba(14, 42, 78, .5);
}
/* Cristal sobre el vídeo del hero. Aquí el encabezado casi no lleva tinte
   propio: el desenfoque hace el trabajo, así que el vídeo se lee a través
   de la banda en vez de quedar lavado detrás de una capa blanca.

   Solo mientras está arriba. En cuanto encoge —`is-scrolled`— recupera el
   fondo sólido, porque de ahí en adelante lo que pasa por debajo es texto
   y no se puede leer el menú encima de él.

   El modificador va solo en index.html a propósito: las tres sedes y el
   aviso de privacidad usan el mismo encabezado sobre fondo blanco, donde
   un cristal a este nivel de transparencia dejaría el menú ilegible. */
.site-header--sobre-hero:not(.is-scrolled) {
  background: rgba(255, 255, 255, .26);
  backdrop-filter: blur(24px) saturate(1.7);
  -webkit-backdrop-filter: blur(24px) saturate(1.7);
  border-bottom-color: rgba(255, 255, 255, .38);
}

/* Sobre una sección oscura el encabezado se invierte — lo aplica app.js */
.site-header.is-over-dark {
  background: rgba(9, 28, 52, .72);
  color: #e2edf6;
  border-bottom-color: rgba(255, 255, 255, .12);
}
.site-header.is-over-dark .brand__tag { color: #a9c0d6; }
.site-header.is-over-dark .nav__link:hover { background: rgba(255, 255, 255, .12); }

.brand { display: flex; align-items: center; gap: 12px; color: inherit; }
.brand:hover { color: inherit; }
.brand__mark {
  width: 40px;
  height: 30px;
  flex: none;
  object-fit: contain;
  transition: width .28s ease, height .28s ease;
}
.site-header.is-scrolled .brand__mark { width: 34px; height: 25px; }
@media (min-width: 768px) {
  .brand__mark { width: 46px; height: 34px; }
  .site-header.is-scrolled .brand__mark { width: 36px; height: 27px; }
}
.brand__text { display: flex; flex-direction: column; gap: 2px; }
.brand__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-texto);
  letter-spacing: -.01em;
  white-space: nowrap;
}
.brand__tag {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--text-soft);
  white-space: nowrap;
  overflow: hidden;
  max-height: 20px;
  transition: opacity .25s ease, max-height .25s ease;
}
.site-header.is-scrolled .brand__tag { opacity: 0; max-height: 0; }

/* Navegación — cajón deslizante en celular, fila en escritorio */
.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid rgba(14, 42, 78, .14);
  border-radius: 12px;
  background: rgba(255, 255, 255, .6);
  color: inherit;
  cursor: pointer;
}
.nav-toggle__bars { display: block; width: 18px; height: 12px; position: relative; }
.nav-toggle__bars::before,
.nav-toggle__bars::after,
.nav-toggle__bars span {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform .3s var(--ease), opacity .2s ease;
}
.nav-toggle__bars::before { top: 0; }
.nav-toggle__bars span    { top: 5px; }
.nav-toggle__bars::after  { top: 10px; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: translateY(5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars span    { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after  { transform: translateY(-5px) rotate(-45deg); }

/* El cajón se desliza fuera de pantalla. Si fuera `position:fixed` a secas,
   ese "fuera de pantalla" ensancharía el documento 340px y toda la página
   scrollearía en horizontal — y `overflow-x:hidden` en <body> no lo evita,
   porque no recorta elementos fijos. La cáscara sí lo recorta: es fija, ocupa
   exactamente el viewport y lleva overflow:hidden. */
.nav-shell {
  position: fixed;
  inset: 0;
  z-index: 45;
  overflow: hidden;
  pointer-events: none;
}

.nav {
  position: absolute;
  inset: 0 0 0 auto;
  width: min(86vw, 340px);
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
  padding: 88px 22px 32px;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -30px 0 60px -40px rgba(14, 42, 78, .6);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform .32s var(--ease), visibility .32s;
  overflow-y: auto;
}
.nav.is-open { transform: translateX(0); visibility: visible; }

.nav__backdrop {
  position: fixed;
  inset: 0;
  z-index: 44;
  background: rgba(9, 28, 52, .42);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .32s ease, visibility .32s;
}
.nav__backdrop.is-open { opacity: 1; visibility: visible; }

.nav__link {
  font-size: var(--fs-texto);
  color: var(--text);
  padding: 13px 14px;
  border-radius: 12px;
  white-space: nowrap;
}

/* El menú pasa a fila horizontal a partir de 1120px y no de 1000px como
   antes. El motivo es la tipografía: los enlaces subieron de 13.5px a
   --fs-texto (16px) y los cinco, más el botón de búsqueda y la marca, ya no
   caben en 1000px de ancho —se pasaban unos 75px y se desbordaban—. Entre
   1000 y 1119px se queda el botón de hamburguesa, que ahí sí cabe siempre. */
@media (min-width: 1120px) {
  .nav-toggle, .nav__backdrop { display: none; }
  /* display:contents disuelve la cáscara: .nav vuelve a ser hijo directo
     del encabezado y se acomoda en la fila. */
  .nav-shell { display: contents; }
  .nav {
    position: static;
    width: auto;
    flex-direction: row;
    align-items: center;
    gap: 2px;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
    transform: none;
    visibility: visible;
    overflow: visible;
  }
  .nav__link {
    font-size: var(--fs-texto);
    color: inherit;
    padding: 9px 10px;
    border-radius: 999px;
  }
  .nav .btn--search { margin-left: 8px; }
}

/* --------------------------------------------------------------------------
   9. Hero
   -------------------------------------------------------------------------- */
/* El hero llena la primera pantalla completa, de borde a borde: empieza en el
   tope del viewport y el vídeo corre por detrás del encabezado, que queda
   flotando encima como una banda de cristal esmerilado.

   El encabezado es sticky, así que va en el flujo y se lleva su propia altura.
   El `margin-top` negativo devuelve exactamente esa altura para que el hero
   suba a ocupar el hueco; sin él, el hero arrancaría por debajo de la barra.
   No se pasa el encabezado a `position: fixed` a propósito: lo comparten las
   tres páginas de sede y el aviso de privacidad, que no tienen vídeo y sí
   dependen de que ocupe espacio real.

   El `padding-top` compensa lo que el margen se llevó. Sin esa compensación
   el texto quedaría centrado contra la pantalla entera y se metería debajo
   del menú; con ella se centra en el espacio libre, igual que antes.

   La medida real la escribe app.js en --alto-encabezado. El valor de reserva
   cubre el instante antes de que el JS corra, y el caso de que no corra.

   svh y no vh: en celular, `vh` mide contando la barra de direcciones oculta,
   así que el hero quedaría más alto que la pantalla y empujaría el contenido.
   `min-height` y no `height`: si el texto crece —traducción, tipografía grande
   del sistema— la sección se estira en vez de recortarlo. */
.hero {
  position: relative;
  display: flex;
  align-items: center;
  /* En celular no llena la pantalla completa: se queda en 82svh para que
     asome el borde de la sección siguiente. Ese asomo es lo que le dice al
     visitante que hay más abajo, y de paso devuelve casi un quinto de
     pantalla. En escritorio sí ocupa el alto completo. */
  min-height: 82svh;
  margin-top: calc(-1 * var(--alto-encabezado, 76px));
  padding: 44px var(--pad-x);
  padding-top: calc(44px + var(--alto-encabezado, 76px));
  overflow: hidden;
}
@media (min-width: 768px) {
  .hero {
    min-height: 100svh;
    margin-top: calc(-1 * var(--alto-encabezado, 88px));
    padding-block: 64px;
    padding-top: calc(64px + var(--alto-encabezado, 88px));
  }
}
@media (min-width: 1100px) {
  .hero {
    margin-top: calc(-1 * var(--alto-encabezado, 98px));
    padding-top: calc(64px + var(--alto-encabezado, 98px));
  }
}

.hero__bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: linear-gradient(180deg, #dff0f8 0%, #eaf5fa 38%, #bfe3ef 52%, #8fcede 78%, #6cbdd2 100%);
}

/* El vídeo es una capa opcional encima del degradado. Si no carga —celular,
   datos limitados, movimiento reducido— el degradado animado queda como fondo. */
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .9s ease;
}
.hero__video.is-ready { opacity: 1; }

/* El resplandor es la escenografía del degradado de reserva. Sobre el vídeo
   estorba, así que cuando el vídeo entra se retira con el mismo tiempo que
   tarda en aparecer. El velo sí se queda: es lo que mantiene legible el
   texto encima. */
.hero__video.is-ready ~ .hero__glow {
  opacity: 0;
  transition: opacity .9s ease;
}

.hero__glow {
  position: absolute;
  inset: -6%;
  background: radial-gradient(60% 40% at 72% 14%, rgba(255,255,255,.85), rgba(255,255,255,0) 70%);
  animation: cav-float 18s ease-in-out infinite;
}
/* Velo legible sobre el fondo. En celular es casi opaco para que el texto
   siempre tenga contraste; en escritorio se abre hacia la derecha. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(249,251,253,.94) 0%, rgba(249,251,253,.86) 55%, rgba(249,251,253,.62) 100%);
}
@media (min-width: 860px) {
  .hero__scrim {
    background: linear-gradient(90deg, rgba(249,251,253,.94) 0%, rgba(249,251,253,.80) 34%, rgba(249,251,253,.34) 62%, rgba(249,251,253,.10) 100%);
  }
}
.hero__sweep {
  position: absolute;
  inset: 0;
  width: 220px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.45), transparent);
  animation: cav-sweep 9s linear infinite;
}

.hero__content {
  position: relative;
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.hero__title {
  font-size: var(--fs-titulo);
  line-height: 1.0;
  letter-spacing: -.035em;
  text-wrap: pretty;
}
.hero__title em { font-style: normal; color: var(--teal); }
.hero__lede {
  max-width: 470px;
  font-size: var(--fs-texto);
  line-height: 1.6;
  color: var(--text-body);
  text-wrap: pretty;
}

/* --------------------------------------------------------------------------
   10. Sección oscura de sedes
   -------------------------------------------------------------------------- */
.section--navy { background: var(--navy); color: var(--on-navy); }

/* Vídeo de fondo de una sección oscura.

   El navy sólido de `.section--navy` se queda y hace de reserva: es lo que se
   ve en celular, donde el vídeo nunca se descarga, y si la reproducción falla.
   El vídeo va encima, y sobre el vídeo el mismo navy pero translúcido.

   El velo aparece solo cuando el vídeo está listo. Si estuviera siempre, sobre
   el fondo sólido se sumarían dos capas y la sección se vería más oscura de la
   cuenta.

   `overflow: hidden` recorta el vídeo a la banda, y `isolation` evita que las
   capas se cuelen por encima de las tarjetas. */
.section--navy { position: relative; overflow: hidden; isolation: isolate; }
.seccion__video,
.seccion__velo { position: absolute; inset: 0; z-index: -1; }

.seccion__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .9s ease;
}
.seccion__video.is-ready { opacity: 1; }

.seccion__velo {
  opacity: 0;
  transition: opacity .9s ease;
  /* Carga alta a propósito: encima van texto blanco, teléfonos en gris claro
     y tarjetas de borde tenue, y no se sabe qué fotograma queda debajo. */
  background: linear-gradient(150deg, rgba(14, 42, 78, .93) 0%, rgba(14, 42, 78, .86) 55%, rgba(10, 126, 146, .80) 100%);
}
.seccion__video.is-ready ~ .seccion__velo { opacity: 1; }
.section--navy a { color: var(--on-navy); }
.section--navy .lede { color: var(--on-navy-soft); }
.section--navy .body-xs { color: var(--on-navy-soft); }

.sede-card {
  overflow: hidden;
  padding: 24px;
  border-radius: var(--radius);
  background-color: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .12);
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: background .35s ease, transform .45s var(--ease), border-color .35s ease;
}
.sede-card--primary { border-color: rgba(127, 216, 230, .32); }
.sede-card--soon {
  background: rgba(255, 255, 255, .03);
  border-style: dashed;
  border-color: rgba(255, 255, 255, .22);
}
.sede-card__name { font-family: var(--font-display); font-size: var(--fs-subtitulo); }
.sede-card__name--soon { color: #c3d3e2; }
.sede-card__phones {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: #e6eef6;
}
/* Los números son enlaces `tel:`. Heredan el color claro de la tarjeta:
   sin esto tomarían el azul marino del enlace por defecto, que sobre el
   fondo oscuro de la tarjeta es ilegible. */
.sede-card__phones a { color: inherit; }
@media (hover: hover) { .sede-card__phones a:hover { color: #fff; text-decoration: underline; } }
.sede-card__actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 4px;
}
.pill {
  font-size: var(--fs-texto);
  padding: 8px 12px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, .25);
  color: #fff;
}
.pill--solid { background: var(--cyan-soft); color: var(--navy); border-color: transparent; }
.pill--solid:hover { color: var(--navy); }
.pill--bare { border-color: transparent; color: var(--cyan-soft); padding-inline: 4px; }
.pill--bare:hover { color: var(--cyan-soft); text-decoration: underline; }

/* --------------------------------------------------------------------------
   11. Bloque de llamada a la acción (a domicilio)
   -------------------------------------------------------------------------- */
.cta {
  position: relative;
  overflow: hidden;
  padding: 32px 24px;
  border-radius: 20px;
  background: linear-gradient(120deg, var(--navy) 0%, var(--teal) 100%);
  color: #fff;
  display: flex;
  flex-direction: column;
  gap: 28px;
}
@media (min-width: 768px)  { .cta { padding: 44px; } }
@media (min-width: 1000px) {
  .cta { flex-direction: row; align-items: center; justify-content: space-between; gap: 40px; }
}
/* Vídeo de fondo del bloque de cierre.

   El degradado navy→teal de `.cta` se queda como está y hace de reserva: es
   lo que se ve en celular, donde el vídeo nunca se descarga, y si falla la
   reproducción. El vídeo va encima y sobre él el mismo degradado con alfa.

   El velo aparece solo cuando el vídeo está listo. Si estuviera siempre,
   sobre el degradado sólido se sumarían dos capas de azul y el bloque se
   vería más oscuro de la cuenta. */
.cta__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .9s ease;
}
.cta__video.is-ready { opacity: 1; }

.cta__velo {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .9s ease;
  /* 88% y 82%: medido contra el vídeo, cuya zona más clara llega a 172/255.
     Con esa carga se cuela menos del 12%, así que el texto blanco y los chips
     de borde tenue se sostienen en cualquier fotograma. */
  background: linear-gradient(120deg, rgba(14, 42, 78, .88) 0%, rgba(10, 126, 146, .82) 100%);
}
.cta__video.is-ready ~ .cta__velo { opacity: 1; }

.cta__sweep {
  position: absolute;
  top: 0; bottom: 0;
  width: 120px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.14), transparent);
  animation: cav-sweep 7s linear infinite;
}
.cta__body { position: relative; display: flex; flex-direction: column; gap: 14px; max-width: 620px; }
.cta__title { font-size: var(--fs-subtitulo); letter-spacing: -.028em; line-height: 1.08; }
.cta__text  { font-size: var(--fs-texto); line-height: 1.6; color: #d6e6ee; }
.cta__actions {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 250px;
}
.cta .eyebrow { color: #9fdfeb; }

/* --------------------------------------------------------------------------
   12. Tarjetas de equipo médico
   -------------------------------------------------------------------------- */
.doc-card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  transition: transform .45s var(--ease), box-shadow .45s ease, border-color .35s ease;
}
.doc-card__photo {
  height: 170px;
  width: 100%;
  object-fit: cover;
  display: block;
  background: #eef3f8;
}
/* Marcador mientras no haya retratos reales. Se sustituye por <img>. */
.doc-card__photo--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(135deg, #eef3f8 0 10px, #e4ebf3 10px 20px);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.doc-card__body { padding: 18px; display: flex; flex-direction: column; gap: 5px; }
.doc-card__name { font-size: var(--fs-texto); font-weight: 500; }

/* --------------------------------------------------------------------------
   13. Bloque de teléfonos
   -------------------------------------------------------------------------- */
.phone-card {
  padding: 16px 20px;
  border-radius: 14px;
  background: var(--surface);
  border: 1px solid var(--border-firm);
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 170px;
  flex: 1 1 170px;
  transition: transform .45s var(--ease), box-shadow .45s ease, border-color .35s ease;
}
.phone-card__num { font-size: var(--fs-texto); font-weight: 500; }

.split {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 28px 24px;
  border-radius: var(--radius-lg);
  background: var(--surface-alt);
  border: 1px solid var(--hairline);
  transition: transform .45s var(--ease), box-shadow .45s ease, border-color .35s ease;
}
@media (min-width: 768px)  { .split { padding: 34px 36px; } }
@media (min-width: 1000px) {
  .split { flex-direction: row; align-items: center; justify-content: space-between; gap: 32px; }
}
.split__body { display: flex; flex-direction: column; gap: 10px; max-width: 520px; }
.split__aside { display: flex; gap: 10px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   14. Buscador de estudios
   -------------------------------------------------------------------------- */
.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: none;
  align-items: flex-start;
  justify-content: center;
  padding: 80px 16px 16px;
  background: rgba(9, 28, 52, .42);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.search-overlay.is-open { display: flex; }
@media (min-width: 768px) { .search-overlay { padding: 110px 24px 24px; } }

.search-overlay__dismiss { position: absolute; inset: 0; }

.search-panel {
  position: relative;
  width: 100%;
  max-width: 640px;
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, .97);
  border: 1px solid rgba(255, 255, 255, .9);
  box-shadow: 0 40px 90px -40px rgba(9, 28, 52, .7);
  overflow: hidden;
}
.search-panel__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid #eaf0f6;
}
.search-panel__input {
  border: 0;
  outline: none;
  width: 100%;
  min-width: 0;
  font-family: var(--font-body);
  /* --fs-texto son 16px exactos, que es el mínimo que evita que iOS haga
     zoom al enfocar el campo. Si algún día se baja ese token, este input
     necesita volver a un valor propio de 16px. */
  font-size: var(--fs-texto);
  color: var(--text);
  background: transparent;
}
.search-panel__esc {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-soft);
  background: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 9px;
  cursor: pointer;
  flex: none;
}
.search-panel__list {
  display: flex;
  flex-direction: column;
  max-height: min(52vh, 420px);
  overflow: auto;
  overscroll-behavior: contain;
}
.search-panel__foot {
  padding: 13px 20px;
  background: #F7FAFC;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.search-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 15px 20px;
  border-bottom: 1px solid #f2f6fa;
}
.search-item:hover { background: rgba(52, 206, 226, .09); }
.search-item__name { font-size: var(--fs-texto); font-weight: 500; }
.search-item__where {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.search-item__cta { font-size: var(--fs-micro); color: var(--teal); white-space: nowrap; }
@media (max-width: 480px) { .search-item__cta { display: none; } }
.search-empty { padding: 28px 20px; text-align: center; color: var(--text-soft); font-size: var(--fs-texto); }

/* --------------------------------------------------------------------------
   15. Botón flotante de WhatsApp
   -------------------------------------------------------------------------- */
.wa-float {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 60;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: var(--whatsapp);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: .94;
  box-shadow: 0 12px 26px -12px rgba(37, 211, 102, .6);
  transition: background .25s ease, opacity .25s ease;
}
@media (min-width: 768px) { .wa-float { right: 20px; bottom: 20px; } }

/* --------------------------------------------------------------------------
   15 bis. Delimitación de WhatsApp y aviso de privacidad simplificado

   No son adornos legales: son dos requisitos distintos.

   · La nota de WhatsApp separa dos regímenes jurídicos. La LGS incorporó en
     enero de 2026 el capítulo de Salud Digital, y su art. 71 Sexies mete la
     "orientación médica" dentro de la telesalud. Decir explícitamente que este
     canal es de información y agenda —no de consulta— es lo que mantiene al
     proyecto fuera de las cuatro condiciones del art. 71 Septies.

   · El aviso simplificado lo exige el art. 16-II de la LFPDPPP: en medios
     electrónicos hacen falta DOS avisos, el integral en su página y el
     simplificado en el punto de contacto, con enlace al primero.
   -------------------------------------------------------------------------- */
.nota-wa {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  max-width: 560px;
  margin-top: 4px;
  font-size: var(--fs-texto);
  line-height: 1.5;
  color: var(--text-muted);
}
.nota-wa svg { flex: none; margin-top: 2px; }
.nota-wa b { color: var(--text); font-weight: 600; }

/* Sobre fondo oscuro (bloque de servicios a domicilio) */
.nota-wa--sobre-oscuro { color: #cfe3ee; max-width: 620px; }
.nota-wa--sobre-oscuro b { color: #fff; }

/* Sin recuadro. Como tarjeta con borde y fondo propio competía con las
   columnas de arriba y pesaba más de lo que le toca a un texto legal.
   Ahora es una franja de lado a lado, separada solo por una línea fina,
   igual que la del pie legal de más abajo. */
.aviso-simple {
  margin: 22px 0 0;
  padding-top: 16px;
  border-top: 1px solid #eef2f7;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.aviso-simple__tit {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--teal);
}
/* A --fs-micro y no a --fs-texto: es letra chica a propósito, y a 16px el
   bloque dominaba el pie de página. El interlineado se queda en 1.6, que a
   este tamaño es lo que lo mantiene legible.

   El texto no se toca. Cubre los cuatro requisitos del aviso simplificado
   —responsable, finalidades, mecanismo de derechos ARCO y enlace al aviso
   integral— y recortarlo es una decisión legal, no de diseño. */
.aviso-simple p { font-size: var(--fs-micro); line-height: 1.6; color: var(--text-muted); }
.aviso-simple b { color: var(--text); font-weight: 600; }
.aviso-simple a { color: var(--teal); text-decoration: underline; }

/* --------------------------------------------------------------------------
   16. Pie de página
   -------------------------------------------------------------------------- */
.site-footer {
  padding: 34px var(--pad-x) 22px;
  background: var(--surface);
  border-top: 1px solid #e9eef4;
}
/* Sin `max-width`: el pie se alinea con el encabezado, que va de borde a borde
   con solo --pad-x de respiro. Con el tope de --wrap y centrado, en pantallas
   anchas el logo del pie quedaba muy por dentro del logo de arriba. */
.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}
@media (min-width: 640px)  { .footer-grid { grid-template-columns: repeat(2, 1fr); } }
/* Contacto se lleva el ancho grande para que las tres sedes quepan en fila.
   Apiladas, esa columna sola medía nueve renglones y estiraba todo el pie. */
@media (min-width: 1000px) { .footer-grid { grid-template-columns: 1.3fr 2fr .7fr; gap: 36px; } }

.footer-col { display: flex; flex-direction: column; gap: 12px; }
.footer-col__head {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.footer-link { font-size: var(--fs-texto); color: var(--text-body); }
/* Las tres sedes en fila, no apiladas. Con `flex-wrap` bajan solas a dos
   renglones cuando no caben, sin necesitar una media query propia. */
.footer-sedes { display: flex; flex-wrap: wrap; gap: 10px 30px; }
.footer-sede { display: flex; flex-direction: column; }
.footer-sede__nombre {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.footer-sede__nombre:hover { color: var(--teal); }
.footer-sede a[href^="tel:"] {
  display: block;
  font-size: var(--fs-texto);
  line-height: 1.35;
  color: var(--text-body);
}
/* WhatsApp y el aviso van uno junto a otro, no en renglones separados. */
.footer-enlaces { display: flex; flex-wrap: wrap; gap: 4px 20px; }
.footer-legal {
  margin: 18px 0 0;
  padding-top: 14px;
  border-top: 1px solid #eef2f7;
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: var(--fs-micro);
  color: var(--text-soft);
}
@media (min-width: 768px) {
  .footer-legal { flex-direction: row; justify-content: space-between; gap: 20px; }
}
/* El aviso médico no se esconde ni se atenúa. (CLAUDE.md · REGLA 5) */
.medical-disclaimer { color: var(--text-muted); }
/* Leyenda del art. 19 del Reglamento de Publicidad. Va al mismo tono discreto
   que el disclaimer médico, pero legible: la norma pide que se exprese, no que
   se esconda. Ver index.html, pie. */
.responsable-sanitario { color: var(--text-muted); }

/* --------------------------------------------------------------------------
   17. Páginas de sede
   -------------------------------------------------------------------------- */
.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-micro);
  color: var(--text-soft);
}
.breadcrumb a { color: var(--text-muted); }
.breadcrumb a:hover { color: var(--teal); }

.sede-hero {
  padding: 40px var(--pad-x) var(--section-y);
  background: linear-gradient(180deg, #EFF7FB 0%, var(--bg) 100%);
}
.sede-hero__title { font-size: var(--fs-titulo); line-height: 1.02; letter-spacing: -.035em; }

.datos {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}
@media (min-width: 700px) { .datos { grid-template-columns: repeat(2, 1fr); } }
.dato {
  padding: 22px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.dato__label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-soft);
}
.dato__value { font-size: var(--fs-texto); line-height: 1.5; }

/* Hueco de dato pendiente de verificar. (CLAUDE.md · REGLA 6: no se inventa) */
.dato--pendiente { border-style: dashed; border-color: #c9b98a; background: #FFFDF5; }
.dato--pendiente .dato__value { color: #8a7434; }

.servicio-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px 20px;
  padding: 0;
  margin: 0;
  list-style: none;
}
@media (min-width: 600px) { .servicio-list { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .servicio-list { grid-template-columns: repeat(3, 1fr); } }
.servicio-list li {
  position: relative;
  padding-left: 20px;
  font-size: var(--fs-texto);
  color: var(--text-muted);
}
.servicio-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--cyan);
}

.map-embed {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  display: block;
}
@media (max-width: 700px) { .map-embed { aspect-ratio: 4 / 3; } }

/* --------------------------------------------------------------------------
   18. Animación
   -------------------------------------------------------------------------- */
@keyframes cav-pulse {
  0%, 100% { opacity: .35; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.35); }
}
@keyframes cav-sweep {
  0%   { transform: translateX(-120%); }
  100% { transform: translateX(320%); }
}
@keyframes cav-float {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.04); }
  50%      { transform: translate3d(-14px, -10px, 0) scale(1.07); }
}

/* Entrada al hacer scroll.
   Clave: el estado oculto solo existe si el JS ya corrió y marcó <html class="js">.
   Sin JS —o si falla— todo se ve. El original ocultaba con JS sin red de seguridad,
   así que una excepción dejaba la página en blanco. */
.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
  will-change: opacity, transform;
}
.js .reveal.is-visible { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   19. Movimiento reducido — respeta la preferencia del sistema
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }

  /* Las bandas de brillo solo se leen como luz cuando se desplazan: quietas
     parecen una mancha, así que con movimiento reducido se retiran en vez de
     congelarse. El resplandor sí funciona estático. */
  .hero__sweep, .cta__sweep { display: none; }
  .hero__glow { animation: none; }
  .js .reveal { opacity: 1; transform: none; }
  .hero__video, .seccion__video, .seccion__velo,
  .cta__video, .cta__velo { display: none; }
}

/* --------------------------------------------------------------------------
   20. Impresión
   -------------------------------------------------------------------------- */
@media print {
  .site-header, .nav, .wa-float, .search-overlay, .hero__sweep, .cta__sweep { display: none !important; }
  body { background: #fff; }
  .js .reveal { opacity: 1 !important; transform: none !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: var(--fs-micro); color: #555; }
}
