/* ==========================================================================
   Dr. José Padilla — Sistema de diseño para landing pages
   Cirugía General y Laparoscópica · Delicias, Chihuahua

   Estructura, tipografía y ritmo clonados del sistema del Dr. Eduardo Álvarez
   Lozano. Lo único que cambia es la marca: el verde salvia y el barro del
   original salen del logotipo de aquel doctor, y aquí se sustituyen por el
   cobre y el verde del logotipo del Dr. Padilla (estómago cobre, conducto
   verde sobre carbón). Las superficies se quedan como estaban —blanco y
   grises neutros— porque el cobre pide un fondo frío para no amarillear.

   Dirección: cálida y cercana. Pensada para quien llega con un diagnóstico
   quirúrgico encima y miedo a operarse: cuerpo grande, interlineado amplio,
   cero alto contraste agresivo.
   ========================================================================== */

:root {
  /* ---- Superficies ---- */
  /* El fondo pasa de crema a blanco. Los otros dos tonos de superficie bajan
     con él, si no el sitio queda a medias: sobre blanco, un crema que antes
     era casi imperceptible se convierte en una franja amarillenta evidente.
     --cream-deep se queda neutro, no cálido, para que la alternancia de
     secciones siga leyéndose sin volver a introducir el crema por la puerta
     de atrás.

     --paper sube a blanco puro por un motivo concreto: valía #FFFDFA, más
     claro que el fondo de antes, y sobre blanco habría quedado más OSCURO que
     la página. Una tarjeta más sucia que su fondo se ve sin saber por qué.
     Ahora empatan y quien define la tarjeta es su sombra, que es lo que ya
     hacía el trabajo.

     --sand era el crema fuerte: la franja de credenciales bajo el hero, el
     recuadro de la letra pequeña y el plato de los sellos. Es el tono que más
     se notaba al dejarlo cálido, porque va en bloques grandes. Pasa a gris,
     pero un escalón por DEBAJO de --cream-deep: el disclaimer vive dentro de
     una sección --cream-deep y si empatan desaparece el recuadro. */
  --cream: #FBF9F5;        /* papel */
  --cream-deep: #F2EFE8;   /* crema */
  --sand: #EFECE5;         /* línea suave, un escalón por debajo de la crema */
  --sand-line: #E4DFD5;    /* línea */
  --paper: #FFFFFF;        /* la tarjeta sigue siendo blanca sobre el papel */

  /* ---- Tinta (nunca negro puro) ---- */
  --ink: #17140F;
  --ink-soft: #3D372F;
  --ink-muted: #645B51;

  /* ---- Acento: cobre ----
     Los nombres --sage/--clay se conservan a propósito: los usan 2.400 líneas
     de este archivo. Lo que hay detrás ya no es ni verde ni miel: son los
     tokens EXACTOS del sitio en producción del doctor
     (jose-padilla-six.vercel.app), leídos de su hoja compilada:

       --primary #8f5620 · copper-800 #7d4a1a · copper #b87333
       --color-copper-300 #dcb47f · ink #17140f · muted #645b51
       paper #fbf9f5 · cream #f2efe8 · line #e4dfd5 · card #fff

     Su sitio no tiene un segundo acento —es cobre monocromo sobre papel
     cálido—, así que --clay deja de ser un color aparte y pasa al cobre
     profundo: el mismo tono, un paso más oscuro, que es lo que ese sistema usa
     para el texto acentuado. */
  --sage: #8F5620;          /* blanco encima = 5.97:1 ✓ */
  --sage-deep: #7D4A1A;     /* enlaces y hover, sobre papel = 6.97:1 ✓ */
  --sage-mid: #B87333;      /* decorativo: 3.61:1, nunca texto pequeño */
  --sage-pale: #F0DCB8;

  /* Sobre --sage-pale el cobre 700 se queda en 4.44:1, así que lo que caiga
     encima usa el profundo (5.45:1). */
  --clay: #7D4A1A;          /* papel encima = 6.97:1 ✓ */
  --clay-pale: #F0DCB8;

  /* ---- Marca (del logotipo) ---- */
  --navy: #17140F;

  /* ---- Tipografía ---- */
  --font-head: 'Satoshi', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-body: 'Satoshi', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* ---- Oscuro de la cromática: cabecera, pie y botón de WhatsApp ----
     Verde petróleo pedido por el cliente. No sale del sistema de su sitio en
     producción —que es cobre sobre papel— y por eso vive en su propio token:
     así se ve de un vistazo que la cabecera, el pie y el botón flotante van
     juntos y que el resto de la página sigue con la tinta cobre/carbón.
     Blanco encima da 15.84:1, y el cobre #B87333 encima 4.18:1, suficiente
     para el símbolo del logotipo pero no para texto pequeño. */
  --pill: #07262E;
  --pill-hover: #0B3540;

  /* ---- CTA azul: probado y REVERTIDO a petición del cliente ----
     Los botones volvieron al cobre (--sage) y el flotante al verde petróleo
     (--pill). Los tokens se quedan declarados por si el azul vuelve.
     Contrastes medidos: blanco sobre base 6.21:1, sobre hover 11.41:1; el
     claro da 2.23:1 con blanco — sólo tinte o anillo de foco. */
  --cta: #006989;
  --cta-deep: #01526C;
  --cta-hover: #013F54;
  --cta-pale: #7FB6C9;

  /* ---- Layout ---- */
  --wrap: 1140px;
  --wrap-narrow: 780px;
  --r-lg: 26px;
  --r-md: 18px;
  --r-sm: 12px;
  --shadow-soft: 0 2px 6px rgba(43, 39, 35, .03), 0 14px 40px rgba(43, 39, 35, .06);
  --shadow-lift: 0 3px 10px rgba(43, 39, 35, .05), 0 22px 60px rgba(43, 39, 35, .09);
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* La píldora de navegación es `sticky` a 16px del borde y mide 66: sin este
     margen, cada salto del menú («Procedimientos», «Trayectoria»,
     «Consultorio») dejaba el título de la sección debajo de ella. */
  scroll-padding-top: 96px;
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 18.5px;
  font-weight: 300;
  line-height: 1.75;
  letter-spacing: .004em;
  color: var(--ink-soft);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Grano de papel: da textura cálida en vez de plano digital */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .028;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}
body > * { position: relative; z-index: 2; }

/* ---------- Enlace de salto ----------
   Antes del contenido hay una píldora con cuatro enlaces, y en las páginas de
   área el recorrido con teclado hasta el texto pasa por el menú entero en cada
   página. Este enlace vive fuera de la vista hasta que recibe foco. */
.salto {
  position: absolute; left: 12px; top: 12px; z-index: 100;
  transform: translateY(-160%);
  background: var(--pill); color: #fff;
  padding: 12px 18px; border-radius: 10px;
  font-size: .95rem; font-family: var(--font-head);
  transition: transform .18s ease;
}
.salto:focus-visible { transform: none; color: #fff; outline: 2px solid #fff; outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .salto { transition: none; } }

img, video { max-width: 100%; display: block; }
/* Las que sí recortan (hero, consultorio) declaran su propio object-fit. */
.split__media img, .card img, .quote img { height: auto; }
a { color: var(--sage-deep); text-decoration: none; }

/* Sin esto, iOS y Android meten ~300 ms de espera en cada toque por si viene
   un doble toque de zoom, y el sitio se siente lento aunque no lo sea. El
   destello gris del toque se sustituye por uno del color de marca. */
a, button, summary, input, label, [role="button"] {
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(143, 86, 32, .16);
}

h1, h2, h3, h4 {
  font-family: var(--font-head);
  color: var(--ink);
  font-weight: 500;
  line-height: 1.16;
  letter-spacing: -.022em;
  margin: 0 0 .55em;
  /* Evita el desbordamiento en pantallas angostas sin partir palabras con guion */
  overflow-wrap: break-word;
  hyphens: manual;
  text-wrap: pretty;
}
h1 { font-size: clamp(2.15rem, 5vw, 3.6rem); line-height: 1.11; letter-spacing: -.02em; }
h2 { font-size: clamp(1.75rem, 3.4vw, 2.65rem); }
h3 { font-size: clamp(1.22rem, 1.9vw, 1.5rem); line-height: 1.28; }

p { margin: 0 0 1.15em; }
ul { margin: 0 0 1.15em; padding-left: 1.2em; }
li { margin-bottom: .55em; }
strong { color: var(--ink); font-weight: 500; }
em { font-style: italic; }

/* ---------- Utilidades ---------- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: 24px; }
.wrap-narrow { max-width: var(--wrap-narrow); }
/* El fondo es obligatorio, no decorativo: el hero queda sticky por debajo y
   una sección transparente lo dejaría verse a través. Coincide con el fondo
   del body, así que no cambia nada a la vista. Los modificadores de más
   abajo (--surface, --sand, --deep) lo sobrescriben. */
.section { padding: clamp(64px, 9vw, 120px) 0; background: var(--cream); }
.section--surface { background: var(--cream-deep); }
.section--sand { background: var(--sand); }
.center { text-align: center; }

.section--deep {
  background: var(--sage-deep);
  color: #D5E0D6;
}
.section--deep h2, .section--deep h3 { color: #FDFBF7; }

.eyebrow {
  font-family: var(--font-body);
  font-size: .8rem;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--clay);
  margin: 0 0 1rem;
}
.section--deep .eyebrow { color: #B9CDBB; }

.lead { font-size: 1.16rem; line-height: 1.72; color: var(--ink-soft); }
.section--deep .lead { color: #E4DFD5; }

.section-head { max-width: 680px; margin-bottom: clamp(40px, 5.5vw, 64px); }
.section-head.center { margin-inline: auto; }

/* ---------- Botones ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55em;
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.3;
  padding: 1.02em 1.75em;
  border: 1.5px solid transparent;
  border-radius: 100px;
  cursor: pointer;
  text-align: center;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease, transform .2s ease;
}
.btn:hover { transform: translateY(-1px); }

/* Primario: salvia. Es el único botón con relleno fuerte. */
.btn--primary { background: var(--sage); color: #FDFBF7; }
.btn--primary:hover { background: var(--sage-deep); }

/* WhatsApp: secundario y discreto, no compite con la marca */
.btn--wa { background: var(--paper); color: var(--sage-deep); border-color: var(--sand-line); }
.btn--wa:hover { border-color: var(--sage); background: var(--sage-pale); }

.btn--ghost { background: transparent; color: var(--ink); border-color: var(--sand-line); }
.btn--ghost:hover { border-color: var(--ink-muted); background: var(--paper); }

.btn--light { background: #fff; color: var(--pill); }
.btn--light:hover { background: #fff; }
.btn--outline-light { background: transparent; color: #EAF0EA; border-color: rgba(255,255,255,.34); }
.btn--outline-light:hover { background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.6); }

.btn-row { display: flex; flex-wrap: wrap; gap: 14px; }
.btn-note { font-size: .93rem; color: var(--ink-muted); margin: 1.15rem 0 0; line-height: 1.6; }
/* Sobre el fondo oscuro, la nota heredaba --ink-muted, un gris
   cálido pensado para fondo crema: daba 2,06:1, muy por debajo del 4,5:1 de
   AA. El .cta-final no es .section--deep, así que la regla de al lado nunca
   llegaba a aplicarse allí. Ahora se cubren las dos, con un tono que da 6,05:1. */
.section--deep .btn-note,
.cta-final .btn-note { color: #D5E0D6; }

/* El precio tachado es información, no adorno: tiene que leerse. Con opacidad
   .6 se quedaba en 1,56:1; con .82 sube a 4,7:1. Y la línea del tachado pasa a
   un barro aclarado, porque el --clay original daba 1,46:1 sobre este verde. */
.section--deep .btn-note .precio-antes,
.cta-final .btn-note .precio-antes {
  opacity: .82;
  text-decoration-color: #D3A98C;
}

/* ---------- Píldora de navegación flotante ----------
   CLARA por pedido del cliente (antes iba en el verde petróleo --pill, que
   se queda para el pie). Sobre la foto del hero se sostiene con el borde y
   la sombra, no con el color. */
.navpill { position: sticky; top: 16px; z-index: 60; padding-top: 16px; }
.navpill__inner {
  background: var(--cream);
  border: 1px solid var(--sand-line);
  border-radius: 44px;
  min-height: 66px;
  display: flex; align-items: center; gap: 22px;
  padding: 9px 9px 9px 26px;
  box-shadow: 0 8px 30px rgba(20, 17, 14, .14);
}
.navpill__logo img { height: 34px; width: auto; display: block; filter: brightness(0) invert(1); }
.navpill__links { display: flex; gap: 26px; margin-inline: auto; }
.navpill__links a { color: var(--ink); font-size: .97rem; font-weight: 600; }
.navpill__links a:hover { color: var(--ink); }
.navpill__spacer { flex: 1; }
.navpill__phone { color: var(--ink-soft); font-size: .95rem; white-space: nowrap; }
.navpill .btn { padding: .72em 1.5em; font-size: .95rem; }
@media (max-width: 1000px) { .navpill__links { display: none; } }
@media (max-width: 720px)  { .navpill__phone { display: none; } }
@media (max-width: 460px)  { .navpill__inner { padding-left: 18px; } .navpill__logo img { height: 28px; } }
/* En móvil la píldora va justa: el botón del header se acorta a "Agendar".
   Solo afecta al header; el CTA del hero mantiene el texto completo. */
@media (max-width: 640px)  { .navpill .btn .solo-ancho { display: none; } }

/* ---------- Marca del Dr. Padilla en la píldora y en el pie ----------
   El logotipo del sitio original era una firma horizontal y cabía entera en
   34 px de alto. Éste es un símbolo apilado SOBRE el nombre, casi cuadrado: a
   34 px de alto el nombre baja a seis píxeles y deja de leerse. Se parte en
   dos piezas —el símbolo como imagen, el nombre como texto de la propia
   página— y la píldora conserva su altura sin perder la marca.

   Y no se blanquea. El original invertía el logotipo a blanco puro porque el
   suyo era monocromo; aquí el cobre y el hueso SON la marca, y sobre el
   carbón de la píldora contrastan de sobra. */
.navpill__logo { display: flex; align-items: center; gap: 11px; }
.navpill__logo img { height: 30px; filter: none; }
.navpill__marca {
  font-family: var(--font-head);
  font-weight: 500; font-size: 1.03rem; letter-spacing: -.015em;
  color: var(--ink); white-space: nowrap;
}
@media (max-width: 460px) {
  .navpill__logo img { height: 26px; }
  .navpill__marca { font-size: .95rem; }
}
/* Por debajo de 380 px el nombre se lleva el sitio del botón de agendar, que
   es lo único que la píldora tiene que garantizar. Queda el símbolo, y el
   nombre del doctor está tres centímetros más abajo, en el H1 del hero. */
@media (max-width: 380px) { .navpill__marca { display: none; } }

/* OBJETIVOS TÁCTILES DE LA PÍLDORA. Los enlaces del menú, el teléfono y el
   propio logotipo medían 27-30 px de alto: el texto marca el alto de la caja y
   ahí se queda. La píldora ya mide 66, así que hay sitio de sobra para llevar
   cada uno a 44 sin mover nada de sitio ni cambiar el aire entre ellos —lo
   único que crece es la zona sensible, que es justo lo que no se ve. */
.navpill__logo,
.navpill__links a,
.navpill__phone {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.navpill__links { align-items: center; }

/* (La regla del logotipo del pie está junto a la del pie, más abajo: aquí
   quedaba por delante de la original y no ganaba.) */

/* ---------- Hero a sangre ---------- */
.hero {
  /* El hero se queda anclado arriba y las secciones siguientes suben por
     encima de él. No se desactiva con prefers-reduced-motion: sticky es
     maquetación, el scroll sigue siendo 1:1 y no hay efecto de paralaje.
     No hace falta tocar z-index: todas las hermanas comparten el z-index 2 de
     `body > *`, y al ir después en el DOM se pintan encima. */
  position: sticky;
  top: 0;
  /* Pantalla completa. svh usa el alto visible real del móvil (sin contar la
     barra del navegador cuando está desplegada), así el hero no queda cortado.
     La regla vh de arriba es el respaldo para navegadores sin svh. */
  min-height: 100vh;
  min-height: 100svh;
  margin-top: -82px;          /* la píldora flota encima de la foto */
  display: flex;
  /* CENTRADO VERTICAL, no anclado abajo: en el mock el bloque de texto vive
     hacia el centro del hero (el titular arranca al ~42% del alto), y con
     align-end ningún ajuste de padding lo alcanzaba — siempre quedaba pegado
     al borde. El sesgo hacia abajo lo pone el padding del contenido: arriba
     hay 120px de holgura por la píldora y abajo bastan ~40. */
  align-items: center;
  overflow: hidden;
  background: var(--pill);
}
.hero__bg { position: absolute; inset: 0; }
.hero__bg img {
  /* Se ensancha la imagen (sin desplazarla) para que la figura caiga a la
     derecha y la columna del titular quede libre. Con margin-left quedaba
     una franja vacía en el borde izquierdo.

     --hero-zoom gobierna el tamaño del doctor: al ser object-fit:cover, la
     escala la marca el ancho. Subirlo acerca, bajarlo aleja. 1.18 era el
     valor original; 1.09 lo deja levemente más pequeño. */
  --hero-zoom: 1.09;
  width: calc(var(--hero-zoom) * 100%);
  height: 100%;
  object-fit: cover;
  object-position: 50% 28%;
}

/* ---------- El doctor, recortado ----------
   Centrado y SIN atenuar, como en su sitio en producción: va después del velo
   en el DOM, así que el degradado oscurece la habitación pero no a él.

   Eso tiene una consecuencia que manda sobre toda la maqueta del hero: su bata
   es lo más claro de la composición, y cualquier letra blanca encima sería
   ilegible —no hay text-shadow que arregle eso, y un velo local sobre él sería
   volver a atenuarlo—. La única salida es que NINGÚN texto le caiga encima,
   así que la columna izquierda se estrecha, el botón de reproducir baja bajo
   el titular y la figura se dimensiona para caber en el hueco que queda entre
   esa columna y el párrafo de la derecha.

   EL TAMAÑO LO GOBIERNA EL ANCHO, no un porcentaje de alto. El techo real es
   el hueco entre la columna de texto y el párrafo de la derecha. Medido en el
   navegador: el texto termina a 379px del borde del wrap, así que centrada la
   figura no puede pasar de 1140−758=382px por encima de 1188px de viewport, y
   por debajo el hueco encoge con la ventana (100vw−758). Se pide el máximo
   con 2px de aire — min(378px, 100vw − 762px) — y el alto sale solo de la
   proporción de la imagen (0.648). Antes iba a 62% de alto = 314px de ancho;
   así queda un 20% más grande sin pisar nada. Si se agranda la columna de
   texto hay que rebajar este techo. */
.hero__figura {
  /* A la derecha del centro, como en el mock: centrada en el 68% del ancho y
     a un 82% de alto. El texto llega como mucho a 34vw + el margen del wrap,
     y el borde izquierdo de la figura (68vw menos media anchura) queda por
     encima de eso en todos los anchos medidos. */
  --figura-alto: min(82%, 780px);
  position: absolute;
  left: 68%;
  translate: -50%;
  bottom: 0;
  height: var(--figura-alto);
  width: auto;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}
.hero__figura img {
  height: 100%;
  width: auto;
  max-width: none;
  display: block;
  /* Sombra de contacto, no un velo: sin ella el recorte flota sobre la foto y
     se ve el montaje. Sigue el contorno, no una caja. */
  filter: drop-shadow(0 20px 34px rgba(23, 20, 15, .5));
}

/* EN VERTICAL NO SALE, y es una decisión, no un olvido.
   Debajo de 900 px el titular pasa a ocupar el ancho entero y no queda hueco
   libre: allí la figura o se cruza con el texto o se queda en un jirón pegado
   al borde. Su sitio en producción sí la enseña en vertical porque su hero
   está montado para eso —texto arriba, figura ocupando el bajo entero—, y
   reproducirlo aquí es rehacer la maqueta, no ajustar un porcentaje. Está
   anotado en PENDIENTES.md. */
@media (max-width: 900px) {
  /* En móvil el doctor sí aparece, como en la imagen OG: anclado a la
     derecha, cara visible y el borde derecho ligeramente cortado. El alto
     se limita para que la cabeza quede bajo el titular y no lo pise. */
  .hero__figura {
    /* Primer plano como en la imagen OG: solo cara, cuello y hombros.
       La figura se agranda mucho y se empuja hacia abajo; overflow:hidden
       del hero recorta el resto del cuerpo. */
    --figura-alto: 106svh;
    left: auto;
    right: -49vw;
    bottom: -64svh;
    translate: 0;
  }
}

/* Garabatos decorativos del mock: blancos, finos, sin interacción. */
.hero__doodle { position: absolute; z-index: 2; opacity: .85; pointer-events: none; }
.hero__doodle--asterisco { left: 54%; top: 30%; width: clamp(28px, 3vw, 44px); }
.hero__doodle--estetoscopio { left: 79%; top: 16%; width: clamp(44px, 4.6vw, 72px); }
@media (max-width: 900px) { .hero__doodle { display: none; } }

/* Velo doble: uno inferior para anclar el texto, otro lateral para el titular */
/* VELO DEL HERO, MEDIDO SOBRE LA FOTO QUE HAY DETRÁS.
   La foto pasó a ser la misma que usa jose-padilla-six.vercel.app: la recepción
   del consultorio, con la pared de diplomas y la persiana. Es bastante más
   clara que la anterior —donde el doctor tapaba media imagen— y con el velo de
   antes el H1 pequeño se quedaba en 2,84:1 y el párrafo de la derecha en
   3,66:1, los dos por debajo del 4,5 que pide el texto normal.

   Los valores no son a ojo: se fotografió el hero con el texto oculto, se
   buscó el píxel MÁS CLARO bajo cada bloque y se calculó desde ahí. Doce por
   ciento más de velo es lo que hace falta, y es poco: la pared de diplomas y
   los girasoles siguen leyéndose. Si algún día se cambia la foto, hay que
   repetir la medición — no vale suponer que aguanta. */
/* Velo correlacionado con el mock del cliente (2026-08-19), no a ojo: medido
   por zonas, el mock es ~1.5x más luminoso donde vive el texto y ~3x en la
   franja baja. Los topes anteriores (.50/.70) venían de la foto oscura del
   principio. Si el texto sufre en alguna foto futura, medir antes de subir. */
.hero__scrim { position: absolute; inset: 0; background: linear-gradient(rgba(0,0,0,.10) 0%, rgba(0,0,0,.24) 78%, rgba(0,0,0,.24) 100%); }
.hero__scrim::after {
  content: ""; position: absolute; inset: 0;
  /* Un solo velo lateral, el de la izquierda, que es el que sostiene el
     titular. Hubo un segundo por la derecha mientras la figura estuvo pegada
     a ese borde y el párrafo caía sobre su bata; centrada la figura, el
     párrafo vuelve a estar sobre la fotografía y ese velo sobraba. */
  background:
    linear-gradient(96deg, rgba(0,0,0,.52) 0%, rgba(0,0,0,.36) 26%, rgba(0,0,0,.16) 52%, rgba(0,0,0,.08) 72%, transparent 84%),
    linear-gradient(276deg, rgba(0,0,0,.15) 0%, transparent 26%);
}

.hero__content { position: relative; z-index: 3; width: 100%; padding: 120px 0 66px; }
/* Una columna: el aside murió con la maqueta del mock; la derecha es de la figura. */
.hero__grid { display: grid; grid-template-columns: 1fr; align-items: end; }

/* El H1 de verdad de la página.
   El titular grande del hero es un gancho emocional: «Recupera la rodilla que
   el dolor te quitó» no dice el procedimiento ni la ciudad, que es justo lo
   que un H1 tiene que decirle a un buscador. En vez de estropear el titular,
   el H1 va aquí, como línea de contexto entre las etiquetas y el titular, y
   ese titular pasa a H2 sin tocar ni una letra ni un píxel de su aspecto.
   Va debajo de las etiquetas y no encima para que caiga por debajo de la
   cara del doctor: el bloque está alineado abajo, así que intercambiarlos no
   cambia el alto total, sólo baja la línea unos 40px.

   Va VISIBLE a propósito. Un H1 metido en un .sr-only sólo para el buscador es
   texto oculto, y ahí Google distingue mal entre accesibilidad y relleno de
   palabras clave. Visible cuesta dos renglones y no tiene ese riesgo. */
.hero__h1 {
  /* Blanco opaco (un translúcido no llegaba al 4,5:1 sobre esta foto) y al
     tamaño del mock: su banda de píxeles mide 10px de x-altura ≈ 20px de
     fuente, contra los 14,7 que traíamos. */
  color: #fff;
  font-family: var(--font-body);
  font-size: 1.22rem;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: 0;
  margin: 0 0 13px;
  /* Sin tope de ancho: cabe en un renglón. Medido con el texto real de las
     cinco páginas, el más largo (condrograft, 90 caracteres) ocupa 592px y la
     columna del hero da 697px. El 46ch que había antes lo partía en dos sin
     necesidad. Por debajo de ~700px de ventana ya no cabe en una línea a un
     tamaño legible —harían falta 9px— así que ahí se parte, y se parte
     equilibrado. */
  max-width: 100%;
  text-wrap: balance;
  text-shadow: 0 1px 14px rgba(0, 0, 0, .4);
}

/* Franja incómoda: a partir de 901px el hero se parte en dos columnas y el H1
   pasa de tener la ventana entera a tener sólo la columna izquierda, que ahí
   todavía es más angosta que el texto. Medido: a 901px la columna da ~542px y
   el H1 más largo (condrograft) necesita 592px; a 1024px ya da 616px y cabe.
   Un punto menos de tamaño en esa banda mantiene el renglón único. */
@media (min-width: 901px) and (max-width: 1010px) {
  .hero__h1 { font-size: .82rem; }
}

/* El titular del hero. Es un H2 desde que el H1 pasó a ser la línea de
   contexto de arriba; el aspecto no cambió, sólo la etiqueta. Se apunta por
   .hero__headline h2 y no por .hero h2 para no alcanzar los H2 de las demás
   secciones, que sí llevan el tamaño normal. */
.hero__headline h2 {
  color: #fff;
  /* Métrica del mock, medida por bandas de píxeles: fuente ~55px e
     interlineado 1.27 a 1657 de ancho (la altura de banda del mock es 40px y
     el paso entre líneas 70). Con 64/1.12 el bloque quedaba un 4% más alto. */
  font-size: clamp(2.2rem, 3.35vw, 3.5rem);
  font-weight: 700;
  line-height: 1.27;
  letter-spacing: -.024em;
  margin: 0;
  max-width: 15ch;
  text-shadow: 0 2px 30px rgba(0,0,0,.34);
}
.hero__headline h2 em { font-style: normal; color: rgba(255,255,255,.62); }

/* La banda gris bajo «explicados antes de operar.» del mock: un subrayado
   grueso y translúcido pegado a la base, no una caja. */
.hero__headline .subrayado {
  background: linear-gradient(rgba(255,255,255,.26), rgba(255,255,255,.26)) left calc(100% - .12em) / 100% .42em no-repeat;
  padding-bottom: .12em;
}

/* Fila de acciones: Agendar grande + el botón de play, lado a lado. */
.hero__acciones {
  display: flex; align-items: center; gap: clamp(18px, 2.4vw, 30px);
  max-width: var(--hero-texto, none);
  margin-top: clamp(18px, 2.4vw, 30px);
  flex-wrap: wrap;
}
.btn--hero {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 1.02em 2.3em;
  font-size: 1.02rem;
}
.btn--hero svg { width: 19px; height: 19px; }

.hero__aside p { color: rgba(255,255,255,.95); font-size: 1.02rem; line-height: 1.66; margin: 0 0 1.5rem; text-shadow: 0 1px 16px rgba(0,0,0,.35); }
.hero__aside .btn-note { color: rgba(255,255,255,.66); margin-top: 1rem; font-size: .88rem; }

@media (max-width: 900px) {
  .hero { min-height: 100vh; min-height: 100svh; }
  .hero__bg img { width: 100%; margin-left: 0; object-position: 52% 20%; }
  .hero__grid { grid-template-columns: 1fr; gap: 30px; align-items: start; }
  .hero__headline h2 { max-width: 100%; }
  /* El velo se aligera donde no hay texto y se mantiene donde sí lo hay. No es
     una reducción uniforme a propósito: el titular cae justo sobre el ventanal
     del fondo, que es la zona más clara de la foto, y ahí bajar el velo se
     lleva por delante el contraste. Medido sobre los píxeles reales de la
     imagen, en el peor de todos ellos: titular 3,46:1 (AA de texto grande pide
     3), párrafo 5,40:1 y píldora de reseñas 5,07:1 (AA pide 4,5).

     Arriba (donde está la cara) y abajo se aligera mucho: .30 → .10 el velo
     superior y .74 → .56 el pie. En el centro casi no se toca: .50 → .48. */
  .hero__scrim { background: linear-gradient(rgba(0,0,0,.06) 0%, rgba(0,0,0,.48) 52%, rgba(0,0,0,.56) 100%); }
  .hero__scrim::after { background: linear-gradient(rgba(0,0,0,.10) 0%, transparent 45%); }
}

/* ---------- El hero en teléfono ----------
   El hero mide la pantalla MENOS la barra fija de WhatsApp y Llamar. Así el
   hero entra entero de una vez y la barra queda debajo, no encima: antes se
   montaba sobre él y se comía la última línea del párrafo.

   --cta-movil es el alto de esa barra. Va como variable porque lo usan las dos
   reglas y tienen que moverse juntas; si algún día cambia el tamaño del botón,
   se toca aquí y basta.

   El bloque de texto está anclado abajo, así que para bajarlo sólo cabe que
   ocupe menos: cada píxel recortado es un píxel más de retrato visible. De ahí
   que se quite el botón —la píldora superior es `sticky` y lleva el mismo CTA
   a la vista todo el rato, así que no se pierde ninguna llamada a la acción— y
   que se aprieten los espacios intermedios. */
@media (max-width: 700px) {
  :root { --cta-movil: 76px; }
  .hero {
    min-height: calc(100vh - var(--cta-movil));
    min-height: calc(100svh - var(--cta-movil));
  }
  /* Sin botón en el hero: el CTA queda en la píldora superior, que es `sticky`
     y no se va nunca, y en la barra inferior.

     Ojo en las páginas de procedimiento: la barra inferior de esas cuatro es
     WhatsApp y Llamar, así que al quitar este botón el formulario se queda sin
     ningún acceso fijo sobre la línea de flotación en móvil. Está decidido así
     a propósito; si algún día se quiere recuperar, lo natural es cambiar el
     botón verde de `.mobile-cta` por uno con data-modal="lead". */
  .hero__aside .btn { display: none; }
  /* El botón está oculto justo encima, así que el párrafo es el último
     elemento que se ve y su margen inferior era espacio muerto: 24px que en
     un teléfono corto salen de la última línea del propio párrafo.
     Antes esto decía p:last-child y no llegaba a aplicarse nunca: :last-child
     mira el DOM, no lo que se ve, y el último hijo del aside sigue siendo el
     botón aunque esté en display:none. */
  .hero__aside p { margin-bottom: 0; }
  .hero__grid { gap: 20px; }
  .hero__content { padding-bottom: 28px; }
}

/* ---------- Teléfonos de pantalla corta ----------
   La foto llena el alto exacto del hero: no sobra ni un píxel por arriba ni
   por abajo, así que el recorte es proporcional y la cara del doctor cae
   siempre en el mismo PORCENTAJE del hero, mida lo que mida. El bloque de
   texto, en cambio, mide 400px fijos y va anclado abajo.

   De ahí el problema: en un hero de 820px el texto arranca al 51% del alto,
   por debajo de la cara; en uno de 624px —un iPhone con las barras de Safari
   desplegadas— arranca al 31%, justo encima de ella. La foto no cambia; lo que
   cambia es cuánto se come el texto.

   La solución es apretar el bloque cuando el hero es corto, no tocar la foto:
   así el texto vuelve a arrancar cerca del 38% y la composición se parece a la
   de una pantalla alta. Nada se elimina, sólo encoge.

   Los dos escalones no son arbitrarios. Medido sobre los píxeles de la propia
   foto: la cabeza empieza al 15,8% del alto, la barbilla ronda el 36% y el
   cuello del uniforme está al 48,7%. Para que el texto no se le monte a la
   cara tiene que arrancar por debajo del 38%, es decir, el bloque más su
   margen inferior no pueden pasar del 62% del alto del hero. Con los valores
   de siempre eso sólo se cumple a partir de un hero de 780px. */
@media (max-width: 700px) and (max-height: 800px) {
  .hero__headline h2 { font-size: 2.05rem; }
  .hero__h1 { font-size: .85rem; line-height: 1.34; margin-bottom: 9px; }
  .hero__aside p { line-height: 1.55; }
  .hero__headline { gap: 12px; }
  .hero__grid { gap: 14px; }
  .hero__reviews { margin-top: 14px; }
  .hero__content { padding-bottom: 20px; }
}
/* Segundo escalón para los teléfonos pequeños con las barras del navegador
   desplegadas, donde el hero se queda por debajo de 600px. */
@media (max-width: 700px) and (max-height: 700px) {
  .hero__headline h2 { font-size: 1.82rem; }
  .hero__h1 { font-size: .8rem; line-height: 1.3; margin-bottom: 7px; }
  .hero__headline { gap: 9px; }
  .hero__grid { gap: 10px; }
  .hero__reviews { margin-top: 10px; }
  .hero__aside p { font-size: .92rem; line-height: 1.45; }
  .hero__content { padding-bottom: 10px; }
  .play-cta__disc { width: 46px; height: 46px; }
}

/* ---------- Franja de confianza ---------- */
.trustbar {
  background: var(--sand);
  /* Sombra hacia arriba: da el relieve de la sección montándose sobre el hero */
  box-shadow: 0 -18px 46px rgba(20, 17, 14, .22);
}
.trustbar__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 34px 28px;
  padding: clamp(38px, 5vw, 56px) 0;
}
.trustbar__item { text-align: center; }
.trustbar__item b {
  /* Rejilla centrada y con alto fijo: en esta franja conviven cifras y sellos,
     y sin una caja común cada columna empujaría su descripción a una altura
     distinta. 1,3em de la propia tipografía deja sitio al sello sin que las
     cifras queden flotando. */
  display: grid;
  place-items: center;
  min-height: 1.3em;
  font-family: var(--font-head);
  font-size: clamp(1.7rem, 2.7vw, 2.3rem);
  font-weight: 500;
  color: var(--sage-deep);
  line-height: 1.05;
  letter-spacing: -.02em;
  /* Cifras de ancho fijo: el contador va de 0 a 30 y sin esto el número
     bailaría de lado en cada fotograma. */
  font-variant-numeric: tabular-nums;
}
.trustbar__item b img { height: 1.25em; width: auto; display: block; }

/* EXCEPCIÓN DE LA UAG. Los otros tres logotipos de institución son sellos casi
   cuadrados (IMSS 273×337, UACH 218×236, Puerta de Hierro 146×152) y a una
   altura común quedan del mismo tamaño. El de la UAG no: es un logotipo
   horizontal de 724×211, casi 3,5:1, y además sus letras ocupan todo el alto
   de la marca. A la misma altura que los sellos salía 158 px de ancho contra
   los 46 de ellos —el triple— y se comía la fila.
   Se baja hasta que su ancho quede en el mismo orden que el de los sellos. La
   referencia no es el alto de la caja, que es lo que iguala el CSS, sino el
   tamaño con el que cada marca se lee. */
.trustbar__item b img[src*="uag"] { height: .78em; }
.trustbar__item span {
  font-size: .89rem;
  color: var(--ink-soft);
  display: block;
  margin-top: 9px;
  line-height: 1.5;
}
@media (max-width: 720px) { .trustbar__grid { grid-template-columns: repeat(2, 1fr); } }

/* ---------- Rejillas ---------- */
.grid { display: grid; gap: 24px; }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .grid--2, .grid--3 { grid-template-columns: 1fr; } }

.card {
  background: var(--paper);
  border-radius: var(--r-lg);
  padding: 34px 32px;
  box-shadow: var(--shadow-soft);
}
.card h3 { margin-bottom: .5em; }
.card p:last-child { margin-bottom: 0; }
.card__icon {
  width: 50px; height: 50px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--sage-pale);
  color: var(--sage-deep);
  margin-bottom: 20px;
}
.card__icon svg { width: 24px; height: 24px; }
.section--deep .card { background: rgba(255,255,255,.07); box-shadow: none; }

/* La negrita heredaba `strong { color: var(--ink) }`, que es la tinta oscura
   del sitio. Sobre el verde de una sección oscura eso daba 2,64:1 — la frase
   que más se quería destacar era la que peor se leía. La excepción existía
   sólo para .creds li strong; se generaliza. Blanco papel sobre el velo del
   10%: 6,05:1. */
.section--deep strong { color: #FDFBF7; }

/* Tarjeta destacada: la opción que el texto recomienda va con más velo para
   separarse de la otra. Estaba al 14% en un `style` suelto del HTML, y ese
   punto extra de claridad dejaba el párrafo en 4,14:1. Al 10% sube a 4,61:1
   sin perder la distinción. */
.section--deep .card--destaca { background: rgba(255, 255, 255, .10); }

/* ---------- Lista de síntomas ---------- */
.symptoms { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px 36px; margin: 0; padding: 0; list-style: none; }
.symptoms li {
  position: relative;
  padding-left: 38px;
  margin: 0;
  font-size: 1.06rem;
  line-height: 1.55;
  color: var(--ink);
}
.symptoms li::before {
  content: "";
  position: absolute; left: 0; top: .18em;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--sage-pale) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237D4A1A' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 13px no-repeat;
}
@media (max-width: 640px) { .symptoms { grid-template-columns: 1fr; } }

/* ---------- Bloque partido ---------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(34px, 5vw, 68px); align-items: center; }
.split--wide-text { grid-template-columns: 1.12fr .88fr; }
/* En la sección de autoridad la lista de credenciales es larga: la foto se
   queda fija mientras se recorre, en vez de irse por arriba de la pantalla.
   Hace falta align-self:start porque el contenedor centra sus ítems y un ítem
   centrado ocupa toda la fila, sin margen donde poder pegarse. */
.section--deep .split__media {
  position: sticky;
  top: clamp(96px, 12vh, 130px);
  align-self: start;
}
@media (max-width: 900px) {
  .section--deep .split__media { position: static; }
}

.split__media img {
  border-radius: var(--r-lg); box-shadow: var(--shadow-lift);
  width: 100%;
  /* Sin esto el navegador usa el atributo height="…" como altura literal y
     deforma la foto. Hace falta siempre que se fije el ancho en porcentaje. */
  height: auto;
}
@media (max-width: 900px) { .split, .split--wide-text { grid-template-columns: 1fr; } }

/* ---------- Credenciales ---------- */
/* ---------- Credenciales ----------
   Lenguaje shadcn/21st.dev: filete de separación, chip cuadrado de esquina
   suave con el icono, y la jerarquía puesta en el peso del texto y no en el
   color. El icono va en un ::before con SVG embebido para no tocar el HTML. */
.creds {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(28px, 3.4vw, 52px);
  row-gap: 0;
}
/* Con dos columnas el filete superior sobra en los dos primeros ítems, no
   sólo en el primero. */
.creds li:nth-child(-n+2) { border-top: 0; padding-top: 0; }
.creds li:nth-child(-n+2)::before { top: 1px; }
/* El chip va absoluto y no como columna de una rejilla: con display:grid en el
   <li>, cada <strong> del texto se convierte en celda y la frase se despedaza. */
.creds li {
  position: relative;
  margin: 0;
  padding: 17px 0 17px 46px;
  line-height: 1.62;
  border-top: 1px solid var(--sand-line);
}
.creds li:last-child { padding-bottom: 0; }
.creds li::before {
  content: "";
  position: absolute; left: 0; top: 18px;
  width: 28px; height: 28px;
  border-radius: 9px;
  background-color: var(--sage-pale);
  border: 1px solid rgba(143, 86, 32, .22);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238F5620' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 13px;
}

/* Sobre el fondo oscuro con foto, el chip se vuelve traslúcido para no
   convertirse en siete manchas claras sobre la imagen. */
.section--deep .creds li { color: #E4DFD5; border-top-color: rgba(255, 255, 255, .13); }
.section--deep .creds li strong { color: #FDFBF7; font-weight: 500; }
.section--deep .creds li::before {
  background-color: rgba(255, 255, 255, .1);
  border-color: rgba(255, 255, 255, .2);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F0DCB8' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
}

@media (max-width: 560px) {
  .creds li { padding: 14px 0 14px 38px; }
  .creds li::before { width: 24px; height: 24px; border-radius: 8px; background-size: 11px; top: 15px; }
  .creds li:first-child::before { top: 0; }
}

/* ---------- Pasos ---------- */
.steps { display: grid; gap: 20px; counter-reset: step; }

/* ---------- Pasos que se apilan al bajar ----------
   Cada tarjeta se queda pegada un poco más abajo que la anterior, así al
   desplazarse se van amontonando en lugar de salir por arriba. El desfase
   creciente deja ver el borde de las que quedan debajo. */
.steps--apiladas { display: block; }
.steps--apiladas .step {
  position: sticky;
  margin-bottom: 20px;
  /* Fondo opaco: si fuera translúcido se verían las de debajo a través */
  background: var(--paper);
}
/* Los desfases van dentro de la consulta, no fuera con un `top: auto` que los
   deshaga después: llevan `:nth-child` y ganaban por especificidad a cualquier
   intento de anularlos desde el bloque de móvil. Si sólo existen cuando el
   apilado está activo, no hay nada que deshacer. */
@media (min-width: 701px) {
  .steps--apiladas .step:nth-child(1) { top: 110px; }
  .steps--apiladas .step:nth-child(2) { top: 124px; }
  .steps--apiladas .step:nth-child(3) { top: 138px; }
  .steps--apiladas .step:nth-child(4) { top: 152px; }
  .steps--apiladas .step:nth-child(5) { top: 166px; }
  .steps--apiladas .step:nth-child(6) { top: 180px; }
  .steps--apiladas .step:nth-child(7) { top: 194px; }
}
/* Espacio al final para que la última llegue a pegarse antes de que acabe */
.steps--apiladas::after { content: ""; display: block; height: 40vh; }

@media (max-width: 700px) {
  /* En pantallas bajas apilar deja muy poco visible: vuelve al flujo normal.

     `relative` y no `static`, que es lo que había: el número de cada paso es un
     ::before con `position: absolute`, y con la tarjeta en `static` deja de ser
     su bloque contenedor. Los seis números se escapaban al ancestro posicionado
     más cercano y se amontonaban en la esquina de la sección, uno encima de
     otro; sólo se veía el último, que marcaba 6, flotando sobre el titular, y
     las tarjetas quedaban sin numerar.

     Y hace falta `top: auto`. Con `static` los `top: 110px…180px` del apilado
     se ignoraban; con `relative` vuelven a contar y desplazan cada tarjeta
     hacia abajo sin mover su hueco, así que se montaban entre ellas y la
     última se salía de la sección por 180px justos. */
  .steps--apiladas .step { position: relative; top: auto; }
  .steps--apiladas::after { display: none; }
}
/* No se desactiva con prefers-reduced-motion: sticky es maquetación, no
   animación. El scroll sigue siendo 1:1 y no produce el efecto vestibular del
   paralaje. Sí se desactiva en pantallas bajas, donde apilar deja poco visible. */
.step {
  position: relative;
  background: var(--paper);
  border-radius: var(--r-lg);
  padding: 30px 34px 30px 92px;
  box-shadow: var(--shadow-soft);
}
.step::before {
  counter-increment: step;
  content: counter(step);
  position: absolute; left: 30px; top: 30px;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--sage-pale);
  color: var(--sage-deep);
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 1.15rem;
}
.step h3 { font-size: 1.2rem; margin-bottom: .35em; }
.step p { margin: 0; font-size: 1.01rem; }
.step__time {
  display: inline-block;
  font-size: .78rem;
  font-weight: 400;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--clay);
  margin-bottom: .65em;
}
@media (max-width: 560px) {
  .step { padding: 76px 26px 28px; }
  .step::before { left: 26px; top: 24px; }
}

/* ---------- Precio ---------- */
.pricing { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; align-items: start; }
/* Una sola tarjeta: sin esto se queda en la mitad izquierda de una rejilla de
   dos, descuadrada. Se usa en las páginas donde sólo se publica el precio de
   la consulta y no el de la cirugía. */
.pricing--sola { grid-template-columns: 1fr; max-width: 560px; margin-inline: auto; }
.price-card {
  background: var(--paper);
  border-radius: var(--r-lg);
  padding: 38px 36px;
  box-shadow: var(--shadow-soft);
}
.price-card--main { box-shadow: var(--shadow-lift); outline: 2px solid var(--sage); outline-offset: -2px; }
.price-card__label { font-size: .87rem; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-muted); margin-bottom: .7rem; }
.price-card__amount {
  font-family: var(--font-head);
  font-size: clamp(2.1rem, 3.6vw, 2.9rem);
  font-weight: 500;
  color: var(--ink);
  line-height: 1.05;
  letter-spacing: -.025em;
}
.precio-antes {
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--clay);
  opacity: .55;
  font-weight: 300;
  margin-right: .18em;
}
.price-card__amount .precio-antes { font-size: .62em; }
.btn-note .precio-antes { opacity: .6; }

.price-card__amount small { font-size: .38em; font-weight: 300; color: var(--ink-muted); letter-spacing: 0; font-family: var(--font-body); }
/* La condición del precio va pegada al importe, antes que la duración: es la
   letra pequeña de la cifra tachada y tiene que leerse junto a ella. */
.price-card__anticipado {
  font-size: .88rem;
  line-height: 1.5;
  color: var(--ink-muted);
  margin: .35rem 0 0;
  max-width: 34ch;
}
.price-card__meta { font-size: .97rem; color: var(--ink-muted); margin: .9rem 0 1.5rem; }
.price-card ul { list-style: none; padding: 0; margin: 0 0 1.7rem; }
.price-card ul li { position: relative; padding-left: 30px; font-size: 1rem; line-height: 1.55; }
.price-card ul li::before {
  content: ""; position: absolute; left: 0; top: .4em;
  width: 16px; height: 16px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238F5620' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / contain no-repeat;
}
.price-note { font-size: .91rem; color: var(--ink-muted); line-height: 1.65; margin-top: 24px; }
@media (max-width: 760px) { .pricing { grid-template-columns: 1fr; } }

/* ---------- Testimonios en video ---------- */
/* ---------- Carrusel de testimonios ----------
   Fila única, arrastrable, con bucle infinito: la lista se duplica y al llegar
   al final se salta al mismo punto del clon sin animación, así el usuario no
   percibe el corte. Las tarjetas de los extremos se difuminan con una máscara
   para sugerir que hay más a los lados. */
.videos-carrusel { position: relative; }
.videos {
  display: flex;
  gap: 18px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  padding: 4px 0 10px;
  cursor: grab;
  scroll-behavior: smooth;
}
.videos::-webkit-scrollbar { display: none; }
.videos.is-dragging { cursor: grabbing; scroll-behavior: auto; }
.videos.is-dragging * { pointer-events: none; }
.video-card { flex: 0 0 clamp(180px, 22vw, 250px); }

/* Flechas */
.carrusel-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 46px; height: 46px; border: 0; border-radius: 50%;
  background: var(--paper); color: var(--ink);
  display: grid; place-items: center; cursor: pointer;
  box-shadow: var(--shadow-soft);
  transition: background-color .2s ease, transform .2s ease;
}
.carrusel-nav:hover { background: var(--sand); transform: translateY(-50%) scale(1.06); }
.carrusel-nav svg { width: 18px; height: 18px; }
.carrusel-nav--prev { left: -10px; }
.carrusel-nav--next { right: -10px; }
@media (max-width: 700px) { .carrusel-nav { display: none; } }
@media (prefers-reduced-motion: reduce) { .videos { scroll-behavior: auto; } }

.video-card { background: var(--paper); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-soft); }
.video-card video {
  width: 100%;
  /* Los testimonios están grabados en vertical 9:16 (formato de Reels).
     Forzarlos a 1/1 recortaba casi la mitad de la imagen. */
  aspect-ratio: 9 / 16;
  object-fit: cover;
  background: var(--sand); display: block;
}
.video-card__body { padding: 20px 24px 24px; }
.video-card__body b { display: block; font-family: var(--font-head); font-weight: 500; color: var(--ink); font-size: 1.06rem; }
.video-card__body span { font-size: .89rem; color: var(--ink-muted); }


/* ---------- Citas ---------- */
.quote {
  background: var(--paper);
  border-radius: var(--r-lg);
  padding: 34px 36px;
  box-shadow: var(--shadow-soft);
  position: relative;
}
.quote::before {
  content: "\201C";
  font-family: var(--font-head);
  font-size: 4.6rem;
  line-height: 1;
  color: var(--sage-pale);
  position: absolute;
  top: 18px; left: 26px;
}
.quote p {
  position: relative;
  font-size: 1.06rem;
  line-height: 1.7;
  color: var(--ink);
  margin-bottom: 1.2rem;
}
.quote cite { font-style: normal; font-family: var(--font-head); font-weight: 500; color: var(--sage-deep); font-size: 1.03rem; }
.quote cite span { display: block; font-weight: 300; font-size: .89rem; color: var(--ink-muted); font-family: var(--font-body); margin-top: 2px; }

/* ---------- FAQ ---------- */
/* ---------- Acordeón de preguntas frecuentes ----------
   Lenguaje shadcn/21st.dev: sin tarjetas flotantes ni sombras, sólo filetes de
   separación, disparador a todo lo ancho y un chevron que gira. La apertura se
   anima desde landing.js: <details> cambia el display al abrir, así que una
   transición en CSS puro no llega a ejecutarse. */
.faq {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--sand-line);
}
.faq details {
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  border-bottom: 1px solid var(--sand-line);
}
.faq summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: flex-start;
  gap: 20px;
  padding: 24px 4px;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: clamp(1.02rem, 1.5vw, 1.14rem);
  line-height: 1.45;
  color: var(--ink);
  transition: color .2s ease;
}
.faq summary:hover { color: var(--sage-deep); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary:focus-visible {
  outline: 2px solid var(--sage);
  outline-offset: 4px;
  border-radius: var(--r-sm);
}

/* El chevron va en un chip circular, como el trigger del acordeón de shadcn */
.faq summary::after {
  content: "";
  flex: 0 0 auto;
  margin-left: auto;
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid var(--sand-line);
  background: var(--paper)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238F5620' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E")
    center / 13px no-repeat;
  transition: transform .32s cubic-bezier(.16, 1, .3, 1), border-color .2s ease, background-color .2s ease;
}
.faq summary:hover::after { border-color: var(--sage); background-color: var(--sage-pale); }
.faq details[open] summary::after { transform: rotate(180deg); }

.faq__body {
  overflow: hidden;                       /* el alto lo anima el JS */
  padding: 0 54px 4px 4px;
}
.faq__body p { color: var(--ink-soft); }
.faq__body p:last-child, .faq__body ul:last-child { margin-bottom: 26px; }

@media (max-width: 560px) {
  .faq summary { padding: 20px 2px; gap: 14px; font-size: 1rem; }
  .faq summary::after { width: 26px; height: 26px; background-size: 12px; }
  .faq__body { padding-right: 40px; }
}

/* ---------- CTA final ---------- */
.cta-final { background: var(--sage-deep); color: #F0DCB8; text-align: center; }
.cta-final h2 { color: #FDFBF7; max-width: 15em; margin-inline: auto; }
.cta-final .lead { color: #BACCBC; max-width: 38em; margin-inline: auto; margin-bottom: 2rem; }
.cta-final .btn-row { justify-content: center; }
/* Sobre fondo salvia, el botón principal se invierte para conservar contraste */
.cta-final .btn--primary,
.section--deep .btn--primary { background: #FDFBF7; color: var(--sage-deep); }
.cta-final .btn--primary:hover,
.section--deep .btn--primary:hover { background: #fff; }
.cta-final .btn--ghost,
.section--deep .btn--ghost { color: #EAF0EA; border-color: rgba(255,255,255,.34); }
.cta-final .btn--ghost:hover,
.section--deep .btn--ghost:hover { background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.6); }

/* ---------- Consultorio ---------- */
.office { display: grid; grid-template-columns: .92fr 1.08fr; gap: clamp(32px, 4.5vw, 60px); align-items: center; }
/* El mapa ocupa el lugar que tenían las fotos del consultorio. Lleva alto
   explícito, no porcentaje: el iframe necesita apoyarse en un alto definido o
   se queda plano dentro de una columna de rejilla. */
.office__mapa {
  height: clamp(340px, 46vh, 520px);
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--sand-line);
  box-shadow: var(--shadow-soft);
  background: var(--sand);
}
.office__mapa iframe { display: block; width: 100%; height: 100%; border: 0; }
@media (max-width: 900px) { .office__mapa { height: clamp(280px, 42vh, 380px); } }
.office dl { display: grid; grid-template-columns: auto 1fr; gap: 15px 24px; margin: 0 0 2rem; font-size: 1.02rem; }
.office dt { font-size: .82rem; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-muted); padding-top: .42em; }
.office dd { margin: 0; color: var(--ink); line-height: 1.6; }
@media (max-width: 900px) { .office { grid-template-columns: 1fr; } }

/* ---------- Aviso ---------- */
.disclaimer {
  background: var(--sand);
  border-radius: var(--r-md);
  padding: 24px 28px;
  font-size: .95rem;
  color: var(--ink-soft);
  line-height: 1.68;
}
.disclaimer p:last-child { margin-bottom: 0; }

/* ---------- Footer ---------- */
.footer { background: var(--paper); color: var(--ink); padding: 62px 0 38px; font-size: .97rem; }
.footer a { color: var(--ink); }
.footer a:hover { color: var(--clay); }
.footer__grid { display: grid; grid-template-columns: 1.3fr 1fr 1fr; gap: 40px; margin-bottom: 40px; }
/* En el pie hay sitio de sobra, así que va el logotipo COMPLETO —símbolo,
   nombre y bajada— y a su color. El original lo blanqueaba con
   `brightness(0) invert(1)` porque el suyo era monocromo; éste es cobre sobre
   hueso y blanquearlo lo convierte en una mancha. */
.footer__logo { height: 96px; width: auto; margin-bottom: 18px; }
.footer__titulo {
  font-family: var(--font-head); color: var(--ink);
  font-size: 1.05rem; font-weight: 500; margin: 0 0 15px;
}
.footer ul { list-style: none; padding: 0; margin: 0; }
.footer li { margin-bottom: 10px; line-height: 1.5; }

/* Los enlaces del pie medían 19 px de alto. Aquí no aplica la excepción de
   «enlace dentro de una frase»: son una lista de destinos, uno por renglón, y
   el dedo tiene que acertar en uno de ellos. Se les da la caja de 44 px sin
   moverlos de sitio: crecen hacia arriba y hacia abajo desde el mismo renglón,
   y el margen inferior de la lista se compensa para que la columna no se
   estire. */
.footer li:has(> a) { margin-bottom: 0; }
.footer li > a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.footer__bottom {
  border-top: 1px solid rgba(23,20,15,.12);
  padding-top: 24px;
  display: flex; flex-wrap: wrap; gap: 12px 28px; justify-content: space-between;
  font-size: .88rem; color: var(--ink);
}
@media (max-width: 800px) { .footer__grid { grid-template-columns: 1fr; gap: 30px; } }

/* ---------- WhatsApp flotante ---------- */
.wa-float {
  position: fixed;
  right: 22px; bottom: 22px;
  z-index: 70;
  width: 54px; height: 54px;
  border-radius: 50%;
  /* Verde de marca de WhatsApp, a petición del cliente (y como el mock): el
     flotante se lee como «esto ES WhatsApp», no como un botón más del sitio.
     El glifo blanco sobre este verde es el uso canónico de la propia marca. */
  background: #25D366;
  display: grid; place-items: center;
  box-shadow: 0 6px 20px rgba(29, 170, 97, .35);
  transition: background-color .2s ease, transform .2s ease;
}
.wa-float:hover { background: #1DAA61; transform: scale(1.05); }
.wa-float svg { width: 27px; height: 27px; fill: #FDFBF7; }

/* ---------- Barra CTA móvil ---------- */
.mobile-cta {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0;
  z-index: 65;
  background: rgba(250, 247, 242, .97);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--sand-line);
  padding: 11px 14px calc(11px + env(safe-area-inset-bottom));
  gap: 10px;
}
.mobile-cta .btn { flex: 1; padding: .95em 1em; font-size: .97rem; }
/* En la barra, WhatsApp va sólo con su icono: la palabra sobra cuando el
   símbolo es de los más reconocibles que hay, y así el botón deja de competir
   por espacio con «Llamar».

   Verde con el icono en blanco. El color va escrito aquí y no se hereda de
   .btn--primary a propósito: existe una clase .btn--wa con el estilo claro de
   WhatsApp, declarada después, y si este botón la llevara —o alguien se la
   pusiera mañana— se volvería blanco sin que nada avise. Blanco sobre el
   verde de marca da 5,8:1. */
.mobile-cta__wa {
  background: var(--sage);
  color: var(--paper);
  border-color: transparent;
}
.mobile-cta__wa svg { width: 23px; height: 23px; fill: currentColor; display: block; }

@media (max-width: 700px) {
  .mobile-cta { display: flex; }
  body { padding-bottom: 80px; }
  /* El banner de cookies caía ENCIMA de la barra fija: los taps al WhatsApp
     y a Agendar los comía el banner — el «no es clickeable» de móvil. Se alza
     para que la barra quede siempre libre por debajo. */
  .cookies { bottom: calc(96px + env(safe-area-inset-bottom)); }
  /* En teléfono el WhatsApp vive DENTRO de la barra fija (botón verde, entre
     Agendar y Llamar): siempre a la vista y al alcance del pulgar. El
     flotante se esconde para no duplicarlo un centímetro más arriba. */
  .wa-float { display: none; }
  .mobile-cta .mobile-cta__wa {
    flex: 0 0 54px;
    display: grid; place-items: center;
    padding: 0; min-height: 44px;
    background: #25D366; border-color: #25D366;
  }
  .mobile-cta .mobile-cta__wa:hover { background: #1DAA61; }
  .mobile-cta .mobile-cta__wa svg { width: 24px; height: 24px; fill: #fff; }
}

/* ---------- Accesibilidad ---------- */
:focus-visible { outline: 3px solid var(--sage); outline-offset: 3px; border-radius: 6px; }
.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;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* El pulso del botón se exceptúa más abajo, por decisión del cliente.
     [data-reveal] también se exceptúa: bajo esta preferencia la entrada pierde
     el desplazamiento y queda como fundido puro, que no produce el malestar
     vestibular que la preferencia busca evitar. Sin la excepción, esta regla
     dejaba la transición en .01ms y la aparición era un salto seco. */
  *:not(.play-cta__disc):not([data-reveal]):not(.faq__body):not(.proceso__panel):not(.modal__panel):not(.banco__check), *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  /* El sello del titular también se exceptúa: es un elemento de 1em que crece
     en su sitio, sin desplazar nada a su alrededor. Se acorta a la mitad en
     vez de suprimirse, que es lo que se viene haciendo en el resto. */
  .banco__check { transition-duration: .34s, .2s !important; }
  /* El panel del modal también se exceptúa: nace en el sitio y el tamaño del
     elemento que lo abrió y crece hasta su posición final. Es un movimiento
     corto y localizado, no un desplazamiento de página, y sin él el vídeo
     aparece de golpe a pantalla completa —que es más brusco, no menos. Se
     acorta a un tercio en vez de suprimirse. */
  .modal__panel { transition-duration: .26s !important; }
}

/* ==========================================================================
   Hero: botón de play, reseñas y modales
   ========================================================================== */

/* ---------- Titular + botón de play ---------- */
.hero__headline { display: flex; align-items: flex-end; gap: clamp(18px, 2vw, 30px); flex-wrap: wrap; }
.hero__headline h2 { margin: 0; }
/* EN ESCRITORIO EL TEXTO SE ESTRECHA PARA DEJARLE SITIO AL DOCTOR.
   Con la figura centrada y sin atenuar, la columna izquierda no puede pasar de
   donde empieza su hombro. --hero-texto es ese tope, y el botón de reproducir
   deja de ir en la misma línea que el titular —ahí caía justo sobre él— y baja
   debajo, alineado a la izquierda.

   Los tres bloques de la columna comparten el mismo tope para que el borde
   derecho del texto quede recto y la separación con la figura se lea como
   aire, no como un choque. */
@media (min-width: 901px) {
  /* Con la figura a la derecha (68%), el texto puede crecer hasta ~34vw sin
     tocarla: el borde izquierdo de la figura queda medido en el bloque de
     .hero__figura. */
  .hero__grid > div:first-child { --hero-texto: clamp(360px, 36vw, 600px); }
  .hero__h1,
  .hero__headline { max-width: var(--hero-texto); }
  .hero__headline { flex-wrap: wrap; }
  .hero__headline h2 { max-width: none; }
}

.play-cta {
  display: inline-flex; align-items: center; gap: 13px;
  background: none; border: 0; padding: 0; cursor: pointer;
  color: #fff; font-family: var(--font-body); text-align: left;
  margin-bottom: .4rem;   /* solo móvil; en escritorio lo pisa el cálculo de abajo */
}
/* Disco de play traído del sitio en producción del doctor. Sus clases de
   Tailwind, traducidas una a una:
     h-14 w-14            -> 56×56
     rounded-full         -> border-radius: 50%
     border-white/35      -> 1px solid rgba(255,255,255,.35)
     bg-ink/30            -> la tinta del sistema al 30%: rgba(23,20,15,.30)
     text-paper           -> el trazo del triángulo hereda #FBF9F5
     backdrop-blur-md     -> blur(12px)
     h-7 w-7 (el svg)     -> 28×28
   Su marcado trae además `tabindex="0"` en un <span aria-hidden>, y eso NO se
   copia: es un nodo enfocable oculto al lector de pantalla, así que el
   tabulador se para en algo que no se anuncia. Aquí el disco vive dentro de un
   <button> de verdad, que ya es el que recibe el foco. */
.play-cta__disc {
  position: relative; flex: none;
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(23, 20, 15, .30);
  border: 1px solid rgba(255, 255, 255, .35);
  backdrop-filter: blur(12px);
  color: #FBF9F5;
  transition: background-color .22s ease, transform .22s ease;
}
.play-cta__disc svg {
  width: 28px; height: 28px; fill: currentColor;
}
/* Pulso cada 3s: dos anillos concéntricos que crecen desde el borde del disco
   y se desvanecen. El segundo va retrasado 0.6s para que se lea como onda
   continua y no como un parpadeo. El disco en sí no se mueve. */
.play-cta__disc::before,
.play-cta__disc::after {
  content: ""; position: absolute; inset: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(255,255,255,.45);
  animation: playPulso 3s cubic-bezier(.22, .61, .36, 1) infinite;
  pointer-events: none;
}
.play-cta__disc::after { animation-delay: .6s; }

@keyframes playPulso {
  0%   { transform: scale(1);    opacity: .85; border-width: 2px; }
  65%  { transform: scale(2.15); opacity: 0;   border-width: .5px; }
  100% { transform: scale(2.15); opacity: 0;   border-width: .5px; }
}

/* Al pasar el ratón se detiene: ya tiene la atención del visitante */
.play-cta:hover .play-cta__disc::before,
.play-cta:hover .play-cta__disc::after { animation-play-state: paused; }
.play-cta:hover .play-cta__disc { background: rgba(255,255,255,.28); transform: scale(1.05); }
.play-cta__label b { display: block; font-size: .95rem; font-weight: 500; line-height: 1.3; }
.play-cta__label span { font-size: .8rem; color: rgba(255,255,255,.72); }
/* El original eximía los anillos de prefers-reduced-motion por decisión del
   cliente DE AQUEL SITIO. Aquí nadie tomó esa decisión, así que se respeta la
   preferencia: con movimiento reducido los anillos se quedan quietos como un
   aro estático — el botón no pierde presencia, pierde el latido. Si este
   cliente pide el pulso de vuelta, se restaura el bloque del original. */
@media (prefers-reduced-motion: reduce) {
  .play-cta__disc::before,
  .play-cta__disc::after {
    animation: none !important;
    opacity: .5;
    transform: scale(1.28);
  }
  .play-cta__disc::after { content: none; }
}
@media (max-width: 560px) {
  .play-cta__disc { width: 46px; height: 46px; }
  .play-cta__disc svg { width: 16px; height: 16px; }
}

/* ---------- Reseñas de Google sobre la foto ---------- */
/* El tope de 640 era el del sitio original, cuando el hero no tenía figura
   recortada. Ahora manda --hero-texto, que lo fija el bloque del hero de más
   arriba; los 640 se quedan de respaldo para cuando esa variable no existe. */
.hero__reviews { margin-top: clamp(24px, 3vw, 34px); max-width: var(--hero-texto, 640px); }
.hero__reviews iframe { display: block; width: 100%; height: 230px; border: 0; overflow: hidden; }
@media (max-width: 900px) { .hero__reviews { max-width: none; } }

/* ---------- Resumen de reseñas del hero, sólo en móvil ----------
   El widget de reseñas ocupa 230px: en una pantalla de teléfono se come el
   hero entero y empuja el titular fuera de vista. Ahí se cambia por la píldora
   de resumen —estrellas, número y logotipo—, que da la misma señal de confianza
   en 40px. La cita completa sigue estando, más abajo, en el muro de reseñas. */
.hero__resumen { display: none; }
@media (max-width: 700px) {
  .hero__reviews iframe { display: none; }
  .hero__resumen {
    display: inline-flex; align-items: center; gap: 9px;
    min-height: 44px;          /* objetivo táctil: es un enlace a la ficha de Google */
    padding: 9px 15px;
    background: rgba(255, 255, 255, .14);
    border: 1px solid rgba(255, 255, 255, .24);
    backdrop-filter: blur(10px);
    border-radius: 100px;
    color: #fff; text-decoration: none;
    font-size: .9rem; line-height: 1;
  }
  .hero__resumen .resena__estrellas { margin: 0; gap: 1px; }
  .hero__resumen .resena__estrellas svg { width: 13px; height: 13px; }
  .hero__resumen-txt b { font-weight: 600; }
  .hero__resumen-g { width: 15px; height: 15px; flex: 0 0 auto; }
}

/* ---------- Modal genérico ---------- */
body.is-locked { overflow: hidden; }
/* Sin esto, al llegar al final del calendario el gesto sigue de largo y arrastra
   la página de detrás (o dispara el «pull to refresh» del navegador). */
.modal, .modal__panel, #cal-mount { overscroll-behavior: contain; }

.modal {
  position: fixed; inset: 0; z-index: 200;
  /* En iOS, un `inset: 0` fijo se mide contra la ventana SIN las barras del
     navegador, así que la caja llega por debajo de la barra inferior de Chrome
     o de Safari. Y como el panel va centrado en esa caja, se desplaza hacia
     abajo y lo último que trae —el botón «Continuar» del calendario, la línea
     de tiempo del vídeo— queda tapado.

     `100svh` es el alto de la ventana CON las barras desplegadas, es decir, lo
     que de verdad se ve siempre. Con top, height y bottom declarados a la vez,
     CSS descarta el bottom y manda el height, que es justo lo que se busca.
     Los navegadores sin svh se quedan con el inset de arriba. */
  height: 100svh;
  display: grid; place-items: center;
  padding: 24px;
  opacity: 0;
  /* Entrada y salida con curvas distintas: al abrir conviene una expo-out
     larga, que arranca rápido y frena suave; al cerrar, algo corto y directo,
     porque una salida lenta se percibe como que la interfaz no responde. */
  transition: opacity .34s cubic-bezier(.16, 1, .3, 1);
}
.modal:not(.is-open) { transition: opacity .18s cubic-bezier(.4, 0, 1, 1); }
.modal[hidden] { display: none; }
.modal.is-open { opacity: 1; }
.modal__backdrop { position: absolute; inset: 0; background: rgba(13, 22, 31, .74); backdrop-filter: blur(6px); }
.modal__panel {
  position: relative; z-index: 2;
  width: 100%; max-width: 560px;
  /* Misma razón que en .modal: el tope se mide contra lo que se ve, no contra
     la ventana completa. La línea vh queda de respaldo para lo que no conozca
     svh; el orden importa, gana la última que el navegador entienda. */
  max-height: 92vh;
  max-height: 92svh;
  overflow: auto; -webkit-overflow-scrolling: touch;
  /* El panel no va en blanco a propósito. Los campos del formulario son
     blancos con un borde de 1px muy tenue; sobre un panel blanco el único
     límite de cada campo sería ese borde. Con el panel un tono por debajo los
     campos se recortan solos, que es como funcionaba con el crema. */
  background: var(--cream-deep); border-radius: var(--r-lg);
  box-shadow: 0 30px 90px rgba(13, 22, 31, .42);
  transform: translateY(28px) scale(.94);
  opacity: 0;
  transition:
    transform .52s cubic-bezier(.16, 1, .3, 1),
    opacity   .30s cubic-bezier(.16, 1, .3, 1);
}
.modal.is-open .modal__panel { transform: none; opacity: 1; }
.modal:not(.is-open) .modal__panel {
  transform: translateY(10px) scale(.98);
  transition:
    transform .2s cubic-bezier(.4, 0, 1, 1),
    opacity   .16s linear;
}

/* El velo entra un poco antes que el panel, así el fondo se asienta primero */
.modal__backdrop { opacity: 0; transition: opacity .3s cubic-bezier(.16, 1, .3, 1); }
.modal.is-open .modal__backdrop { opacity: 1; }
.modal__close {
  position: absolute; top: 14px; right: 14px; z-index: 6;
  width: 42px; height: 42px; border: 0; border-radius: 50%;
  background: rgba(23, 20, 15, .09); color: var(--ink);
  display: grid; place-items: center; cursor: pointer;
  transition: background-color .2s ease;
}
.modal__close:hover { background: rgba(23, 20, 15, .18); }
.modal__close svg { width: 18px; height: 18px; }
.modal__head { padding: 30px 32px 0; }
.modal__head h2 { font-size: 1.5rem; margin: 0 0 .3em; }
.modal__head p { font-size: .98rem; color: var(--ink-muted); margin: 0; }
.modal__body {
  /* Sin cabecera, hace falta hueco para que el botón de cerrar (42px a 14px
     del borde) no quede encima del calendario. */
  padding: 64px 26px 26px;
}

/* Marcador de carga mientras el calendario aún no responde */
#cal-mount { min-height: 400px; position: relative; }
#cal-mount::before {
  content: "Cargando agenda…";
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--ink-muted); font-size: .95rem;
}
#cal-mount.is-ready::before { content: none; }

/* La salida de emergencia del calendario (ver landing.js): pila de botones
   centrada donde iba el iframe. Si el calendario acaba llegando tarde,
   .is-ready la retira para que no convivan los dos. */
#cal-mount .cal-salida {
  position: relative; z-index: 2;
  display: grid; gap: 12px; justify-items: stretch;
  padding: 46px 26px 30px;
  text-align: center;
}
/* El panel del modal es transparente a propósito (el calendario trae su
   propio fondo). La salida de emergencia no trae ninguno: se le da la
   tarjeta de papel aquí, o los botones flotan sobre el velo. */
#modal-cita #cal-mount.con-salida {
  background: var(--cream);
  height: auto; min-height: 0;
}
#cal-mount .cal-salida p { margin: 0 0 6px; color: var(--ink-soft); }
#cal-mount.con-salida::before { content: none; }
#cal-mount.is-ready .cal-salida { display: none; }
#cal-mount iframe { position: relative; z-index: 1; }

/* ---------- Modal de video ---------- */
.modal__panel--video {
  max-width: min(420px, 92vw);
  background: transparent; box-shadow: none;
  overflow: visible; border-radius: 0;
}

/* La cruz de este modal cae directamente sobre el video, no sobre el papel
   crema de los demás: la tinta oscura y el fondo casi transparente que sirven
   allí aquí desaparecen. Se invierte a blanco sobre un disco oscuro, que es lo
   único que aguanta un fotograma cualquiera. En el peor caso posible —un
   fotograma completamente blanco— el velo deja el fondo en gris medio y la
   cruz mantiene 4,74:1, por encima del 3:1 que pide un elemento no textual. */
#modal-video .modal__close {
  color: #fff;
  background: rgba(0, 0, 0, .55);
  backdrop-filter: blur(4px);
}
#modal-video .modal__close:hover { background: rgba(0, 0, 0, .72); }

/* ---------- Llamada a la acción dentro del vídeo ----------
   Aparece sobre el minuto 1:24, cuando el doctor termina de explicar por qué
   conviene una segunda opinión. Va por encima de la barra del reproductor
   —que ocupa los 90px de abajo cuando se muestra— para no taparle los
   controles ni que se tapen entre ellos. */
.video-cta {
  position: absolute; z-index: 8;
  left: 50%; bottom: 96px; transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--font-body); font-size: .97rem; font-weight: 500;
  color: var(--paper); background: var(--sage);
  border: 0; border-radius: 100px;
  padding: .92em 1.7em; cursor: pointer;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .45);
  animation: ctaVideoEntra .42s cubic-bezier(.16, 1, .3, 1);
}
.video-cta:hover { background: var(--sage-deep); }
.video-cta[hidden] { display: none; }
@keyframes ctaVideoEntra {
  from { opacity: 0; transform: translate(-50%, 14px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
@media (max-width: 700px) { .video-cta { bottom: 86px; font-size: .93rem; } }

/* ==========================================================================
   Reproductor de video
   Diseño portado del componente de referencia (React/Tailwind) a CSS propio:
   disco central translúcido con desenfoque, barra inferior sobre degradado,
   y controles que se ocultan solos mientras se reproduce.
   ========================================================================== */
.rp {
  position: relative;
  width: 100%;
  background: #000;
  border-radius: var(--r-lg);
  overflow: hidden;
  line-height: 0;
}
.rp:focus-visible { outline: 3px solid var(--sage); outline-offset: 3px; }
.rp video { width: 100%; height: 100%; display: block; cursor: pointer; }

/* Disco central */
.rp__centro {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  pointer-events: none;
  opacity: 0; transition: opacity .3s ease;
}
.rp.is-paused .rp__centro,
.rp.is-hover  .rp__centro { opacity: 1; }
.rp__disco {
  width: 64px; height: 64px; border-radius: 50%;
  background: rgba(255,255,255,.2);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.3);
  display: grid; place-items: center;
  color: #fff; cursor: pointer; pointer-events: auto;
  transition: background-color .2s ease, transform .2s ease;
}
.rp__disco:hover { background: rgba(255,255,255,.3); transform: scale(1.05); }
.rp__disco svg { width: 24px; height: 24px; fill: currentColor; }

/* Barra inferior */
.rp__barra {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: linear-gradient(to top, rgba(0,0,0,.8), transparent);
  padding: 34px 14px 12px;
  opacity: 0; pointer-events: none;
  transition: opacity .3s ease;
  line-height: 1;
}
.rp.is-paused .rp__barra,
.rp.is-hover  .rp__barra { opacity: 1; pointer-events: auto; }

.rp__fila { display: flex; align-items: center; gap: 8px; }
.rp__fila + .rp__fila { margin-top: 10px; justify-content: space-between; }
.rp__grupo { display: flex; align-items: center; gap: 2px; }
.rp__tiempo {
  color: #fff; font-size: .72rem;
  font-variant-numeric: tabular-nums;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  min-width: 34px; text-align: center;
}

/* Barras de progreso y volumen: un range nativo repintado */
.rp__range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 4px; border-radius: 4px;
  background: rgba(255,255,255,.3);
  /* Se quita el contorno nativo porque sobre el video se pinta como un
     rectángulo gris ilegible, PERO se repone con un aro propio: sin él, quien
     navega con teclado no sabe si está sobre la barra o sobre el botón. */
  cursor: pointer; outline: none;
}
.rp__range:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
  border-radius: 4px;
}
.rp__range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 12px; height: 12px; border-radius: 50%;
  background: #fff; cursor: pointer;
  transition: transform .2s ease;
}
.rp__range:hover::-webkit-slider-thumb { transform: scale(1.25); }
.rp__range::-moz-range-thumb {
  width: 12px; height: 12px; border: 0; border-radius: 50%; background: #fff;
}
.rp__progreso { flex: 1; }

.rp__btn {
  width: 32px; height: 32px; flex: none;
  border: 0; border-radius: 6px;
  background: none; color: #fff;
  display: grid; place-items: center; cursor: pointer;
  transition: background-color .18s ease;
}
.rp__btn:hover { background: rgba(255,255,255,.2); }
.rp__btn svg { width: 16px; height: 16px; }

/* En pantallas táctiles los controles del reproductor suben a 44px: a 32 el
   dedo falla, y el pulgar tapa el botón antes de acertarlo. En ratón se quedan
   a 32, que es donde encajan con la barra. */
@media (pointer: coarse) {
  .rp__btn { width: 44px; height: 44px; }
  /* La barra se ve igual de fina —6 px— pero se toca en una franja de 44: el
     relleno vertical va en transparente y el `background-clip: content-box`
     impide que el color lo pinte. El margen negativo devuelve la barra a su
     sitio, así que la botonera no se estira ni un píxel. */
  .rp__range {
    height: 6px;
    padding-block: 19px;
    margin-block: -19px;
    background-clip: content-box;
    box-sizing: content-box;
  }
}


/* El volumen se despliega al pasar por encima, como en la referencia */
.rp__vol { display: flex; align-items: center; gap: 6px; }
.rp__vol .rp__range { width: 0; transition: width .2s ease; }
.rp__vol:hover .rp__range, .rp__vol:focus-within .rp__range { width: 68px; }

/* En reproductores estrechos (tarjetas del carrusel) solo caben lo esencial */
.rp--compacto .rp__btn--salto,
.rp--compacto .rp__btn--stop,
.rp--compacto .rp__vol { display: none; }
.rp--compacto .rp__barra { padding: 26px 10px 9px; }
.rp--compacto .rp__disco { width: 48px; height: 48px; }
.rp--compacto .rp__disco svg { width: 18px; height: 18px; }

@media (max-width: 620px) {
  .modal { padding: 0; }
  /* Aquí estaba el fallo de verdad en teléfono: estos dos `100vh` pisaban el
     tope de arriba y devolvían la medida sin las barras del navegador. El
     panel llegaba por debajo de la barra inferior de Chrome y se comía lo
     último de cada modal: el botón «Continuar» del calendario y la línea de
     tiempo del reproductor. Se repiten en vh y svh —el orden importa, gana la
     última que el navegador entienda— para no dejar tirado a lo que no
     conozca svh. */
  .modal__panel { max-width: none; border-radius: 0; max-height: 100vh; max-height: 100svh; }

  /* El formulario no: es contenido corto y a sangre parece una pantalla del
     sistema, no algo que se pueda cerrar. Se queda como tarjeta con esquinas
     redondeadas y aire alrededor, que además deja ver el fondo y hace evidente
     que se sale tocando fuera. */
  #modal-lead { padding: 18px; }
  #modal-lead .modal__panel {
    border-radius: var(--r-lg);
    max-height: calc(100svh - 36px);
  }
  .modal__panel--video {
    display: grid; place-items: center; padding: 0 12px;
    height: 100vh;
    height: 100svh;
  }
  .vp { width: 100%; border-radius: var(--r-md); }
  /* La cruz de salida queda arriba a la derecha de la pantalla */
  .modal__panel--video .modal__close {
    top: calc(14px + env(safe-area-inset-top)); right: 14px;
    width: 44px; height: 44px;
  }

  /* ---------- El calendario, a pantalla completa y con scroll propio ----------
     El iframe crecía a lo alto según su contenido: la ficha se pinta primero y
     los horarios llegan después, así que el alto final supera la pantalla y el
     botón «Continuar» acaba por debajo del borde.

     Acotar el panel no bastaba. En iOS, el gesto de arrastre sobre un iframe se
     lo queda el iframe, y como iba con el scroll desactivado no llegaba al
     contenedor de detrás: el botón no sólo no se veía, es que no había forma
     de alcanzarlo.

     Así que en teléfono el iframe ocupa exactamente lo visible y se desplaza
     por dentro. El alto lo manda esta regla, no los mensajes de altura del
     widget, que landing.js ignora a este tamaño. */
  /* Tarjeta CENTRADA en la pantalla (pedido del cliente), no a sangre: el
     contenedor genérico ya centra con place-items, así que basta con que el
     panel no mida 100svh. El alto del calendario se lleva casi todo lo
     visible y deja aire arriba y abajo. */
  #modal-cita { padding: 14px; }
  #modal-cita .modal__panel { height: auto; overflow: visible; }
  #modal-cita .modal__body { height: auto; padding: 0; }
  /* En el celular la tarjeta mide LO QUE MIDA EL WIDGET: la altura la dicta
     el estilo inline que Docplanner manda por postMessage. CON TOPE al alto
     visible: sin él, un calendario más alto que la pantalla se salía y
     quedaba cortado sin forma de alcanzar el faldón (reportado en un
     dispositivo real). Cuando el widget cabe no hay scroll ninguno; cuando
     no cabe, el scroll aparece sólo entonces — el overflow vive en el bloque
     de después de la regla base, que si no la pisaría. */
  #modal-cita #cal-mount { height: auto; min-height: 0; max-height: calc(100svh - 76px); border-radius: var(--r-md); }
  #modal-cita #cal-mount iframe { height: auto; min-height: 480px; }
  #modal-cita .modal__close { top: 10px; right: 10px; transform: none; }
}

/* ==========================================================================
   Sección de segunda opinión (video + carta) y formulario de contacto
   ========================================================================== */
/* La sección ocupa el 80% del alto de pantalla y el vídeo va a sangre por la
   izquierda, sin esquinas redondeadas. El padding vertical se anula: quien
   manda el alto es la propia sección. */
.opinion { background: var(--cream-deep); padding: 0; }
.opinion__grid {
  display: grid;
  grid-template-columns: minmax(300px, .8fr) 1.2fr;
  gap: clamp(32px, 5vw, 68px);
  align-items: stretch;          /* el vídeo estira hasta el alto completo */
  min-height: 80vh;
  min-height: 80svh;
  /* Anula el .wrap para que la columna del vídeo llegue al borde */
  max-width: none;
  padding-inline: 0;
}
.opinion__video {
  position: relative; margin: 0;
  border-radius: 0;              /* a sangre: sin esquinas redondeadas */
  overflow: hidden;
  background: var(--sand); box-shadow: none;
  max-width: none;
  /* Tiene que ser height, no min-height: un porcentaje sobre un alto que sólo
     viene de min-height resuelve a 0, y el vídeo absoluto se quedaba plano.
     Con height definido, el height:100% del vídeo se apoya en 80svh. */
  height: 80vh;
  height: 80svh;
}
/* Aquí ya no hay <video>: es un cartel que abre el modal. El fotograma está
   recortado a 2:3, la misma proporción de la ventana, así que no se pierde
   encuadre al aplicar cover. */
.opinion__abrir {
  display: block; width: 100%; height: 100%;
  margin: 0; padding: 0; border: 0; background: none;
  position: relative; overflow: hidden; cursor: pointer;
}
.opinion__abrir img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Anclado arriba, no al centro: la ventana de esta columna es más ancha que
     el cartel en casi todas las pantallas, así que cover recorta alto. Con el
     50% por defecto la mitad de ese recorte se comía el aire sobre la cabeza. */
  object-position: 50% 18%;
}
.opinion__abrir:focus-visible { outline: 3px solid var(--sage); outline-offset: -3px; }
.opinion__abrir:hover .opinion__play { transform: scale(1.06); }

/* El texto conserva el margen derecho del resto del sitio, para que su borde
   coincida con el de las demás secciones aunque la rejilla vaya a sangre. */
.opinion__texto {
  /* Ritmo vertical comprimido para que el bloque quepa dentro del 80vh en
     portátiles de 900px de alto. En pantallas más altas sobra sitio. */
  padding-block: clamp(34px, 4.4vh, 62px);
  padding-right: max(24px, calc((100vw - var(--wrap)) / 2 + 24px));
  align-self: center;
}
.opinion__texto p { margin-bottom: .92em; }
.opinion__texto h2 { margin-bottom: .42em; }
.opinion__texto .eyebrow { margin-bottom: .7rem; }
.opinion__texto .opinion__firma { margin: 16px 0 4px; }
.opinion__texto .opinion__cargo { margin-bottom: 1.15rem; }
.opinion__play {
  position: absolute; inset: 0; margin: auto;
  width: 74px; height: 74px; border: 0; border-radius: 50%;
  background: rgba(255,255,255,.92); display: grid; place-items: center; cursor: pointer;
  transition: opacity .2s ease, transform .2s ease;
}
.opinion__play svg { width: 26px; height: 26px; fill: var(--pill); transform: translateX(-1.97px); }
.opinion__play:hover { transform: scale(1.06); }
.opinion__video.is-playing .opinion__play { opacity: 0; pointer-events: none; }

.opinion__firma {
  display: block; width: 190px; height: auto; margin: 28px 0 6px;
  /* Ya es un SVG vectorial con transparencia real, así que no hace falta el
     mix-blend-mode: multiply que antes disimulaba el fondo blanco del PNG.
     Al ser vector se mantiene nítida en pantallas 2x y 3x. */
  opacity: .88;
}
.opinion__cargo { font-size: .92rem; color: var(--ink-muted); margin: 0 0 1.9rem; }
@media (max-width: 900px) {
  /* Apilado: el sangrado y el 80vh dejan de tener sentido en vertical */
  .opinion__grid { grid-template-columns: 1fr; min-height: 0; gap: 0; }
  .opinion__video { max-width: none; height: auto; }
  /* Apilado, el cartel marca su propio alto por proporción */
  .opinion__abrir { height: auto; }
  .opinion__abrir img { height: auto; aspect-ratio: 4 / 5; max-height: 70svh; }
  .opinion__texto { padding: clamp(36px, 6vw, 56px) 24px; }
}

/* ---------- Formulario ---------- */
.form-campo { margin-bottom: 18px; }
.form-campo label { display: block; font-size: .93rem; color: var(--ink); margin-bottom: 7px; }
.form-campo input {
  width: 100%; font-family: var(--font-body); font-size: 1.02rem;
  /* Borde propio, no --sand-line. Al pasar el panel a gris neutro el borde
     genérico quedó a 1,16:1 contra el panel, por debajo del 1,33:1 que daba
     sobre el crema. Este tono devuelve el mismo recorte que tenía antes. */
  padding: .85em 1.1em; border: 1.5px solid #D6D6DB; border-radius: var(--r-sm);
  background: var(--paper); color: var(--ink);
}
/* ---------- Bandera del país en el teléfono ----------
   Va como adorno dentro del campo, no como parte del valor: el `+52 ` sigue
   siendo texto editable, así que quien tenga un número de otro país puede
   borrarlo y escribir el suyo, y la normalización de landing.js no cambia.
   `pointer-events: none` para que el toque caiga en el campo y no en la
   bandera, que si no roba el foco en teléfono. */
.form-tel { position: relative; }
.form-tel__bandera {
  position: absolute;
  left: 13px; top: 50%;
  transform: translateY(-50%);
  font-size: 1.12rem;
  line-height: 1;
  pointer-events: none;
}
/* Hueco para la bandera. Sólo en este campo: el resto sigue con su relleno. */
.form-tel input { padding-left: 42px; }

.form-campo input:focus-visible { border-color: var(--sage); outline: none; box-shadow: 0 0 0 3px var(--sage-pale); }
.form-campo input[aria-invalid="true"] { border-color: #B4482F; }
.form-error { display: none; font-size: .87rem; color: #B4482F; margin-top: 6px; }
.form-campo.is-mal .form-error { display: block; }
.form-aviso {
  display: none; margin-top: 14px; padding: 12px 16px; border-radius: var(--r-sm);
  background: #F7E6E1; color: #8A3520; font-size: .92rem;
}
.form-aviso.is-visible { display: block; }
/* El enlace a WhatsApp del aviso de error. Subrayado y en el mismo tono del
   texto: sobre el fondo rosa del aviso, el verde de marca queda en 2,4:1. */
.form-aviso a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
.form-legal { font-size: .84rem; color: var(--ink-muted); margin: 14px 0 0; line-height: 1.55; }
.btn[aria-busy="true"] { opacity: .6; pointer-events: none; }

/* ═══════════════════════════════════════════════════════════════
   PÁGINA LEGAL (aviso de privacidad)
   ═══════════════════════════════════════════════════════════════ */
.navpill--solido { background: var(--cream); }
.legal { padding: 132px 0 96px; }
.legal h1 { font-size: clamp(2rem, 4.4vw, 3rem); margin: 0 0 10px; }
.legal__fecha { color: var(--ink-muted); font-size: .93rem; margin: 0 0 30px; }
.legal h2 {
  font-size: clamp(1.15rem, 2.1vw, 1.42rem);
  margin: 44px 0 12px; padding-top: 26px;
  border-top: 1px solid var(--sand-line);
}
.legal p { color: var(--ink-soft); line-height: 1.72; margin: 0 0 14px; }
.legal ul { color: var(--ink-soft); line-height: 1.72; margin: 0 0 18px; padding-left: 1.15rem; }
.legal li { margin-bottom: 9px; }
.legal strong { color: var(--ink); font-weight: 600; }
.legal a { color: var(--sage); text-decoration: underline; text-underline-offset: 3px; }
.legal a:hover { color: var(--sage-deep); }
/* El consentimiento expreso para datos de salud tiene que destacarse
   visualmente: es el punto que la LFPDPPP exige que el titular no pase por alto. */
.legal__destacado {
  background: var(--sage-pale); border-left: 3px solid var(--sage);
  padding: 16px 20px; border-radius: 0 var(--r-sm) var(--r-sm) 0;
  margin: 0 0 16px !important;
}
.legal__cierre {
  margin-top: 52px; padding-top: 30px; border-top: 1px solid var(--sand-line);
}
.legal__cierre .btn { margin-top: 8px; }

/* ═══════════════════════════════════════════════════════════════
   FOOTER · redes, COFEPRIS y firma +Pacientes
   ═══════════════════════════════════════════════════════════════ */
.footer__social { display: flex; gap: 10px; margin-top: 20px; }
.footer__social a {
  width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid rgba(23, 20, 15, .16);
  color: var(--ink); transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.footer__social a:hover { background: rgba(23, 20, 15, .05); border-color: rgba(23, 20, 15, .32); color: var(--clay); }
.footer__social svg { width: 18px; height: 18px; fill: currentColor; }

.footer__cofepris {
  margin-top: 34px; padding: 15px 18px;
  /* Era punteado mientras el folio estaba pendiente; con el número ya
     publicado pasa a sólido, como pedía la nota del original. */
  border: 1px solid rgba(23, 20, 15, .2); border-radius: var(--r-sm);
  font-size: .86rem; line-height: 1.6; color: var(--ink);
}
.footer__cofepris strong { color: var(--ink); font-weight: 600; }

/* ---------- Otros procedimientos, en el pie ----------
   Las cuatro landings eran callejones sin salida: se entraba desde un anuncio
   y no había forma de llegar a las demás. Aquí no estorban a la conversión
   —quedan por debajo del formulario y del CTA final— y hacen que las páginas
   se sostengan entre sí en vez de competir sueltas. */
.footer__procs { margin-top: 30px; padding-top: 24px; border-top: 1px solid rgba(23, 20, 15, .1); }
.footer__procs-tit {
  display: block; margin-bottom: 12px;
  font-size: .78rem; letter-spacing: .1em; text-transform: uppercase;
  color: rgba(23, 20, 15, .55);
}
.footer__procs-lista { display: flex; flex-wrap: wrap; gap: 10px 12px; }
.footer__procs-lista a {
  padding: 8px 15px; border-radius: 999px;
  border: 1px solid rgba(23, 20, 15, .18);
  font-size: .9rem;
  transition: border-color .2s ease, background-color .2s ease;
}
.footer__procs-lista a:hover { border-color: rgba(23, 20, 15, .4); background: rgba(23, 20, 15, .05); }

.footer__legal { display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 26px; }
/* Mismo motivo que la lista de arriba: son dos controles sueltos, no texto
   corrido. El relleno vertical los lleva a 44 px sin cambiar dónde se leen. */
.footer__legal a,
.footer__legal button { display: inline-flex; align-items: center; min-height: 44px; }
.footer__legal a { text-decoration: underline; text-underline-offset: 3px; }

.footer__marca {
  margin-top: 26px; padding-top: 22px;
  border-top: 1px solid rgba(23, 20, 15, .1);
  display: flex; justify-content: center;
}
.footer__marca a {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: .88rem; color: var(--ink); opacity: .9;
  transition: opacity .2s ease, color .2s ease;
}
.footer__marca a:hover { opacity: 1; color: var(--clay); }
.footer__marca img { width: 20px; height: 20px; display: block; }

/* ═══════════════════════════════════════════════════════════════
   BANNER DE COOKIES
   ═══════════════════════════════════════════════════════════════ */
.cookies {
  position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 90;
  max-width: 640px; margin-inline: auto;
  background: var(--paper); border: 1px solid var(--sand-line);
  border-radius: var(--r-md); box-shadow: var(--shadow-lift);
  padding: 20px 22px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px 18px;
  transform: translateY(140%); opacity: 0;
  transition: transform .5s cubic-bezier(.22, 1, .36, 1), opacity .35s ease;
}
.cookies.is-visible { transform: translateY(0); opacity: 1; }
.cookies p { margin: 0; flex: 1 1 280px; font-size: .9rem; line-height: 1.6; color: var(--ink-soft); }
.cookies a { color: var(--sage); text-decoration: underline; text-underline-offset: 3px; }
.cookies__acciones { display: flex; gap: 10px; flex: 0 0 auto; }
.cookies .btn { padding: 10px 18px; font-size: .88rem; }
@media (max-width: 560px) {
  .cookies { padding: 18px; }
  .cookies__acciones { width: 100%; }
  .cookies__acciones .btn { flex: 1; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .cookies { transition: opacity .2s ease; transform: none; }
}

/* ---------- Panel de preferencias de cookies ----------
   Vive dentro de un .modal normal (#modal-cookies), así hereda el fondo, el
   cierre con Escape y el clic fuera. Sólo cambia lo de dentro. */
.ck { padding: 6px 32px 30px; }
.ck__fila {
  display: flex; align-items: flex-start; gap: 18px;
  padding: 17px 0; border-top: 1px solid var(--sand-line);
  cursor: pointer;
}
.ck__fila:first-child { border-top: 0; }
.ck__fila--fija { cursor: default; }
.ck__texto { flex: 1 1 auto; }
.ck__texto strong { display: block; font-size: 1rem; margin-bottom: .18em; }
.ck__texto span { display: block; font-size: .87rem; line-height: 1.55; color: var(--ink-muted); }
.ck__siempre {
  flex: 0 0 auto; margin-top: 3px;
  font-size: .76rem; letter-spacing: .01em; white-space: nowrap;
  color: var(--sage-deep); background: var(--sage-pale);
  border-radius: 999px; padding: 5px 11px;
}

/* Interruptor. Es un <input type="checkbox"> de verdad: así el teclado, el
   lector de pantalla y el envío del formulario funcionan sin ayuda. */
.ck__sw {
  appearance: none; -webkit-appearance: none;
  flex: 0 0 auto; position: relative; margin: 2px 0 0;
  width: 46px; height: 27px; border: 0; border-radius: 999px;
  background: #D6CFC2; cursor: pointer;
  transition: background-color .22s ease;
}
.ck__sw::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 21px; height: 21px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .28);
  transition: transform .22s cubic-bezier(.3, 1.4, .5, 1);
}
.ck__sw:checked { background: var(--sage); }
.ck__sw:checked::after { transform: translateX(19px); }
.ck__sw:focus-visible { outline: 2px solid var(--sage); outline-offset: 3px; }

.ck__pie { display: flex; gap: 10px; margin-top: 26px; }
.ck__pie .btn { flex: 1 1 0; justify-content: center; }

@media (max-width: 520px) {
  .ck { padding: 6px 22px 24px; }
  .ck__pie { flex-direction: column; }
}

/* Enlace del pie para volver a abrir el panel una vez decidido */
.footer__legal button {
  appearance: none; background: none; border: 0; padding: 0;
  font: inherit; color: inherit; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}

/* ═══════════════════════════════════════════════════════════════
   ASEGURADORAS
   Rejilla de logotipos, cada uno enlazado al sitio de su aseguradora.

   auto-fit + minmax en vez de un número fijo de columnas y media queries:
   la rejilla se reacomoda sola de 6 columnas en escritorio a 2 en un
   teléfono de 375px, y si algún día se añade o se quita una aseguradora no
   hay que tocar ningún breakpoint.

   Los logos van en gris y al 75% de opacidad a propósito: son doce marcas
   ajenas, cada una con su color corporativo, y a todo color compiten con la
   página y entre ellas. Al pasar por encima recuperan su color, que es la
   señal de que la tarjeta es un enlace.
   ═══════════════════════════════════════════════════════════════ */
.aseguradoras {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px;
  margin-top: 34px;
}
.aseguradora {
  display: grid;
  place-items: center;
  min-height: 104px;
  padding: 20px 18px;
  background: var(--paper);
  border: 1px solid var(--sand-line);
  border-radius: var(--r-md);
  transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
}
.aseguradora img {
  max-width: 100%;
  max-height: 34px;
  width: auto;
  object-fit: contain;
  filter: grayscale(1);
  opacity: .75;
  transition: filter .2s ease, opacity .2s ease;
}
.aseguradora:hover {
  border-color: var(--sage);
  box-shadow: var(--shadow-soft);
  transform: translateY(-2px);
}
.aseguradora:hover img { filter: none; opacity: 1; }
/* El foco de teclado tiene que verse igual que el hover: son enlaces. */
.aseguradora:focus-visible img { filter: none; opacity: 1; }

/* (Aquí vivía el bloque .aseguradora--texto, para las siete aseguradoras que
   no tenían archivo de logotipo. Ya lo tienen las dieciocho, así que el bloque
   se retira en vez de quedarse como código muerto.) */

.aseguradoras-nota a {
  display: inline-block;
  padding-block: 13px;
  margin-block: -13px;
}

.aseguradoras-nota {
  margin: 26px auto 0;
  max-width: 62ch;
  text-align: center;
  font-size: .93rem;
  color: var(--ink-muted);
}
.aseguradoras-nota a { text-decoration: underline; text-underline-offset: 3px; }

@media (max-width: 480px) {
  .aseguradoras { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .aseguradora { min-height: 88px; padding: 16px 12px; }
  .aseguradora img { max-height: 28px; }
}

/* ═══════════════════════════════════════════════════════════════
   PRUEBA SOCIAL EXTERNA (Google + Doctoralia) en testimonios
   ═══════════════════════════════════════════════════════════════ */
.prueba-social { margin-top: 54px; }
/* ---------- Muro de reseñas ----------
   Tres columnas equilibradas al generar el HTML, dentro de un contenedor con
   scroll propio. Se reparten en columnas ya montadas y no con column-count:
   las multicolumna fluyen en horizontal al limitar el alto, y aquí hace falta
   que el desbordamiento sea vertical. */
/* Sin scroll propio: se muestran 20 y el resto se cargan por lotes. */
.resenas__pie { display: flex; justify-content: center; margin-top: 26px; }
.resenas__mas[hidden] { display: none; }

/* Las que aún no se han cargado no ocupan sitio */
.resena--oculta { display: none; }

/* Entrada de cada tanda: una a una, con la misma curva del resto del sitio */
.resena--entrando { opacity: 0; transform: translateY(26px); }
.resena--dentro {
  opacity: 1; transform: none;
  transition:
    opacity   .62s cubic-bezier(.16, 1, .3, 1),
    transform .74s cubic-bezier(.16, 1, .3, 1);
  transition-delay: var(--entrada, 0ms);
}
@media (prefers-reduced-motion: reduce) {
  /* Fundido puro, sin desplazamiento */
  .resena--entrando { transform: none; }
  .resena--dentro { transition-duration: .4s !important; transition-delay: var(--entrada, 0ms) !important; }
}
.resenas__cols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: start; }
.resenas__col  { display: grid; gap: 16px; align-content: start; }

.resena {
  background: var(--paper);
  border: 1px solid var(--sand-line);
  border-radius: var(--r-md);
  padding: 20px 22px 22px;
  box-shadow: var(--shadow-soft);
}
.resena__cab { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.resena__avatar {
  width: 38px; height: 38px; flex: 0 0 auto;
  border-radius: 50%; display: grid; place-items: center;
  color: #fff; font-family: var(--font-head); font-weight: 500; font-size: 1.02rem;
}
.resena__nombre { margin: 0; font-family: var(--font-head); font-weight: 500; color: var(--ink); font-size: .98rem; line-height: 1.3; }
.resena__fecha  { margin: 0; font-size: .82rem; color: var(--ink-muted); }
.resena__estrellas { display: inline-flex; gap: 2px; margin-bottom: 10px; }
.resena__estrellas svg { width: 15px; height: 15px; fill: #FFD069; }
.resena__texto { margin: 0; font-size: .96rem; line-height: 1.62; color: var(--ink-soft); }

/* Las reseñas muy largas se recortan y se despliegan al pulsar */
.resena--larga .resena__texto {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 11;
  overflow: hidden;
}
.resena--larga.is-abierta .resena__texto { -webkit-line-clamp: unset; }
.resena__mas {
  margin-top: 10px; padding: 0; border: 0; background: none; cursor: pointer;
  font-family: var(--font-body); font-size: .9rem; color: var(--sage);
  text-decoration: underline; text-underline-offset: 3px;
}
.resena__mas:hover { color: var(--sage-deep); }

@media (max-width: 1000px) { .resenas__cols { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 660px)  {
  .resenas__cols { grid-template-columns: 1fr; }
  /* Aquí había un `max-height` sin `overflow`. Sobraba del diseño anterior,
     cuando el muro tenía scroll propio; al quitar el scroll y dejar el botón
     de «Cargar más», la altura máxima se quedó suelta. El resultado en
     teléfono era que las reseñas desbordaban la caja y los enlaces a Google y
     Doctoralia, que van justo debajo, se pintaban encima de ellas. */
}
.perfiles { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin-top: 22px; }
.perfil-chip {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 11px 18px; border-radius: 999px;
  border: 1px solid var(--sand-line); background: var(--paper);
  color: var(--ink); font-size: .91rem; font-weight: 500;
  transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
}
.perfil-chip:hover { border-color: var(--ink-muted); box-shadow: var(--shadow-soft); transform: translateY(-1px); }
.perfil-chip svg { width: 17px; height: 17px; flex: 0 0 auto; }
.perfil-chip span { color: var(--ink-muted); font-weight: 400; }

/* ---------- Los dos perfiles, en la misma fila en teléfono ----------
   Sumaban 435px de ancho para los 327 disponibles a 375px de pantalla, así que
   el flex-wrap los apilaba. Se reparten la fila a partes iguales y se aprieta
   lo que se puede sin bajar de un tamaño legible; lo que no cabe en una línea
   se parte en dos dentro de su propia píldora, que es preferible a apilarlas.
   `min-width: 0` es lo que permite que un elemento flexible baje de su ancho
   de contenido: sin él, `flex: 1` no sirve de nada aquí. */
@media (max-width: 620px) {
  .perfiles { flex-wrap: nowrap; gap: 9px; }
  .perfil-chip {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    text-align: center;
    padding: 10px 12px;
    gap: 7px;
    font-size: .82rem;
    line-height: 1.28;
  }
  .perfil-chip svg { width: 16px; height: 16px; }
}

/* ═══════════════════════════════════════════════════════════════
   ANIMACIÓN DE ENTRADA AL SCROLLEAR

   El atributo data-reveal lo pone landing.js, nunca el HTML: si el
   JavaScript fallara, el contenido se queda visible en lugar de
   desaparecer para siempre.
   ═══════════════════════════════════════════════════════════════ */
/* Mientras landing.js reparte los data-reveal, la transición se apaga: si no,
   el navegador anima de opacidad 1 a 0 y el bloque se ve desvanecerse antes de
   entrar. Se quita en cuanto termina el etiquetado. */
.reveal-preparando [data-reveal] { transition: none !important; }

[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .8s cubic-bezier(.22, 1, .36, 1),
              transform .8s cubic-bezier(.22, 1, .36, 1);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
/* Variante sin desplazamiento para elementos con position:sticky: moverlos
   con transform los saca de su contenedor y rompe el pegado. */
[data-reveal="fade"] { transform: none; }

[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;   /* se libera la capa de GPU una vez terminada */
}

@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    transform: none;                      /* fundido puro, sin movimiento */
    transition-duration: .5s !important;
    transition-delay: var(--reveal-delay, 0ms) !important;
  }
}

/* ---------- Tarjeta con fotografía ---------- */
.card--foto { padding: 0; overflow: hidden; display: block; }
.card__foto {
  width: 100%;
  aspect-ratio: 8 / 5;
  object-fit: cover;
  /* Las fotos vienen del sitio anterior con fondo blanco; se generaron ya
     fundidas sobre --paper, así que empalman con la tarjeta sin costura. */
  background: var(--paper);
  transition: transform .5s cubic-bezier(.22, 1, .36, 1);
}
.card--foto:hover .card__foto { transform: scale(1.035); }
.card--foto h3 { margin: 26px 32px .5em; }
.card--foto p  { margin: 0 32px 30px; }
@media (prefers-reduced-motion: reduce) {
  .card--foto:hover .card__foto { transform: none; }
}

/* ---------- Rejilla a sangre (procedimientos) ----------
   La rejilla vive fuera del .wrap, así que ya ocupa el ancho completo sin
   recurrir a 100vw ni a márgenes negativos, que en escritorio se cuelan por
   debajo de la barra de scroll. El encabezado sí se queda dentro del .wrap:
   un titular a todo lo ancho pierde legibilidad. */
.grid--sangrado {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;               /* pegadas entre sí, como en la web de referencia */
}
.grid--sangrado .card {
  border-radius: 0;
  box-shadow: none;
  border-right: 1px solid var(--sand-line);
}
.grid--sangrado .card:last-child { border-right: 0; }
.grid--sangrado .card--foto h3 { margin: 24px 26px .45em; font-size: clamp(1.1rem, 1.5vw, 1.28rem); }
.grid--sangrado .card--foto p  { margin: 0 26px 28px; font-size: .98rem; }

@media (max-width: 1100px) {
  .grid--sangrado { grid-template-columns: repeat(2, 1fr); }
  /* Con dos columnas el borde derecho sobra en las tarjetas pares */
  .grid--sangrado .card:nth-child(2n) { border-right: 0; }
  .grid--sangrado .card:nth-child(-n+2) { border-bottom: 1px solid var(--sand-line); }
}
@media (max-width: 640px) {
  .grid--sangrado { grid-template-columns: 1fr; }
  .grid--sangrado .card { border-right: 0; border-bottom: 1px solid var(--sand-line); }
  .grid--sangrado .card:last-child { border-bottom: 0; }
}




/* ---------- El pop-up de la agenda es el propio calendario ----------
   Sin tarjeta, sin relleno y sin fondo alrededor: el envé del calendario ya
   trae su propio diseño y encima quedaba una caja dentro de otra caja. */
#modal-cita .modal__panel {
  background: transparent;
  box-shadow: none;
  border-radius: 0;
  overflow: visible;
  max-width: min(460px, 94vw);
}
#modal-cita .modal__body { padding: 0; }
#modal-cita #cal-mount {
  border-radius: var(--r-md);
  /* Sin scroll y a alto completo (pedido del cliente): el contenedor toma
     todo el alto visible y el iframe lo llena con !important — es la única
     forma de ganarle a la altura inline que Docplanner escribe por
     postMessage. El propio widget reacomoda su contenido al alto que se le
     da; si algún día vuelve a cortarse, la alternativa documentada en git es
     el overflow-y:auto (commit 9e7ce91). */
  overflow: hidden;
  background: transparent;
}



/* ALTURA DEL CALENDARIO EN ESCRITORIO. Sin esto el widget no se ve.
   El de +Pacientes que traía el original crecía a lo alto solo: llegaba su
   altura real por postMessage y landing.js se la escribía al iframe. El de
   Doctoralia hace otra cosa: se pone `height: 100%` a sí mismo y espera que el
   contenedor tenga una altura definida. #cal-mount sólo tenía `min-height`, y
   un porcentaje NO resuelve contra un padre de altura `auto` — min-height no
   cuenta—, así que el 100% se quedaba en `auto` y el iframe caía a los 150 px
   por defecto del navegador: un calendario recortado dentro de una caja de
   400. Se le da altura al contenedor y el 100% ya tiene contra qué resolverse.

   Por debajo de 620 px no hace falta: el modal va a pantalla completa y la
   cadena de alturas la monta el bloque de esa media query, que además es
   posterior en el archivo. Por eso ésta se acota a escritorio en lugar de
   sobrescribirla. */
@media (min-width: 621px) {
  /* overflow-y auto y no hidden: widget.js de Docplanner escribe la altura
     REAL del calendario como estilo inline vía postMessage, y el inline gana
     a nuestro height:100%. Cuando esa altura supera los 660 del contenedor,
     con hidden el faldón quedaba CORTADO (y un reload, con otro timing del
     mensaje, lo «arreglaba»). Con auto, el iframe crece y el contenedor se
     desplaza: nada se corta llegue o no llegue el mensaje. El 100% se queda
     como base para cuando el mensaje no llega. */
  #modal-cita #cal-mount { height: calc(100svh - 96px); min-height: 0; }
  /* Sólo escritorio: el iframe llena el contenedor con !important para
     ganarle a la altura inline que Docplanner escribe por postMessage. */
  #modal-cita #cal-mount iframe { height: 100% !important; }
}
/* EL BOTÓN DE CERRAR DEL CALENDARIO.
   Aquí el botón no cae sobre el papel crema de los otros modales: cae sobre el
   interior del calendario de Doctoralia, que es blanco arriba y trae sus
   propios controles. Con el 8 % de tinta que heredaba del original quedaba un
   disco casi invisible y una cruz oscura suelta sobre contenido ajeno: no se
   leía como botón, y encima tapaba la esquina del widget.

   Se resuelve con un disco OPACO en carbón, cruz blanca y un aro claro que lo
   despega de lo que tenga detrás — el mismo recurso que ya usa el modal de
   video sobre los fotogramas. Y se sube fuera de la caja del calendario
   (translate hacia arriba y a la derecha, con el panel en `overflow: visible`),
   así deja de tapar nada. En pantallas donde el modal va a sangre eso no cabe,
   y ahí se queda dentro: lo resuelve la media query de 620 px. */
#modal-cita .modal__close {
  top: 0; right: 0;
  transform: translate(38%, -38%);
  width: 40px; height: 40px;
  background: var(--pill);
  color: #fff;
  box-shadow: 0 0 0 3px var(--cream), 0 6px 18px rgba(20, 17, 14, .28);
}
#modal-cita .modal__close:hover,
#modal-cita .modal__close:focus-visible { background: #2A2420; }

/* Después de la regla base a propósito: el overflow es por-propiedad en la
   cascada y el `overflow: hidden` del base (que viene antes que esto pero
   después que las media queries de arriba) ganaba al del bloque de 620. */
@media (max-width: 620px) {
  #modal-cita #cal-mount { overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; }
}
@media (max-width: 620px) {
  /* A sangre no hay margen fuera del panel: vuelve adentro, sobre el blanco
     del calendario, donde el disco opaco sigue leyéndose. */
  #modal-cita .modal__close {
    top: calc(10px + env(safe-area-inset-top)); right: 10px;
    transform: none;
  }
}


/* ---------- Objetivos táctiles que quedaban por debajo de 44 px ----------
   Todos son enlaces o botones sueltos —no texto corrido—, así que aquí no
   aplica la excepción de «enlace dentro de una frase» y hay que darles la caja
   entera. Ninguno cambia de sitio ni de tamaño aparente: crece la zona que
   responde al dedo, que es justo lo que no se ve. */

/* Teléfono y WhatsApp de la ficha del consultorio: van uno por renglón dentro
   de un <dl>, y medían 20 px de alto. */
.office dd a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* Las dos pastillas que llevan a Google y a Doctoralia: en escritorio dan 44
   de sobra, pero al estrecharse la columna bajaban a 39. */
.perfil-chip { min-height: 44px; }

/* Iconos de Instagram y Facebook del pie: 38 px de disco. */
.footer__social a { width: 44px; height: 44px; }

/* Atribución de +Pacientes. */
.footer__marca a { min-height: 44px; align-items: center; }

/* Banner de cookies: los dos botones se quedaban en 40 px de alto, y el
   enlace al aviso va dentro de la frase, así que ése se estira con relleno
   vertical y margen negativo para no descuadrar el párrafo. */
.cookies .btn { min-height: 44px; }
.cookies p a {
  display: inline-block;
  padding-block: 13px;
  margin-block: -13px;
}

/* ═══════════════════════════════════════════════════════════════
   SECCIÓN CON FOTOGRAFÍA DE FONDO («Con quién te vas a operar»)

   Se usa <picture> y no background-image para conservar el WebP con su
   respaldo JPG y la carga diferida. El velo va en un pseudo-elemento
   aparte, no como filtro sobre la imagen, para no encarecer la composición.
   ═══════════════════════════════════════════════════════════════ */
.section--foto { position: relative; overflow: hidden; }

.section__fondo { position: absolute; inset: 0; z-index: 0; }
.section__fondo picture,
.section__fondo img { display: block; width: 100%; height: 100%; }
.section__fondo img { object-fit: cover; object-position: 50% 42%; }

/* Velo miel: la sección es --sage-deep con texto claro, así que la foto tiene
   que quedar por debajo del umbral de contraste del cuerpo de texto. Más denso
   a la izquierda, donde va el texto, y más abierto a la derecha, donde se deja
   ver el muro de certificaciones.

   El tono del velo (29°) es el mismo del cobre, con la saturación y el valor
   del velo verde que traía el original: así el degradado sigue muriendo
   dentro del color de la sección en vez de ensuciarla con un tinte ajeno. */
.section__fondo::after {
  content: "";
  position: absolute; inset: 0;
  background:
    linear-gradient(96deg,
      rgba(45, 31, 17, .95) 0%,
      rgba(45, 31, 17, .94) 58%,
      rgba(45, 31, 17, .86) 82%,
      rgba(45, 31, 17, .55) 100%);
}

.section--foto > .wrap { position: relative; z-index: 1; }

/* El texto ya no vive en una columna, así que necesita su propia medida:
   a todo lo ancho la línea se vuelve ilegible. */
.trayectoria__texto { max-width: 980px; }
.trayectoria__texto > .lead { max-width: 620px; }

@media (max-width: 900px) {
  /* En vertical el degradado lateral no cubre: se vuelve de arriba abajo */
  .section__fondo::after {
    background:
      linear-gradient(180deg,
        rgba(45, 31, 17, .93) 0%,
        rgba(45, 31, 17, .95) 55%,
        rgba(45, 31, 17, .96) 100%);
  }
  .trayectoria__texto { max-width: none; }
}


/* ---------- Entrada escalonada de las credenciales ----------
   Curva propia, más expresiva que la del resto de bloques: arranca rápido y
   frena largo al final (expo-out), con un desplazamiento algo mayor para que
   el escalonado se lea al bajar. */
.creds li[data-reveal] {
  transform: translateY(30px);
  transition:
    opacity   .72s cubic-bezier(.16, 1, .3, 1),
    transform .82s cubic-bezier(.16, 1, .3, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
.creds li[data-reveal].is-revealed { transform: none; }

@media (max-width: 860px) {
  .creds { grid-template-columns: 1fr; }
  /* Vuelta a una columna: sólo el primero pierde el filete */
  .creds li:nth-child(-n+2) { border-top: 1px solid; border-top-color: inherit; padding-top: 17px; }
  .creds li:first-child { border-top: 0; padding-top: 0; }
  .creds li:nth-child(2)::before { top: 18px; }
  .creds li:first-child::before  { top: 1px; }
  .trayectoria__texto { max-width: none; }
}


/* Bloque de texto suelto dentro de una sección: necesita medida propia, que a
   todo lo ancho del contenedor la línea se vuelve incómoda de leer. */
.bloque-texto { max-width: 68ch; }
.bloque-texto h3 { margin-bottom: .6em; }

/* Bloque de autoridad sin imagen al lado: el titular y la entradilla necesitan
   medida propia para no cruzar los 1140px del contenedor. Las credenciales sí
   aprovechan todo el ancho, que ya van en dos columnas. */
/* La medida es 980px, la misma que .trayectoria__texto: el velo de
   .section__fondo está calibrado para que el contraste aguante hasta ese ancho.
   Si el bloque creciera, su borde derecho caería en la zona clara del degradado
   y el cuerpo de texto bajaría del mínimo AA. */
.bloque-autoridad { max-width: 980px; }
.bloque-autoridad > h2   { max-width: 22ch; }
.bloque-autoridad > .lead { max-width: 62ch; margin-bottom: 2.2rem; }

/* ═══════════════════════════════════════════════════════════════
   PROCESO EN DOS COLUMNAS QUE AVANZA CON EL SCROLL

   La sección mide N pantallas de alto y su contenido se ancla arriba: al bajar
   la vista no se mueve, pero la fase activa va cambiando. El alto extra es lo
   que da recorrido al scroll; el índice lo calcula landing.js desde la
   posición de la sección.
   ═══════════════════════════════════════════════════════════════ */
.proceso {
  /* Una pantalla por paso, más una de margen para entrar y salir */
  height: calc(var(--pasos, 6) * 78vh + 100vh);
  position: relative;
}
.proceso__fijo {
  position: sticky;
  top: 0;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-columns: minmax(240px, .82fr) 1.18fr;
  gap: clamp(36px, 6vw, 96px);
  align-items: center;
}

/* ---------- Columna izquierda: las fases ---------- */
.proceso__fases { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.proceso__fase {
  width: 100%;
  display: flex; align-items: baseline; gap: 16px;
  padding: 14px 4px;
  border: 0; background: none; cursor: pointer;
  font-family: var(--font-body);
  text-align: left;
  color: var(--ink-muted);
  transition: color .35s cubic-bezier(.16, 1, .3, 1);
}
.proceso__num {
  font-size: .78rem; letter-spacing: .1em;
  font-variant-numeric: tabular-nums;
  opacity: .55;
  transition: opacity .35s ease;
}
.proceso__rotulo {
  font-family: var(--font-head);
  font-size: clamp(1rem, 1.5vw, 1.18rem);
  line-height: 1.35;
  position: relative;
}
/* Filete que se rellena de izquierda a derecha en la fase activa */
.proceso__rotulo::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -6px;
  height: 1.5px; background: var(--sage);
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s cubic-bezier(.16, 1, .3, 1);
}
.proceso__fase:hover { color: var(--ink-soft); }
.proceso__fase[aria-current="true"] { color: var(--ink); }
.proceso__fase[aria-current="true"] .proceso__num { opacity: 1; color: var(--sage); }
.proceso__fase[aria-current="true"] .proceso__rotulo::after { transform: scaleX(1); }
.proceso__fase:focus-visible { outline: 2px solid var(--sage); outline-offset: 4px; border-radius: var(--r-sm); }

/* ---------- Columna derecha: los paneles ---------- */
.proceso__paneles {
  position: relative;
  min-height: 260px;
  /* La dirección la pone el JS según se baje o se suba */
  --entrada: 46px;
  --salida: -46px;
}
.proceso__paneles[data-dir="arriba"] { --entrada: -46px; --salida: 46px; }

.proceso__panel {
  position: absolute; inset: 0;
  opacity: 0; visibility: hidden;
  transform: translateY(var(--entrada));
  transition: opacity .42s cubic-bezier(.16, 1, .3, 1),
              transform .58s cubic-bezier(.16, 1, .3, 1),
              visibility 0s linear .6s;
}
/* El que entra: sube a su sitio y se descubre con un barrido desde abajo */
.proceso__panel[data-activo] {
  opacity: 1; visibility: visible; transform: none;
  transition-delay: 0s;
  /* El barrido lleva curva propia. La del desplazamiento, cubic-bezier(.16,1,.3,1),
     es muy frontal: a un cuarto del tiempo el borde ya iba por el 83% del
     recorrido y luego se arrastraba. Con esta la pasada se lee entera. */
  animation: barridoEntra .66s cubic-bezier(.38, .05, .2, 1);
}
.proceso__paneles[data-dir="arriba"] .proceso__panel[data-activo] { animation-name: barridoEntraArriba; }

/* El que sale se va en sentido contrario, no vuelve por donde vino */
.proceso__panel[data-saliente] {
  opacity: 0; visibility: visible;
  transform: translateY(var(--salida));
  transition-delay: 0s;
}

/* El barrido usa una máscara en degradado y no clip-path: el corte duro
   arrancaba el texto de golpe. Con la máscara, el borde que avanza lleva su
   propia transición de opacidad y el texto se va fundiendo a medida que sube.

   La máscara mide el triple que el panel y lo que se anima es su posición: al
   empezar, el panel cae sobre la zona transparente del degradado; al terminar,
   sobre la zona opaca. Las propiedades de máscara viven dentro de los
   fotogramas para que, al acabar, el panel se quede sin máscara ninguna. */
@keyframes barridoEntra {
  from {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 46%);
            mask-image: linear-gradient(to bottom, transparent 0%, #000 46%);
    -webkit-mask-size: 100% 300%;  mask-size: 100% 300%;
    -webkit-mask-position: 0% 0%;  mask-position: 0% 0%;
  }
  to {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 46%);
            mask-image: linear-gradient(to bottom, transparent 0%, #000 46%);
    -webkit-mask-size: 100% 300%;    mask-size: 100% 300%;
    -webkit-mask-position: 0% 100%;  mask-position: 0% 100%;
  }
}
@keyframes barridoEntraArriba {
  from {
    -webkit-mask-image: linear-gradient(to top, transparent 0%, #000 46%);
            mask-image: linear-gradient(to top, transparent 0%, #000 46%);
    -webkit-mask-size: 100% 300%;    mask-size: 100% 300%;
    -webkit-mask-position: 0% 100%;  mask-position: 0% 100%;
  }
  to {
    -webkit-mask-image: linear-gradient(to top, transparent 0%, #000 46%);
            mask-image: linear-gradient(to top, transparent 0%, #000 46%);
    -webkit-mask-size: 100% 300%;  mask-size: 100% 300%;
    -webkit-mask-position: 0% 0%;  mask-position: 0% 0%;
  }
}
.proceso__panel h3 { font-size: clamp(1.5rem, 2.8vw, 2.15rem); margin-bottom: .55em; }
.proceso__panel p  { font-size: 1.08rem; line-height: 1.72; margin: 0; }
.proceso__fase-movil { display: none; }

@media (prefers-reduced-motion: reduce) {
  /* No se desactiva, se acorta y se le quita el desplazamiento: el barrido es
     el contenido apareciendo, no un adorno, y sin él el cambio de paso pasa
     desapercibido. Misma decisión de cliente que en el acordeón de las FAQ. */
  .proceso__panel { transform: none; transition-duration: .3s !important; }
  .proceso__panel[data-saliente] { transform: none; }
  .proceso__panel[data-activo] { animation-duration: .42s !important; }
}

@media (max-width: 900px) {
  /* En vertical no hay sitio para dos columnas ni para anclar: se despliega
     todo en una lista normal y el scroll vuelve a ser el de siempre. */
  .proceso { height: auto; }
  .proceso__fijo { position: static; min-height: 0; display: block; }
  .proceso__fases { display: none; }
  .proceso__paneles { position: static; min-height: 0; display: grid; gap: 30px; }
  .proceso__panel {
    position: static; opacity: 1; visibility: visible; transform: none;
    background: var(--paper); border-radius: var(--r-lg);
    padding: 26px 28px; box-shadow: var(--shadow-soft);
  }
  .proceso__fase-movil {
    display: block; font-size: .8rem; letter-spacing: .1em; text-transform: uppercase;
    color: var(--clay); margin: 0 0 .5rem;
  }
  .proceso__panel h3 { font-size: 1.3rem; }
  .proceso__panel p { font-size: 1rem; }
}

/* El antetítulo del CTA final va en píldora: sobre el verde salvia, el texto
   suelto en #B9CDBB se diluye en el fondo y no ancla la sección. */
.cta-final .eyebrow {
  display: inline-block;
  margin-inline: auto;
  padding: 8px 18px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .12);
  border: 1px solid rgba(255, 255, 255, .22);
  color: #EAF2EB;
  backdrop-filter: blur(2px);
}

/* ---------- Fondo fotográfico del CTA final ----------
   Aquí el texto va centrado y ocupa el ancho medio, así que el velo es
   uniforme y no en degradado como en las secciones de autoridad.
   La densidad no es estética: con la miel de la sección haría falta más del
   96 % para que el .lead llegase al mínimo AA, y a esa opacidad la foto ya no
   se vería. Con este cobre más oscuro basta el 82 % y quedan 6,76:1 en el peor
   caso, sobre un píxel blanco de la fotografía. */
.cta-final .section__fondo::after {
  background: rgba(45, 31, 17, .82);
}
.cta-final .section__fondo img { object-position: 50% 62%; }

/* ---------- Sello de la American Association of Tissue Banks ----------
   Va en línea con el texto de la credencial. El color se hereda con
   currentColor, así que basta cambiar `color` según el fondo. */
.logo-aatb {
  display: inline-block;
  height: 1.18em;
  width: auto;
  vertical-align: -.3em;
  margin-left: .32em;
  color: #36671D;
}
/* Sobre el velo verde oscuro de las secciones de autoridad, el #36671D queda
   en 2,15:1 y no se distingue del fondo. Se aclara al mismo verde de marca
   pero legible: 7,07:1. */
/* (El sello de la AATB era del doctor anterior; su regla se retira.) */

/* ==========================================================================
   EL BANCO DE TEJIDOS — sección propia con el retrato recortado

   La foto va a sangre contra el borde inferior: por eso la sección no lleva
   relleno abajo y se lo pone la columna de texto, que sí lo necesita. El
   `align-items: end` de la rejilla es lo que apoya al doctor en esa línea.

   `overflow: hidden` no es decorativo: en pantallas estrechas la foto se
   ensancha por encima de su columna y sin recorte asomaría por el costado.
   ========================================================================== */
.banco {
  background: #ECE2DF;
  padding-bottom: 0;
  overflow: hidden;
}
.banco__grid {
  display: grid;
  grid-template-columns: 1.06fr .94fr;
  gap: clamp(28px, 4vw, 68px);
  align-items: end;
}
.banco__texto { padding-bottom: clamp(64px, 9vw, 120px); }
.banco__texto h2 { margin-bottom: .5em; }

/* ---------- El sello de verificado del titular ----------
   Va en el flujo del texto y no absoluto: así el titular se parte solo en
   pantallas estrechas y el sello se lleva la primera línea con él, sin
   solaparse con nada. */
.banco__titulo { display: flex; align-items: center; gap: .5em; flex-wrap: wrap; }
.banco__check {
  flex: 0 0 auto;
  width: 1.16em; height: 1.16em;
  border-radius: 50%;
  background: var(--sage);
  color: var(--paper);
  display: inline-grid; place-items: center;
  /* Entra girando y creciendo desde nada, un pelo después que el texto: el
     retraso es lo que hace que se lea como un sello que se estampa y no como
     una parte más del titular. */
  transform: scale(.2) rotate(-35deg);
  opacity: 0;
  transition: transform .62s cubic-bezier(.34, 1.56, .64, 1),
              opacity   .32s ease-out;
  transition-delay: .18s;
}
.banco__check svg { width: .62em; height: .62em; }
[data-reveal].is-revealed .banco__check,
.banco__texto:not([data-reveal]) .banco__check {
  transform: none;
  opacity: 1;
}

/* La figura entra más tarde y desde más abajo que el texto: apoyada en el
   borde, subir es el único gesto que no la despega de él.

   El `:not(.is-revealed)` no es cosmético. `[data-reveal].is-revealed` tiene
   la misma especificidad que `.banco__foto[data-reveal]` —una clase y un
   atributo cada uno— y esta regla va después en el archivo, así que ganaba
   también una vez revelada y la foto se quedaba desplazada para siempre. */
.banco__foto[data-reveal]:not(.is-revealed) { transform: translateY(52px); }
.banco__foto[data-reveal] { transition-delay: .26s; }
.banco__texto p + p { margin-top: 1em; }
.banco__foto picture { display: block; }
.banco__foto img {
  display: block;
  width: 100%;
  height: auto;
  /* Pegada abajo del todo: es lo que hace que se lea como si estuviera de pie
     sobre el borde de la sección y no flotando dentro de ella. */
  margin-bottom: -1px;   /* mata el hueco de línea base del inline */
}
@media (max-width: 900px) {
  .banco__grid { grid-template-columns: 1fr; gap: 0; }
  .banco__texto { padding-bottom: clamp(28px, 5vw, 44px); }
  /* De frente ocupa demasiado alto; centrada y algo más chica respira mejor */
  .banco__foto { max-width: 420px; margin-inline: auto; width: 100%; }
}

/* ---------- Sellos de la U.A.N.L. y de la Universidad de Navarra ----------
   Van bastante más altos que el de la AATB (1,18em) a propósito. Aquél es un
   logotipo de cuatro letras y se lee a cualquier tamaño; éstos son sellos con
   trazo muy fino y por debajo de ~36px se convierten en una mancha. A 2,15em
   sobre el cuerpo de 18,5px salen 40px, que es donde empiezan a leerse.
   `vertical-align: middle` los deja repartidos por igual arriba y abajo del
   renglón; la línea que los contiene crece unos 10px y ninguna otra se mueve. */
.logo-uanl,
.logo-navarra {
  display: inline-block;
  height: 2.15em;
  width: auto;
  vertical-align: middle;
  margin-left: .34em;
}

/* Misma excepción dentro del texto de credenciales: a 2,15em el logotipo de la
   UAG medía 137 px de ancho en mitad de un renglón y partía la frase en dos. */
.logo-uanl[src*="uag"] { height: 1.45em; }

/* El escudo de la U.A.N.L. es una mancha de color con anillo claro y aguanta
   solo sobre el velo verde. El de Navarra es de línea: a 40px el trazo no
   llega a cubrir un píxel entero, así que sobre fondo oscuro el rojo se mezcla
   y vira a marrón (2,65:1 en el peor caso) — y aclararlo lo vuelve gris. Se
   resuelve con la placa clara que usa cualquier manual de marca para fondos
   oscuros: el rojo institucional se conserva y se lee. */
.section--deep .logo-navarra {
  background: var(--sand);
  border-radius: 7px;
  padding: 2px 4px;
  box-sizing: content-box;
}

/* Widget de reseñas de Google bajo los botones del hero (2026-08-20).
   En móvil se oculta: el hero de 100svh ya carga con el primer plano del
   doctor y el widget de 230px lo pisaba con texto encima de la cara. */
.hero__resenas { max-width: 640px; margin-top: clamp(22px, 3vw, 32px); }
.hero__resenas iframe { display: block; width: 100%; height: 230px; border: 0; }
@media (max-width: 900px) { .hero__resenas { display: none; } }

/* Página /testimonios/: sin hero detrás, la sección respira bajo la navpill */
.pagina-testimonios { padding-top: clamp(28px, 4vw, 56px); }

/* ── Rediseño 2026-09: bajada del hero + franja de credenciales ── */
.hero__lead { color: rgba(255,255,255,.95); font-size: 1.04rem; line-height: 1.6; max-width: 46ch; margin: 14px 0 0; text-shadow: 0 1px 14px rgba(0,0,0,.35); }
.hero__lugar { display: block; margin-top: 8px; font-size: .9rem; color: rgba(255,255,255,.75); }
.credenciales { background: var(--cream-deep); padding: 26px 0; }
.credenciales .wrap { display: flex; align-items: center; justify-content: center; gap: 14px 30px; flex-wrap: wrap; }
.credenciales__lista { list-style: none; display: flex; flex-wrap: wrap; gap: 10px 26px; margin: 0; padding: 0; justify-content: center; }
.credenciales__lista li { display: inline-flex; align-items: center; gap: 8px; font-size: .95rem; color: var(--ink-soft); }
.credenciales__lista svg { width: 16px; height: 16px; flex: none; color: var(--clay); }
.credenciales__btn { display: inline-flex; align-items: center; min-height: 44px; padding: 8px 18px; border: 1.5px solid rgba(23,20,15,.25); border-radius: 100px; color: var(--ink); text-decoration: none; font-size: .92rem; white-space: nowrap; transition: border-color .2s ease, background-color .2s ease; }
.credenciales__btn:hover { border-color: var(--clay); background: rgba(125,74,26,.06); }
@media (max-width: 900px) {
  /* En móvil la bajada se oculta (el primer plano del doctor manda) y los
     botones se compactan para no pisarle la cara; el outline lleva fondo
     vidrio por si toca la bata blanca. */
  .hero__lead { display: none; }
  .hero__acciones { gap: 12px; }
  .hero__acciones .btn { padding: .85em 1.3em; font-size: .95rem; }
  .hero__acciones .btn--outline-light { background: rgba(23, 20, 15, .35); backdrop-filter: blur(6px); }
}

/* Botones dentro de páginas de texto (.legal): sin el color/subrayado de los
   enlaces de prosa — el texto del botón quedaba cobre sobre cobre. */
.legal a.btn { text-decoration: none; }
.legal .btn--primary { color: #FDFBF7; }
.legal .btn--primary:hover { color: #FDFBF7; }

/* Tarjetas de procedimientos con icono ilustrado (2026-10) en vez de foto:
   mismo marco 8/5, pero el icono se muestra completo con aire. */
.card--icono .card__foto { object-fit: contain; padding: clamp(18px, 2.5vw, 30px); background: var(--paper); }

/* ── Teléfonos (2026-10): selector de llamada en la barra móvil y botones
   de consultorio/urgencias en el hero de escritorio ── */
/* Icono de teléfono en el header (escritorio): despliega consultorio/urgencias */
.llamar-menu--nav { position: relative; }
.llamar-menu--nav summary.navpill__tel {
  list-style: none; cursor: pointer; width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center; color: var(--ink);
  border: 1.5px solid rgba(23, 20, 15, .22);
  transition: border-color .2s ease, background-color .2s ease;
}
.llamar-menu--nav summary.navpill__tel:hover { border-color: var(--clay); background: rgba(125, 74, 26, .06); }
.llamar-menu--nav summary::-webkit-details-marker { display: none; }
.llamar-menu--nav .llamar-menu__opciones { bottom: auto; top: calc(100% + 12px); left: auto; right: 0; min-width: 215px; }
@media (max-width: 900px) { .llamar-menu--nav { display: none; } } /* en móvil llama desde la barra inferior */
.mobile-cta .llamar-menu { flex: 1; position: relative; }
.llamar-menu summary { list-style: none; width: 100%; cursor: pointer; }
.llamar-menu summary::-webkit-details-marker { display: none; }
.llamar-menu__opciones {
  position: absolute; bottom: calc(100% + 10px); left: 0; right: 0; z-index: 80;
  background: var(--paper); border: 1px solid var(--sand-line); border-radius: 16px;
  box-shadow: 0 14px 36px rgba(23, 20, 15, .2); overflow: hidden;
}
.llamar-menu__opciones a {
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  min-height: 52px; padding: 10px 16px; color: var(--ink); text-decoration: none;
}
.llamar-menu__opciones a:hover { background: var(--cream-deep); }
.llamar-menu__opciones a + a { border-top: 1px solid var(--sand-line); }
.llamar-menu__opciones b { font-weight: 600; font-size: .95rem; }
.llamar-menu__opciones span { font-size: .84rem; color: var(--ink-muted); }

/* WhatsApp del hero: circular, solo icono (2026-10-22) */
.hero__wa { width: 56px; height: 56px; padding: 0; border-radius: 50%; flex: none; justify-content: center; }
/* Altura unificada de las acciones del hero: botón, WhatsApp y disco de play a 56px */
.hero__acciones .btn--hero { height: 56px; padding-top: 0; padding-bottom: 0; }
