/* ==========================================================================
   iSYSTEM S.A. — Sistema de diseño
   ADN medido sobre un referente institucional y traducido a la identidad de iSYSTEM.

   Principios heredados del referente:
   · Todos los títulos en peso 400. Ningún título en negrita, nunca.
   · letter-spacing -0.02em uniforme, en títulos y en cuerpo.
   · Superficies cálidas alternadas (arena / blanco) en vez de bordes y sombras.
   · Un solo acento, racionado: el ámbar aparece únicamente en botones de acción.
   · Prácticamente plano. Una sola sombra en toda la hoja, al 5%.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Color — arena dominante, marino como ancla, ámbar racionado */
  --c-marine:      #0A3D57;   /* ancla estructural: héroe, cifras, contacto */
  --c-marine-deep: #072B3E;   /* pie de página */
  --c-cyan:        #0095CF;   /* cian del logo: íconos, enlaces, filetes */
  --c-amber:       #F29400;   /* ámbar del logo: SOLO botones de acción */
  --c-amber-hover: #D98200;
  --c-sobre-amber: #241500;   /* 7.62:1 sobre el ámbar — el blanco daba 2.31:1 y fallaba AA */
  --c-sand:        #EDEAE5;   /* superficie alterna dominante */
  --c-sand-deep:   #E3DED7;   /* bordes sobre arena */
  --c-light:       #FEFEFE;
  --c-dark:        #1A1C1E;   /* cuerpo de texto — nunca negro puro */
  --c-muted:        #6E7378;  /* 4.75:1 sobre blanco — FALLA sobre arena (3.99:1) */
  --c-muted-fuerte: #5A5F64;  /* 5.38:1 sobre arena · 6.40:1 sobre blanco — el gris seguro en cualquier superficie clara */
  --c-line:        rgba(26, 28, 30, .12);
  --c-line-light:  rgba(254, 254, 254, .22);

  /* Geometría — escala de radios 9 / 18 / 28 del referente */
  --r-sm: 9px;
  --r-md: 18px;
  --r-lg: 28px;

  /* Espaciado — unidad base 8px */
  --unit:      8px;
  --section-y: 180px;         /* ritmo vertical en desktop */
  --header-h:  76px;

  /* Movimiento — un solo token de hover, igual que el referente */
  --t: .3s ease-in-out;
  /* Curva de los reveals: equivalente CSS del power1.out de GSAP, la que el
     referente usa (implícita) en todos sus fade-up de scroll. */
  --ease-reveal: cubic-bezier(.25, .46, .45, .94);

  /* Duración de la entrada: la tarjeta sube, se detiene y se expande.
     Calibrada contra los tiempos reales del referente (delay 200ms + subida
     800ms circ.out + asentado interior 1000ms): con las dos fases del gesto
     y la pausa, 2400ms le devuelve la gravedad sin volver a la cola de 4,8s
     (los textos entran SOLAPADOS, no después). Afinar aquí, son dos tokens. */
  --hero-t: 2400ms;
  /* Espera en blanco antes de que la tarjeta suba: el primer respiro de la
     entrada. Subir --hero-delay hace que la tarjeta tarde más en aparecer. */
  --hero-delay: 600ms;

  /* Elevación — dos niveles, y sólo dos. El referente es prácticamente plano:
     lo que no despega del papel va sin sombra, separado por superficies alternas. */
  /* Nivel 1 — se apoya en el contenido: cabecera sólida, burger. */
  --shadow: 0 4px 10px rgba(0, 0, 0, .05);
  /* Nivel 2 — FLOTA sobre el contenido y tiene que despegarse de una fotografía
     o de texto denso: panel del menú móvil y barra de contacto de celular. */
  --shadow-flotante: 0 4px 10.1px rgba(0, 0, 0, .05), 0 24px 48px rgba(26, 28, 30, .12);

  /* Contenedor */
  --wrap:   1265px;
  --gutter: 40px;
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

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

body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, ul, ol, dl, dd {
  margin: 0;
  padding: 0;
}

ul[class], ol[class] { list-style: none; }

img, picture, svg { max-width: 100%; display: block; }

button, input, textarea, select { font: inherit; color: inherit; }

button { background: none; border: 0; cursor: pointer; }

a { color: inherit; text-decoration: none; }

/* Foco visible por defecto en TODO lo enfocable. Antes existían tres reglas
   sueltas para tres botones (nav, hero, barra de contacto); los demás
   elementos quedaban con el anillo del navegador o, en el formulario, con un
   borde de 1px casi invisible. :where() tiene especificidad cero a propósito:
   las tres reglas específicas de más abajo siguen ganando donde ya existían. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--c-cyan);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Sobre superficies marinas el cian pierde separación: se usa blanco. */
.section--marine :where(a, button, input, select, textarea):focus-visible,
.footer :where(a, button):focus-visible,
.hero :where(a, button):focus-visible {
  outline-color: var(--c-light);
}

/* Enlace de salto: primera parada del tabulador en una página de 24 pantallas. */
.salto {
  position: absolute;
  left: 12px;
  top: -100px;
  z-index: 100;
  padding: 14px 22px;
  background: var(--c-marine);
  color: var(--c-light);
  border-radius: var(--r-sm);
  transition: top var(--t);
}
.salto:focus { top: 12px; }

/* --------------------------------------------------------------------------
   3. Tipografía
   Escala fluida calibrada sobre las medidas reales del referente:
   h1 64→120px · h2 43→80px · h3 35→64px · h4 29→40px  (de 480px a 1920px)
   El cuerpo queda fijo en 17px — un punto por encima del referente, porque
   la audiencia son dirigentes vecinales de 40 a 70 años, muchos en celular.
   -------------------------------------------------------------------------- */

body {
  font-family: 'Source Sans 3', 'Source Sans Pro', -apple-system,
               BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  font-size: 17px;
  line-height: 1.5;
  letter-spacing: -.02em;
  color: var(--c-dark);
  background: var(--c-light);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: 400;              /* la firma del referente: ningún título en negrita */
  line-height: 1.1;
  letter-spacing: -.02em;
  text-wrap: balance;
}

h1 { font-size: clamp(4rem,    2.833rem + 3.889vw, 7.5rem); line-height: 1; }
h2 { font-size: clamp(2.7rem,  1.95rem  + 2.542vw, 5rem); }
h3 { font-size: clamp(2.17rem, 1.558rem + 2.035vw, 4rem); }
h4 { font-size: clamp(1.8rem,  1.583rem + .764vw,  2.5rem); }
h5 { font-size: 1.5rem; }
h6 { font-size: 1.35rem; }

p { text-wrap: pretty; }

/* Título bicolor — el rasgo más característico del referente: la primera mitad
   en color pleno y la segunda apagada, dentro del mismo encabezado. */
.t-muted { color: var(--c-muted); }
.section--marine .t-muted { color: rgba(254, 254, 254, .55); }

/* Única salida del ámbar fuera de los botones, igual que hace el referente en
   su bloque de cierre. Reservado al llamado final. */
.t-accent { color: var(--c-amber); }

/* --------------------------------------------------------------------------
   4. Primitivas de layout
   -------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section-y); }

.section--sand   { background: var(--c-sand); }
.section--marine { background: var(--c-marine); color: var(--c-light); }

.section--marine h1, .section--marine h2, .section--marine h3,
.section--marine h4, .section--marine h5, .section--marine h6 { color: var(--c-light); }

/* Cabecera de sección: título grande + texto de apoyo al costado */
.sec-head {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 24px 80px;
  align-items: end;
  margin-bottom: 72px;
}

.sec-head__lede {
  font-size: 1.15rem;
  color: var(--c-muted);
  max-width: 46ch;
}

/* Sobre arena, --c-muted cae a 3.99:1 y falla AA. La regla ya existía en
   .familia__conteo y .fondo__detalle pero nunca se propagó aquí, que es donde
   más se lee: es la bajada de Servicios y de Fondos. */
.section--sand .sec-head__lede { color: var(--c-muted-fuerte); }

.section--marine .sec-head__lede { color: rgba(254, 254, 254, .72); }

/* Filete cian: el acento estructural de bajo costo */
.rule {
  width: 56px;
  height: 3px;
  background: var(--c-cyan);
  border-radius: 2px;
  margin-bottom: 28px;
}

/* --------------------------------------------------------------------------
   5. Botones
   Medidas tomadas del referente: 17px 28px de relleno, radio 18px, peso 400,
   sin mayúsculas. La forma es suave, no una píldora completa.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 17px 28px;
  border-radius: var(--r-md);
  font-size: 1rem;
  font-weight: 400;
  letter-spacing: -.02em;
  transition: background var(--t), color var(--t), border-color var(--t), transform var(--t);
  white-space: nowrap;
}

/* Sin lift en hover: el referente responde cambiando color, nunca moviendo
   el botón. La respuesta de cada variante vive en su propio :hover. */

.btn--primary { background: var(--c-amber); color: var(--c-sobre-amber); }
.btn--primary:hover { background: var(--c-amber-hover); }

.btn--ghost {
  background: transparent;
  color: var(--c-light);
  border: 1px solid var(--c-line-light);
}
.btn--ghost:hover { background: rgba(254, 254, 254, .1); border-color: rgba(254, 254, 254, .5); }

.btn--dark { background: var(--c-marine); color: var(--c-light); }
.btn--dark:hover { background: var(--c-marine-deep); }

/* Barrido ámbar — el botón-joya del hero, generalizado (2026-07-24): blanco
   con texto oscuro; al hover un barrido ámbar lo llena desde la izquierda,
   el texto vira a blanco y el botón crece apenas (la excepción de lift
   documentada del hero: es un momento de venta). Brilla sobre paneles
   oscuros. El contenido va en spans (.btn__label/.btn__arrow) para quedar
   sobre el ::before del barrido. Radio r18 del sistema (el del hero
   mantiene su píldora propia). */
.btn--sweep {
  position: relative;
  overflow: hidden;
  background: var(--c-light);
  color: var(--c-dark);
  transition: transform .22s cubic-bezier(.2, .7, .2, 1),
              color .22s ease, box-shadow .3s ease;
}
.btn--sweep::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--c-amber);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .35s cubic-bezier(.4, 0, .2, 1);
}
.btn--sweep .btn__label,
.btn--sweep .btn__arrow,
.btn--sweep svg { position: relative; z-index: 1; }   /* íconos sueltos (WhatsApp de "Escribir por WhatsApp"): sin esto el barrido los tapaba al hover */
.btn--sweep:hover {
  color: var(--c-sobre-amber);
  transform: scale(1.03);
  box-shadow: 0 12px 32px rgba(242, 148, 0, .38);
}
.btn--sweep:hover::before { transform: scaleX(1); }
.btn--sweep:active { transform: scale(.98); }

.btn__arrow { transition: transform var(--t); }
.btn:hover .btn__arrow { transform: translateX(4px); }

/* --------------------------------------------------------------------------
   6. Cabecera y navegación
   Transparente sobre el héroe; se vuelve sólida al hacer scroll.
   El logo se invierte a blanco puro mientras la cabecera es transparente.
   -------------------------------------------------------------------------- */

.header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background var(--t), box-shadow var(--t);
  /* Sobre el héroe, el contenido de la barra baja hasta el centro vertical
     MEDIDO en el nav del referente a 1920px (el ancho real del usuario): 62px del
     techo (logo y botón primario centran ambos en 62). Nuestra fila centra a
     38 (76/2), así que el drop es 62−38 = 24px. Al solidificar vuelve a la
     barra compacta: el drop viaja por transform, que no altera el layout. */
  --header-drop: 24px;
}

.header__inner {
  width: 100%;
  /* Wrapper del nav al estilo del referente, con su canaleta responsiva MEDIDA en
     vivo: 40px @1265 y 80px @1905. La recta entre ambos puntos es
     6.25vw − 39px; el clamp fija esos dos extremos. */
  max-width: 1952px;
  margin-inline: auto;
  padding-inline: clamp(40px, 6.25vw - 39px, 80px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  transform: translateY(var(--header-drop));
  transition: transform var(--t);
}

/* Solo desde 1280px, grid de 3 columnas: el nav queda centrado GEOMÉTRICAMENTE
   en la página (flex space-between lo desplazaría, porque logo y CTA no miden
   lo mismo). Bajo 1280 el lienzo no alcanza para los cinco enlaces con su aire
   —medido: a 1150px las columnas 1fr colapsaban y el logo se ENCOGÍA a 24px;
   a 1024, a cero— así que ahí manda el flex de arriba: logo + CTA + burger. */
@media (min-width: 1280px) {
  .header__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
  }
  .header__logo { justify-self: start; }
  .nav          { justify-self: center; }
  .nav__cta     { justify-self: end; }
}

/* El blanco táctil llega a 44px sin agrandar el logo: la caja del enlace crece
   por min-height y el <img> sigue midiendo 30px, centrado dentro. El header ya
   alinea al centro, así que el logo no se mueve ni un pixel. */
.header__logo {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.header__logo img {
  height: 30px;
  width: auto;
  /* max-width:none anula el 100% del reset: dentro de una columna 1fr que
     colapsa, ese 100% encogía el logo hasta hacerlo desaparecer (visto en
     vivo entre 900 y 1300px). La marca no negocia su tamaño: los breakpoints
     de abajo garantizan que siempre haya sitio para sus 194px. */
  max-width: none;
  /* Sobre el héroe oscuro el logo va en blanco de recorte */
  filter: brightness(0) invert(1);
  transition: filter var(--t);
}

.header.is-solid { background: var(--c-light); box-shadow: var(--shadow); --header-drop: 0px; }

/* Con el panel móvil abierto el logo sobra: se apaga con el token de hover. */
.header__logo { transition: opacity var(--t); }
.header.is-menu .header__logo { opacity: 0; pointer-events: none; }

/* CTA del panel móvil: invisible en escritorio (allí el CTA vive en la barra). */
.nav__menu-cta { display: none; }

/* Enlaces que solo existen en el panel desplegable: la barra centrada tiene
   capacidad para cinco (medido: más enlaces no caben ni a 1600px sin asfixiar
   el aire del sistema), así que Proceso vive aquí abajo y en el panel, donde
   la lista va completa y en el orden de la página. */
.nav__link--panel { display: none; }
.header.is-solid .header__logo img { filter: none; }

/* El aire entre links lo dan sus propios paddings (18px por lado) más el
   gap: 64 + 36 = 100px visuales entre textos — a escala del lienzo de 1952px
   y dentro de la escala de 8 del sistema. El clamp cede aire donde el lienzo
   no da: 40px justo a 1280 (76 visuales) y los 64 plenos desde ~1472. */
.nav { display: flex; align-items: center; gap: clamp(40px, 12.5vw - 120px, 64px); }

/* Cada link es una píldora invisible que se revela al hover: fondo translúcido
   esmerilado sobre el video (la referencia de la captura "Resources"). Radio 18
   del sistema — la esquina de botón del ADN, no píldora completa. */
.nav__link {
  font-size: 1rem;
  font-weight: 400;
  letter-spacing: -.02em;
  color: var(--c-light);
  opacity: .88;
  padding: 10px 18px;
  border-radius: var(--r-md);
  transition: opacity var(--t), color var(--t), background-color var(--t);
}
.nav__link:hover {
  opacity: 1;
  background: rgba(254, 254, 254, .16);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.header.is-solid .nav__link { color: var(--c-dark); }
.header.is-solid .nav__link:hover { background: rgba(26, 28, 30, .06); }

/* CTA de la barra — neutral, como el nav del referente (que no lleva ningún
   color): fantasma blanco sobre el héroe, marino sólido con la cabecera
   clara. El ámbar queda reservado a los llamados reales: si está siempre en
   pantalla deja de significar. El hover cambia color, no posición; el
   :active presiona hacia dentro (scale .97), como los ítems del referente. */
.nav__cta {
  padding: 12px 24px;
  font-size: .95rem;
  font-weight: 500;
  gap: 8px;
  border-radius: 100px;
  background: rgba(254, 254, 254, .06);
  color: var(--c-light);
  border: 1px solid var(--c-line-light);
  transition: background .3s ease-out, border-color .3s ease-out, color .3s ease-out,
              opacity var(--t);
}
.nav__cta:hover { background: rgba(254, 254, 254, .14); border-color: rgba(254, 254, 254, .55); }
.nav__cta:active { transform: scale(.97); }
.nav__cta:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

.header.is-solid .nav__cta {
  background: var(--c-marine);
  border-color: var(--c-marine);
  color: var(--c-light);
}
.header.is-solid .nav__cta:hover { background: var(--c-marine-deep); border-color: var(--c-marine-deep); }

/* La cabecera no existe durante la entrada: aparece recién cuando la tarjeta
   terminó de expandirse por completo. Antes el botón "Conversemos" se veía
   flotando sobre la página en blanco. */
.header {
  /* Receta literal del referente (.header.hidden .wrapper): sube desde
     translateY(30px) con fade, 1000ms ease-in-out — el mismo gesto del texto
     del hero (que usa 50px). Un solo movimiento para logo + nav + CTA, como
     hace el referente con su wrapper: nada aparece por separado. */
  animation: headerEntra 1000ms ease-in-out calc(var(--hero-delay) + var(--hero-t)) both;
}
@keyframes headerEntra {
  from { opacity: 0; transform: translateY(30px); }
  to   { opacity: 1; transform: none; }
}

/* El bloque que apaga estas animaciones con reduce-motion NO vive aquí: vive
   después de la última de ellas (busque "reduce-motion: la entrada completa").
   Un @media no aporta especificidad, así que puesto aquí lo sobrescribían las
   declaraciones posteriores — el hero se quedaba en blanco ~2s y luego entraba
   animado igual, justo para quien pidió que no se moviera. */

/* Botón hamburguesa — botón blanco redondeado, no un ícono suelto.
   Sobre el héroe el fondo cambia con cada clip del carrusel; un ícono
   sin superficie propia quedaría a merced de lo que haya detrás. */
.burger {
  display: none;
  width: 44px;
  height: 44px;
  position: relative;
  background: var(--c-light);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow);
}
.burger span {
  position: absolute;
  left: 11px;
  width: 22px;
  height: 1.5px;
  background: var(--c-dark);       /* siempre oscuras: el botón ya es blanco */
  transition: transform var(--t), opacity var(--t);
}
.burger span:nth-child(1) { top: 17px; }
.burger span:nth-child(2) { top: 22px; }
.burger span:nth-child(3) { top: 27px; }

.burger.is-open span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.burger.is-open span:nth-child(2) { opacity: 0; }
.burger.is-open span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* El logo de la tarjeta móvil no existe en el nav de escritorio. */
.nav__logo { display: none; }

/* --------------------------------------------------------------------------
   7. Héroe
   -------------------------------------------------------------------------- */

/* Pin del héroe — la física en manos del usuario, la clave del referente.
   El contenedor reserva el recorrido extra (--pin-d) y el héroe queda
   sticky dentro mientras js/main.js vuelca el progreso 0→1 en --pin-p.
   Sin JS, --pin-d no existe (0px) y esta caja mide exactamente 100svh.
   CENTINELA: ningún ancestro de .hero-pin puede llevar overflow distinto
   de visible — un overflow en <body> o <main> mataría el sticky en silencio. */
.hero-pin { height: calc(100svh + var(--pin-d, 0px)); }

.js .hero-pin { --pin-d: 1500px; }

.hero {
  position: sticky;
  top: 0;
  height: 100svh;
  /* Cuánto sube la tarjeta durante el scrub para hacerle sitio a la promesa
     (el -200px del referente, a escala). En celular es chica pero ya no 0
     (2026-08-02): el patrón de escritorio calcado deja los juegos colgando
     bajo la tarjeta y sin esta elevación rozaban el titular de la promesa.
     En px FIJOS, no svh: la promesa mide lo suyo en px, y una elevación
     que se encogiera con la pantalla devolvía el roce justo en los
     teléfonos más bajos (a 320×568 eran 5px de pisada). */
  --rise: 24px;
  display: grid;
  place-items: center;
  text-align: center;
  color: var(--c-light);
  overflow: hidden;
  /* La página abre en blanco: es lo que se ve mientras la tarjeta sube. */
  background: var(--c-light);
  /* Paddings IGUALES arriba y abajo: con place-items:center, un padding
     asimétrico corre el bloque la mitad de su diferencia — los 140/80 de antes
     lo dejaban 30px bajo el centro de la pantalla, y eso se notaba justo contra
     el eje del pin, porque la tarjeta del video encoge al centro geométrico
     exacto del viewport. Medido: desviación 30px → 0. El valor sigue siendo el
     que protege del header (76 + 64 de aire). */
  padding-block: calc(var(--header-h) + 64px);
}

/* Entrada. El medio nace como tarjeta fuera de cuadro por abajo, sube hasta su
   sitio, se detiene un instante, y recién entonces se expande a sangre completa.
   La pausa entre subir y expandir es lo que hace que se lean como dos gestos y
   no como un zoom continuo. Ocurre una sola vez, al cargar. */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;              /* recorta las esquinas mientras es tarjeta */
  /* will-change promueve la capa: la expansión corre en el compositor (GPU) y no
     da tirones. */
  will-change: transform;
  /* Look "cine a 45 FPS": la entrada usa los keyframes HORNEADOS (heroEntrada45)
     — el movimiento original (heroEntrada + heroRadio, conservados abajo como
     fuente de verdad) muestreado cada 1/45s; step-end sostiene cada cuadro.
     OJO: el horneado asume --hero-t = 2400ms; si cambia la duración, re-hornear
     para mantener los 45 FPS exactos. */
  animation: heroEntrada45 var(--hero-t) step-end var(--hero-delay) both;
  /* Encogimiento conducido por el scroll (--pin-p 0→1): a 1, el video queda
     como tarjeta de --card-w × --card-h con radio --card-r, centrada. Una
     sola propiedad compositada: no deforma el video ni repinta el radius
     en cada frame (medidas de tarjeta tomadas del referente: 309×362 r28). */
  /* min(Npx, (N/10)svh): a 1000px de alto o más, el valor de diseño exacto;
     por debajo, TODA la composición del payoff (tarjeta, satélites, --rise)
     se compresa proporcionalmente con la altura. Sin esto, en viewports
     bajos (iPad apaisado ~744-834, notebooks 768) la constelación invadía
     la promesa "Usted no pone dinero" — medido hasta +97px de solape. */
  --card-w: min(309px, 30.9svh);
  --card-h: min(362px, 36.2svh);
  --card-r: var(--r-lg);
  /* Porcentajes de inset(): relativos al propio elemento (alto/ancho), asi
     que 50% centra exacto sin que la scrollbar desplace la tarjeta. El
     desbalance top/bottom con --rise la hace subir mientras encoge. */
  clip-path: inset(
    calc(var(--pin-p, 0) * (50% - var(--card-h) / 2 - var(--rise)))
    calc(var(--pin-p, 0) * (50% - var(--card-w) / 2))
    calc(var(--pin-p, 0) * (50% - var(--card-h) / 2 + var(--rise)))
    calc(var(--pin-p, 0) * (50% - var(--card-w) / 2))
    round calc(var(--pin-p, 0) * var(--card-r)));
  /* La tarjeta principal NO se traslada con el ratón (decisión del usuario):
     queda en su sitio y MIRA hacia el cursor. La rotación replica LITERAL la
     fórmula del hero.js del referente: rotX/Y = ratón × speed×150, rotZ =
     ratón × speed×20, con perspective(1000px) POR ELEMENTO (equivale a su
     transformPerspective: 1000 y en el mismo orden en que GSAP compone:
     perspective → rotation → rotationY → rotationX). La perspectiva
     compartida del intento anterior deformaba en trapecio a las piezas
     descentradas y obligaba al hack de 250px aquí: retirado. --vel =
     speed×10 del referente (attachment: 0.13 → 1.3; multiplicadores 15deg y
     2deg = 150/10 y 20/10). --mxn/--myn viven en .hero (JS) y son 0 hasta
     que el parallax se activa; durante la entrada, la animación de
     keyframes pisa este transform: inofensivo. */
  --vel: 1.3;
  transform: perspective(1000px)
    rotate(calc(var(--mxn, 0) * var(--vel) * 2deg))
    rotateY(calc(var(--mxn, 0) * var(--vel) * 15deg))
    rotateX(calc(var(--myn, 0) * var(--vel) * -15deg));
}

/* El contenido del video se ENCOGE de verdad durante el scrub (no sólo lo
   recorta la ventana del clip-path): a p=1 queda a escala .5 — un plano más
   cerrado que la pantalla completa pero sin calzar con la tarjeta. El
   translateY acompaña la subida de la ventana (--rise): sin él, el contenido
   escalado queda centrado en la pantalla mientras la ventana sube, y por
   arriba asoma una franja vacía (el "sombreado" que se veía). El factor .5
   (no .55) garantiza cubrir la ventana de 362px incluso en pantallas bajas
   (800×.5 = 400 > 362). Puro transform compositado. */
.hero__clip,
.hero__media picture img {
  transform: translateY(calc(var(--pin-p, 0) * -1 * var(--rise, 0px)))
             scale(calc(1 - var(--pin-p, 0) * .5));
}

/* Con el primer scroll, el scrub toma el mando y las animaciones de entrada
   se apagan: su estado final coincide con el reposo (no hay salto) y lo que
   aún no había entrado aparece en su sitio. */
.hero--scrub .hero__media,
.hero--scrub h1,
.hero--scrub .hero__actions { animation: none; }

/* will-change sólo mientras el pin está activo: promoverla siempre cuesta memoria. */
.hero.is-pinning .hero__media { will-change: clip-path; }

/* Pasada la mitad del recorrido, el contenido ya casi no se ve: fuera del paso. */
.hero--faded .hero__inner { pointer-events: none; }

/* --------------------------------------------------------------------------
   7b. El pago del pin — constelación + promesa
   El referente nunca deja sola a la tarjeta que encoge: imágenes satélite se
   dispersan a su alrededor (offsets 0.2–0.35 de su timeline) y un texto entra
   en la segunda mitad del recorrido. Todo se conduce con --pin-p: cero JS.
   -------------------------------------------------------------------------- */

/* Satélites: nacen ocultos tras la tarjeta central y se separan con el pin.
   En todas las pantallas desde el 2026-08-02 (pedido del empleador: en el
   celular el payoff quedaba con la tarjeta central sola). El celular carga
   versiones -m de 640px (ver js) y lleva su propia dispersión de retrato,
   en el bloque ≤720 de abajo. */
.hero__constelacion {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
  pointer-events: none;
  /* SIN perspective aquí: el referente usa transformPerspective POR ELEMENTO
     (cada tarjeta lleva su perspective(1000px) dentro de su propio
     transform). Una perspectiva compartida proyecta a un único punto de fuga
     y deformaba en trapecio a las tarjetas descentradas. */
  /* OJO: no declarar aquí --mxn/--myn. El JS las escribe sobre .hero (para
     que también las vea la tarjeta principal) y una declaración local
     bloquearía la herencia; los satélites ya llevan fallback 0. */
  transform: translateY(calc(var(--pin-p, 0) * -1 * var(--rise)));
}

.hero__sat {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 150px;
  height: auto;          /* sin esto, el atributo height del HTML anula aspect-ratio */
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--r-md);
  /* Aparecen entre p .35 y .6, ya con la tarjeta claramente encogida. */
  opacity: clamp(0, calc((var(--pin-p, 0) - .35) * 4), 1);
  /* Las tarjetas NO se trasladan con el ratón (decisión del usuario): quedan
     fijas en su dispersión y solo MIRAN hacia el cursor. El giro replica la
     fórmula literal del referente, con DOSIS POR TARJETA: rotX/Y =
     ratón × speed×150, rotZ = ratón × speed×20, perspective(1000px) dentro
     del propio transform (su transformPerspective) y orden GSAP
     (perspective → translate → rotation → rotationY → rotationX).
     --vel = speed×10, así 15deg×--vel ≡ speed×150 y 2deg×--vel ≡ speed×20. */
  transform: perspective(1000px)
    translate(calc(-50% + var(--sx) * var(--pin-p, 0)),
              calc(-50% + var(--sy) * var(--pin-p, 0)))
    rotate(calc(var(--mxn, 0) * var(--vel, 1) * 2deg))
    rotateY(calc(var(--mxn, 0) * var(--vel, 1) * 15deg))
    rotateX(calc(var(--myn, 0) * var(--vel, 1) * -15deg));
}

/* Offsets del DNA del referente reducidos para el collage apretado (las
   tarjetas se pisan tras la central, como en el referente); --vel = speed×10 de
   sus velocidades de parallax 0.08 / 0.12 / 0.10 / 0.15 y dosifica la
   ROTACIÓN de cada tarjeta (la traslación de ratón sigue apagada). */
/* Mismo esquema min/max((N/10)svh) que --card-w: el collage entero escala
   con la altura del viewport y conserva sus proporciones. En los offsets
   negativos el "menor en magnitud" es max(), no min(). */
.hero__sat--1 { --sx: min(154px, 15.4svh);   --sy: max(-145px, -14.5svh); width: min(238px, 23.8svh); --vel: .8; }
.hero__sat--2 { --sx: min(240px, 24svh);     --sy: min(54px, 5.4svh);     width: min(198px, 19.8svh); --vel: 1.2; }
.hero__sat--3 { --sx: max(-158px, -15.8svh); --sy: min(96px, 9.6svh);     width: min(214px, 21.4svh); --vel: 1; }
.hero__sat--4 { --sx: max(-244px, -24.4svh); --sy: max(-85px, -8.5svh);   width: min(186px, 18.6svh); --vel: 1.5; }
/* Quinta tarjeta (2026-07-25): el referente tiene cinco satélites, no
   cuatro. Su offset (-60,-140) y su speed 0.11 son los del kit, escalados
   igual que los otros; cae arriba a la izquierda del centro, asomando por
   detrás de la tarjeta principal como en la captura del referente. */
.hero__sat--5 { --sx: max(-64px, -6.4svh); --sy: max(-152px, -15.2svh); width: min(205px, 20.5svh); --vel: 1.1; }

@media (min-width: 721px) {
  .hero { --rise: min(80px, 8svh); }  /* compresa con la altura, ver --card-w */
}

/* Celular (≤720): el MISMO patrón de escritorio, calcado (pedido del
   empleador del 2026-08-02 — sus dos dispersiones previas, anillo y
   racimo, no le gustaron; pidió copiar la composición de computador).
   Cada offset y ancho es la fracción que ese satélite guarda con la
   tarjeta central de escritorio (309×362), aplicada a la móvil (150×200):
   p. ej. sat-2 sx = 240/309 · 150 = 117. Se conserva todo: luminarias
   grande arriba-derecha, la energización de corona sobre el borde
   superior, bombas rozando por la izquierda, el solar asomando a media
   altura derecha y los juegos colgando abajo-izquierda por DEBAJO de la
   tarjeta, como en escritorio (de ahí el --rise móvil, ver §7). Baseline
   svh 714, la misma de --card-w/h: bajo esa altura el collage entero se
   compresa al ritmo de la tarjeta. Cabe en 375 con ~30px de margen por
   lado y en 320 de ancho (svh de SE1) sin desborde. */
@media (max-width: 720px) {
  .hero__sat--1 { --sx: min(75px, 10.5svh);    --sy: max(-80px, -11.2svh); width: min(116px, 16.2svh); }
  .hero__sat--2 { --sx: min(117px, 16.4svh);   --sy: min(30px, 4.2svh);    width: min(96px, 13.4svh); }
  .hero__sat--3 { --sx: max(-77px, -10.8svh);  --sy: min(53px, 7.4svh);    width: min(104px, 14.6svh); }
  .hero__sat--4 { --sx: max(-118px, -16.5svh); --sy: max(-47px, -6.6svh);  width: min(90px, 12.6svh); }
  .hero__sat--5 { --sx: max(-31px, -4.3svh);   --sy: max(-84px, -11.8svh); width: min(99px, 13.9svh); }
}

/* Promesa: entra en la segunda mitad del pin (p .45 → .9), bajo la tarjeta.
   Texto oscuro: a esa altura el fondo ya es la página blanca. Decorativa
   (sin --pin-p, con reduce-motion o sin JS, simplemente no existe). */
/* El bloque subió (2026-07-25) y ganó un párrafo debajo, como el titular +
   descripción del referente: antes la promesa iba sola y pegada al borde
   inferior. Sigue anclada por abajo —así crece hacia arriba sin invadir el
   pie del héroe— pero con más aire bajo ella. */
.hero__promesa {
  position: absolute;
  left: 50%;
  bottom: clamp(30px, 12svh, 132px);
  z-index: 1;
  width: min(92%, 720px);
  text-align: center;
  color: var(--c-dark);
  pointer-events: none;
  --fase: clamp(0, calc((var(--pin-p, 0) - .45) * 2.2), 1);
  opacity: var(--fase);
  transform: translate(-50%, calc((1 - var(--fase)) * 26px));
}

.hero__promesa-titulo {
  font-size: clamp(1.7rem, 1.25rem + 1.5vw, 2.6rem);
  line-height: 1.15;
  letter-spacing: -.02em;
  text-wrap: balance;
}

.hero__promesa-titulo span { color: var(--c-muted); }

/* El párrafo entra un poco después que el titular (fase propia, desfasada
   .08 del pin): el ojo lee primero la promesa y luego el detalle. */
.hero__promesa-texto {
  margin: 18px auto 0;
  max-width: 62ch;
  font-size: clamp(.98rem, .93rem + .2vw, 1.08rem);
  line-height: 1.5;
  color: var(--c-muted);
  text-wrap: pretty;
  opacity: clamp(0, calc((var(--pin-p, 0) - .53) * 2.4), 1);
}

/* Viewports bajos (tablet apaisada, notebook con barras): el aire de 12svh
   bajo la promesa era lo que, sumado al collage, no cabía. Se recorta solo
   aquí; sobre 920px de alto la composición original queda intacta. */
@media (min-width: 721px) and (max-height: 920px) {
  .hero__promesa { bottom: clamp(22px, 4.5svh, 96px); }
}

/* Alturas extremas (≤700px: notebook 768 con el navegador abierto): el
   titular baja medio escalón para que el conjunto respire. */
@media (min-width: 721px) and (max-height: 700px) {
  .hero__promesa-titulo { font-size: clamp(1.45rem, 1.1rem + 1.3vw, 2rem); }
}

/* Teléfonos cortos (iPhone SE): mismo recorte de aire que en escritorio
   bajo; acompaña al min() de --card-h del bloque móvil (§17). */
@media (max-width: 720px) and (max-height: 700px) {
  .hero__promesa { bottom: clamp(24px, 6svh, 132px); }
}

/* Cada tramo lleva su propia curva. Con una sola curva global no se puede
   pedir "sube lento pero expande rápido": la aceleración sería la misma en
   ambos gestos.
     0 → 50%    sube desde fuera del cuadro (ágil, rápida), frenando al llegar
    50 → 50.2%  pausa mínima, casi imperceptible
    50.2 → 100% se expande suave (~1.4s), un poco más lenta que la subida
   La tarjeta es grande y menos ancha: scale(.65, .74), esquinas suaves 34px. */
@keyframes heroEntrada {
  0% {
    /* 96% de su propia altura: el borde superior queda bajo el viewport, así
       que la tarjeta entra desde fuera de la página. */
    transform: translateY(96%) scale(.65, .74);
    animation-timing-function: cubic-bezier(.16, .9, .3, 1);
  }
  50% {
    transform: translateY(0) scale(.65, .74);
    animation-timing-function: linear;
  }
  50.2% {
    transform: translateY(0) scale(.65, .74);
    animation-timing-function: cubic-bezier(.34, 0, .22, 1);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}

/* El radio va aparte: colapsa de 34px a 0 pronto (51%→64%), al inicio de la
   expansión. Así el repintado del border-radius (que no es composited) ocurre
   temprano y el acomodo final —lo que se sentía con tirones— queda como puro
   transform en la GPU. */
@keyframes heroRadio {
  0%, 50% { border-radius: 34px; }
  62%     { border-radius: 0; }
  100%    { border-radius: 0; }
}

/* La misma entrada muestreada a 45 FPS (109 cuadros en 2400ms): cada keyframe es
   un cuadro y step-end lo sostiene hasta el siguiente. Generado con
   scratchpad/bake24fps.py a partir de heroEntrada + heroRadio (las curvas
   .16,.9,.3,1 de subida y .34,0,.22,1 de expansión). No editar a mano:
   re-hornear si cambian las curvas o --hero-t. */
@keyframes heroEntrada45 {
  0.0000% { transform: translateY(96.000%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  0.9259% { transform: translateY(86.311%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  1.8519% { transform: translateY(77.298%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  2.7778% { transform: translateY(69.023%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  3.7037% { transform: translateY(61.510%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  4.6296% { transform: translateY(54.753%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  5.5556% { transform: translateY(48.719%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  6.4815% { transform: translateY(43.357%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  7.4074% { transform: translateY(38.606%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  8.3333% { transform: translateY(34.403%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  9.2593% { transform: translateY(30.685%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  10.1852% { transform: translateY(27.395%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  11.1111% { transform: translateY(24.479%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  12.0370% { transform: translateY(21.891%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  12.9630% { transform: translateY(19.590%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  13.8889% { transform: translateY(17.541%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  14.8148% { transform: translateY(15.712%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  15.7407% { transform: translateY(14.077%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  16.6667% { transform: translateY(12.613%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  17.5926% { transform: translateY(11.299%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  18.5185% { transform: translateY(10.120%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  19.4444% { transform: translateY(9.059%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  20.3704% { transform: translateY(8.104%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  21.2963% { transform: translateY(7.244%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  22.2222% { transform: translateY(6.468%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  23.1481% { transform: translateY(5.768%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  24.0741% { transform: translateY(5.136%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  25.0000% { transform: translateY(4.566%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  25.9259% { transform: translateY(4.051%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  26.8519% { transform: translateY(3.586%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  27.7778% { transform: translateY(3.167%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  28.7037% { transform: translateY(2.789%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  29.6296% { transform: translateY(2.448%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  30.5556% { transform: translateY(2.141%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  31.4815% { transform: translateY(1.865%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  32.4074% { transform: translateY(1.618%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  33.3333% { transform: translateY(1.396%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  34.2593% { transform: translateY(1.198%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  35.1852% { transform: translateY(1.021%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  36.1111% { transform: translateY(0.864%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  37.0370% { transform: translateY(0.725%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  37.9630% { transform: translateY(0.602%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  38.8889% { transform: translateY(0.494%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  39.8148% { transform: translateY(0.400%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  40.7407% { transform: translateY(0.319%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  41.6667% { transform: translateY(0.249%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  42.5926% { transform: translateY(0.190%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  43.5185% { transform: translateY(0.140%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  44.4444% { transform: translateY(0.099%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  45.3704% { transform: translateY(0.067%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  46.2963% { transform: translateY(0.041%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  47.2222% { transform: translateY(0.022%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  48.1481% { transform: translateY(0.010%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  49.0741% { transform: translateY(0.002%) scale(0.6500, 0.7400); border-radius: 34.00px; }
  50.0000% { transform: translateY(0) scale(0.6500, 0.7400); border-radius: 34.00px; }
  50.9259% { transform: translateY(0) scale(0.6502, 0.7402); border-radius: 31.38px; }
  51.8519% { transform: translateY(0) scale(0.6512, 0.7409); border-radius: 28.75px; }
  52.7778% { transform: translateY(0) scale(0.6530, 0.7422); border-radius: 26.13px; }
  53.7037% { transform: translateY(0) scale(0.6558, 0.7443); border-radius: 23.51px; }
  54.6296% { transform: translateY(0) scale(0.6597, 0.7472); border-radius: 20.88px; }
  55.5556% { transform: translateY(0) scale(0.6647, 0.7509); border-radius: 18.26px; }
  56.4815% { transform: translateY(0) scale(0.6711, 0.7557); border-radius: 15.64px; }
  57.4074% { transform: translateY(0) scale(0.6790, 0.7615); border-radius: 13.01px; }
  58.3333% { transform: translateY(0) scale(0.6884, 0.7685); border-radius: 10.39px; }
  59.2593% { transform: translateY(0) scale(0.6994, 0.7767); border-radius: 7.77px; }
  60.1852% { transform: translateY(0) scale(0.7120, 0.7861); border-radius: 5.14px; }
  61.1111% { transform: translateY(0) scale(0.7261, 0.7965); border-radius: 2.52px; }
  62.0370% { transform: translateY(0) scale(0.7413, 0.8078); border-radius: 0.00px; }
  62.9630% { transform: translateY(0) scale(0.7573, 0.8197); border-radius: 0.00px; }
  63.8889% { transform: translateY(0) scale(0.7738, 0.8319); border-radius: 0.00px; }
  64.8148% { transform: translateY(0) scale(0.7902, 0.8441); border-radius: 0.00px; }
  65.7407% { transform: translateY(0) scale(0.8062, 0.8560); border-radius: 0.00px; }
  66.6667% { transform: translateY(0) scale(0.8215, 0.8674); border-radius: 0.00px; }
  67.5926% { transform: translateY(0) scale(0.8361, 0.8782); border-radius: 0.00px; }
  68.5185% { transform: translateY(0) scale(0.8498, 0.8884); border-radius: 0.00px; }
  69.4444% { transform: translateY(0) scale(0.8625, 0.8979); border-radius: 0.00px; }
  70.3704% { transform: translateY(0) scale(0.8744, 0.9067); border-radius: 0.00px; }
  71.2963% { transform: translateY(0) scale(0.8854, 0.9149); border-radius: 0.00px; }
  72.2222% { transform: translateY(0) scale(0.8956, 0.9224); border-radius: 0.00px; }
  73.1481% { transform: translateY(0) scale(0.9050, 0.9295); border-radius: 0.00px; }
  74.0741% { transform: translateY(0) scale(0.9138, 0.9359); border-radius: 0.00px; }
  75.0000% { transform: translateY(0) scale(0.9218, 0.9419); border-radius: 0.00px; }
  75.9259% { transform: translateY(0) scale(0.9293, 0.9475); border-radius: 0.00px; }
  76.8519% { transform: translateY(0) scale(0.9361, 0.9526); border-radius: 0.00px; }
  77.7778% { transform: translateY(0) scale(0.9425, 0.9573); border-radius: 0.00px; }
  78.7037% { transform: translateY(0) scale(0.9484, 0.9616); border-radius: 0.00px; }
  79.6296% { transform: translateY(0) scale(0.9538, 0.9657); border-radius: 0.00px; }
  80.5556% { transform: translateY(0) scale(0.9588, 0.9694); border-radius: 0.00px; }
  81.4815% { transform: translateY(0) scale(0.9634, 0.9728); border-radius: 0.00px; }
  82.4074% { transform: translateY(0) scale(0.9676, 0.9759); border-radius: 0.00px; }
  83.3333% { transform: translateY(0) scale(0.9715, 0.9788); border-radius: 0.00px; }
  84.2593% { transform: translateY(0) scale(0.9750, 0.9815); border-radius: 0.00px; }
  85.1852% { transform: translateY(0) scale(0.9783, 0.9839); border-radius: 0.00px; }
  86.1111% { transform: translateY(0) scale(0.9813, 0.9861); border-radius: 0.00px; }
  87.0370% { transform: translateY(0) scale(0.9840, 0.9881); border-radius: 0.00px; }
  87.9630% { transform: translateY(0) scale(0.9864, 0.9899); border-radius: 0.00px; }
  88.8889% { transform: translateY(0) scale(0.9886, 0.9915); border-radius: 0.00px; }
  89.8148% { transform: translateY(0) scale(0.9906, 0.9930); border-radius: 0.00px; }
  90.7407% { transform: translateY(0) scale(0.9923, 0.9943); border-radius: 0.00px; }
  91.6667% { transform: translateY(0) scale(0.9939, 0.9955); border-radius: 0.00px; }
  92.5926% { transform: translateY(0) scale(0.9953, 0.9965); border-radius: 0.00px; }
  93.5185% { transform: translateY(0) scale(0.9964, 0.9973); border-radius: 0.00px; }
  94.4444% { transform: translateY(0) scale(0.9974, 0.9981); border-radius: 0.00px; }
  95.3704% { transform: translateY(0) scale(0.9982, 0.9987); border-radius: 0.00px; }
  96.2963% { transform: translateY(0) scale(0.9989, 0.9992); border-radius: 0.00px; }
  97.2222% { transform: translateY(0) scale(0.9994, 0.9995); border-radius: 0.00px; }
  98.1481% { transform: translateY(0) scale(0.9997, 0.9998); border-radius: 0.00px; }
  99.0741% { transform: translateY(0) scale(0.9999, 1.0000); border-radius: 0.00px; }
  100.0000% { transform: translateY(0) scale(1.0000, 1.0000); border-radius: 0.00px; }
}

/* display:contents disuelve la caja del <picture> para que el <img> siga
   recibiendo las reglas de .hero__media img sin duplicarlas. */
.hero__media picture { display: contents; }

.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Carrusel de clips, SIN animación de escala propia. El gesto de
   tarjeta→pantalla completa ocurre una sola vez, en la entrada, y lo ejecuta
   .hero__media sobre todo el bloque.
   El cambio entre clips es un fundido cruzado suave (ya no un corte seco): dos
   escenas distintas se leen más naturales al mezclarse que al saltar. La
   duración debe coincidir con FUNDIDO en js/main.js. */
.hero__clip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .6s ease;
}

.hero__clip.is-active { opacity: 1; }

/* Secuencia deliberada: el titular "Fondos públicos, obras reales" sube solo
   desde abajo y se queda un momento SIN compañía. Recién tras una pausa entran
   el sello, el texto de apoyo y los botones — así hay un instante en que sólo
   se lee el titular. Todo atado a --hero-delay + --hero-t. */
/* El texto entra con la receta LITERAL del referente (no la máscara por líneas que
   hubo antes: el referente no la usa). Su interior sube entero desde
   translateY(50px) con fade, 1000ms ease-in-out — el mismo gesto para
   titular, apoyo y botones, escalonados en el tiempo. */
.hero__line { display: block; }
.hero__line > span { display: block; }

/* Sin la línea de apoyo (retirada el 2026-08-02) la cascada tiene dos tiempos,
   no tres: los botones suben a .8 — el turno que ocupaba el apoyo— o quedaría
   un silencio de casi medio segundo entre el titular y ellos. */
.hero h1       { animation: heroTexto 1000ms ease-in-out calc(var(--hero-delay) + var(--hero-t) * .62) both; }
.hero__actions { animation: heroTexto 1000ms ease-in-out calc(var(--hero-delay) + var(--hero-t) * .8) both; }

/* Los 50px de recorrido son los de .hero .wrapper en el CSS del referente. */
@keyframes heroTexto {
  from { opacity: 0; transform: translateY(50px); }
  to   { opacity: 1; transform: none; }
}

/* reduce-motion: la entrada completa, apagada.
   VA AQUÍ Y NO ARRIBA, y el orden es el arreglo: `@media` no suma
   especificidad, así que este `animation: none` solo gana si aparece DESPUÉS
   de las tres declaraciones que apaga —.hero__media (§7), .hero h1 y
   .hero__actions (aquí arriba)—. Mientras vivió antes que ellas, quien pedía
   menos movimiento veía el hero vacío ~2s y luego todo subiendo igual.
   Al mover o añadir una animación de entrada, mantener este bloque al final. */
@media (prefers-reduced-motion: reduce) {
  .hero__media, .header,
  .hero h1, .hero__actions { animation: none; }
}

/* Sombra neutra, NO un velo de color. El referente deja ver el video en sus
   colores propios: sólo oscurece arriba (para la barra) y abajo (para el
   titular y los botones), y deja el centro casi limpio. Un tinte marino al
   88% como el que había aquí antes esconde el video en vez de acompañarlo. */
.hero__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(0, 0, 0, .38) 0%,
    rgba(0, 0, 0, .08) 26%,
    rgba(0, 0, 0, .12) 58%,
    rgba(0, 0, 0, .50) 100%);
}

.hero__inner {
  position: relative;
  z-index: 1;
  max-width: 1000px;
  /* Se desvanece en la primera mitad del pin (p×2), como el referente. */
  opacity: clamp(0, calc(1 - var(--pin-p, 0) * 2), 1);
}

/* 48px, no los 30 de antes: ese margen se apoyaba en la línea de apoyo que
   seguía. Sin ella, los botones quedaban pegados al titular — 48 es el mismo
   aire que la línea de apoyo tenía bajo sí, así que el bloque conserva su
   proporción. */
.hero h1 { margin-bottom: 48px; }

.hero__actions {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
}

/* Botones del hero — píldoras minimalistas estilo del referente, blancas sobre el
   video. El ámbar de marca se reserva para el CTA de la barra superior.
   El hover (translateY -2px) lo hereda de .btn; aquí se suma el press y focus. */
.hero__actions .btn {
  padding: 15px 30px;
  min-height: 52px;                 /* ≥44px, cómodo al tacto */
  border-radius: 100px;             /* píldora */
  font-weight: 500;
  transition: transform .22s cubic-bezier(.2, .7, .2, 1),
              background .22s ease, border-color .22s ease, box-shadow .22s ease;
}
.hero__actions .btn:active { transform: translateY(0) scale(.98); }
.hero__actions .btn:focus-visible { outline: 2px solid #fefefe; outline-offset: 3px; }

/* Primario: relleno blanco, texto oscuro, sombra suave que lo despega del video.
   El hover es EL momento de venta de la página: un barrido ámbar (el color de
   acción de la marca, en su llamado más legítimo) llena el botón desde la
   izquierda, el texto vira a blanco, el botón crece apenas y la sombra se
   tiñe del mismo ámbar. La flecha hereda su empujón de .btn. */
.hero__actions .btn--primary {
  position: relative;
  overflow: hidden;
  background: #fefefe;
  color: var(--c-dark);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .18);
  transition: transform .22s cubic-bezier(.2, .7, .2, 1),
              color .22s ease, box-shadow .3s ease;
}
/* El barrido vive bajo el contenido: ::before posicionado + label/flecha con
   z-index propio (el texto suelto quedaría por debajo del pseudo). */
.hero__actions .btn--primary::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--c-amber);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .35s cubic-bezier(.4, 0, .2, 1);
}
.hero__actions .btn--primary .btn__label,
.hero__actions .btn--primary .btn__arrow {
  position: relative;
  z-index: 1;
}
.hero__actions .btn--primary:hover {
  color: var(--c-sobre-amber);
  transform: scale(1.03);
  box-shadow: 0 12px 32px rgba(242, 148, 0, .38);
}
.hero__actions .btn--primary:hover::before { transform: scaleX(1); }
.hero__actions .btn--primary:active { transform: scale(.98); }

/* Secundario: contorno blanco translúcido, se rellena apenas al pasar el mouse. */
.hero__actions .btn--ghost {
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .55);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.hero__actions .btn--ghost:hover {
  background: rgba(255, 255, 255, .14);
  border-color: #fff;
}

/* (El indicador "Baje para conocer" se retiró: le ponía peso de más al
   héroe y el pin ya invita a bajar por sí solo.) */

/* --------------------------------------------------------------------------
   8. Modelo — "la garantía en grande"
   Full-width editorial: cabecera → frase-garantía display → párrafo de
   contexto → 3 tarjetas (parientes de las stat-cards de §9, con gradiente
   ESTÁTICO 133deg: sin chase de cursor, cero JS) → banda fotográfica 21/9.
   Contrastes sobre el blanco de la sección (#FEFEFE, sin section--sand):
   · cian #0095CF = 3.36:1 → AA SOLO texto grande (≥24px): por eso vive
     únicamente en la garantía (40–64px) y en el número 01–03 (24px y
     además aria-hidden); PROHIBIDO en texto corriente de esta sección.
   · marino #0A3D57 = 11.45:1 ✓ · --c-muted #6E7378 = 4.75:1 ✓ (aquí sí
     pasa AA-normal, a diferencia de sobre arena) · #5A5F64 en tarjetas =
     6.40:1 sobre blanco y 5.83:1 sobre el extremo lavado del gradiente ✓.
   -------------------------------------------------------------------------- */

.modelo h2 { margin-bottom: 26px; }

/* Display entre el h3 y el h2 del sistema: 40→64px. Peso 400 — jerarquía
   por tamaño, la firma del referente. */
.modelo__garantia {
  margin-top: 56px;
  font-size: clamp(2.5rem, 1.7rem + 2.7vw, 4rem);
  line-height: 1.1;
  color: var(--c-marine);
  text-wrap: balance;
  max-width: 22ch;
}

/* El énfasis no engorda: colorea. Cian legal aquí SOLO por ser texto
   grande (3.36:1 ≥ 3:1 AA-large; sobre blanco puro, nunca sobre arena). */
.modelo__garantia strong {
  font-weight: 400;
  color: var(--c-cyan);
}

.modelo__contexto {
  margin-top: 28px;
  font-size: 1.15rem;
  color: var(--c-muted);          /* 4.75:1 sobre blanco: AA ✓ */
  max-width: 52ch;
}

.modelo__lista {
  margin-top: 72px;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;                      /* el gap de grillas del kit (= cifras) */
}

/* Tarjeta: pariente de .cifra (§9) — mismo borde, radio 18 y gradiente
   133deg (aquí fijo: el ángulo NO persigue al cursor), lavado cian de la
   c1. Sin sombras. */
.punto {
  background: linear-gradient(133deg, #FEFEFE 55%, #EBF5FB);
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  padding: 28px 30px;
}

/* 24px = umbral de "texto grande" WCAG: el cian pasa 3:1 incluso sobre el
   extremo lavado (3.06:1). Redundante con el <ol>, por eso aria-hidden. */
.punto__num {
  display: block;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--c-cyan);
  font-variant-numeric: tabular-nums;
}

/* Filete 34×4 r100: la puntuación tipográfica del referente, idéntica a
   cifras y fondos; crece al hover por transform (compositado). */
.punto__filete {
  display: block;
  width: 34px;
  height: 4px;
  border-radius: 100px;
  background: var(--c-cyan);
  margin: 18px 0 16px;
  transform-origin: left center;
  transition: transform .3s ease-out;
}

@media (hover: hover) {
  .punto:hover .punto__filete { transform: scaleX(1.65); }
}

.punto__titulo {
  font-size: 1.25rem;
  font-weight: 400;
  color: var(--c-dark);
  margin-bottom: 6px;
}

.punto__texto {
  font-size: .98rem;
  color: var(--c-muted-fuerte);   /* --c-muted falla AA aquí: ver tokens */
}

.modelo__banda { margin-top: 72px; }

.modelo__banda img {
  width: 100%;
  height: auto;        /* sin esto, el atributo height="" del HTML anula aspect-ratio */
  aspect-ratio: 21 / 9;
  object-fit: cover;
  border-radius: var(--r-lg);
}

/* Responsive autocontenido (como fondos §13): nada de esta sección vive
   ya en §17. */
@media (max-width: 1080px) {
  .modelo__garantia { margin-top: 44px; }
  .modelo__lista { grid-template-columns: 1fr; margin-top: 56px; }
  .modelo__banda { margin-top: 56px; }
}

@media (max-width: 720px) {
  .modelo__lista { margin-top: 48px; gap: 12px; }
  .punto { padding: 24px 22px; }
  .modelo__banda { margin-top: 48px; }
  .modelo__banda img { aspect-ratio: 16 / 10; }
}

/* --------------------------------------------------------------------------
   9. Cifras — panel de color + tarjetas
   No es una banda plana: el referente pone un panel vertical de color junto a
   una grilla 2×2 de tarjetas claras, sobre fondo arena.
   -------------------------------------------------------------------------- */

.cifras__layout {
  display: grid;
  grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
  gap: 24px;
  align-items: stretch;
}

.cifras__panel {
  position: relative;
  overflow: hidden;
  /* Degradado de anochecer marino (2026-07-24, antes plano): claro arriba-
     izquierda, profundo abajo-derecha — el cielo bajo el que se encienden
     las luces del pueblo. 145° ≈ el ángulo de gradiente de la casa. */
  background: linear-gradient(145deg, #0D4A6B 0%, var(--c-marine) 48%, var(--c-marine-deep) 100%);
  color: var(--c-light);
  border-radius: var(--r-lg);
  padding: 44px 40px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 36px;
}

/* El panel es angosto: el h2 se acota para no desbordarlo, sin perder el
   nivel semántico correcto en el documento. */
.cifras__panel h2 {
  color: var(--c-light);
  position: relative;
  z-index: 1;
  font-size: clamp(1.8rem, 1.35rem + 1.4vw, 2.6rem);
}

/* "iSYSTEM" ya no va en ámbar (2026-07-24): cian claro de las luces sobre
   el marino — 6.8:1, AA sobrado. El ámbar queda solo en el barrido del
   botón: un color de acción no decora titulares. */
.cifras__panel h2 span { color: #7FD1F2; }

.cifras__apoyo {
  position: relative;
  z-index: 1;
  font-size: 1rem;
  color: rgba(254, 254, 254, .7);
  margin-top: 16px;
}

.cifras__panel .btn { position: relative; z-index: 1; align-self: flex-start; }

/* Luces del pueblo (2026-07-24, reemplazo de los rayos radiales): las
   luminarias de un sector al anochecer, ancladas a la esquina inferior
   derecha. En reposo casi todas están apagadas (puntos tenues) y solo cinco
   laten; al pasar el cursor por el panel, el pueblo se enciende casa por
   casa. (La pasada de limpieza llegó el 2026-08-01: js/main.js ya no busca
   .cifras__rayos ni escribe --ray.) */
.cifras__luces {
  position: absolute;
  right: -24px;
  bottom: -16px;
  width: 360px;
  height: auto;
  pointer-events: none;
  z-index: 0;
}

/* El halo es un filtro POR GRUPO —dos en total, cálido y frío— en vez de
   uno por círculo: cincuenta drop-shadows individuales costarían pintado
   en cada frame del encendido. Cada luz solo anima su fill; el halo sale
   solo, proporcional a lo brillante que esté. */
.luces .campo {
  filter: drop-shadow(0 0 4px rgba(255, 198, 110, .5));
  transition: filter .4s ease-out;   /* el halo sube al hover, sin salto */
}
.luces .campo--frio { filter: drop-shadow(0 0 4px rgba(127, 209, 242, .5)); }

/* En reposo cada luz ya está viva: el pueblo titila SIEMPRE (2026-07-25;
   antes el ciclo sólo existía en hover). El fill declarado aquí es el
   estado apagado, que además es el que queda con reduce-motion —la regla
   global aplasta la animación a .01ms y el keyframe termina apagado. */
.luces .p {
  fill: rgba(254, 254, 254, .16);
  animation: titila 9s ease-in-out infinite;
  animation-delay: calc(var(--d, 0s) * 5);
}
.luces .p--lejos { fill: rgba(254, 254, 254, .08); }
.luces .campo--frio .p { animation-name: titilaFrio; }
.luces .p--lejos { animation-name: titilaLejos; }
/* Tres ciclos que no encajan entre sí (9/11/13s): las luces que arrancan
   juntas se desfasan solas y el patrón nunca se repite. */
.luces .p:nth-child(3n)   { animation-duration: 11s; }
.luces .p:nth-child(3n+1) { animation-duration: 13s; }

/* El pueblo vivo: cada luz PRENDE Y SE APAGA sola en un ciclo propio, así
   que nunca terminan todas encendidas — en cualquier instante hay unas
   pocas brillando y son otras un segundo después. El ciclo tiene la luz
   encendida solo entre el 5% y el 22% (≈1,5s de 9): el resto del tiempo
   espera apagada. */
@keyframes titila {
  0%, 100% { fill: rgba(254, 254, 254, .16); }
  5%, 15%  { fill: #FFD9A0; }
  22%      { fill: rgba(254, 254, 254, .16); }
}
@keyframes titilaFrio {
  0%, 100% { fill: rgba(254, 254, 254, .16); }
  5%, 15%  { fill: #A8E1F7; }
  22%      { fill: rgba(254, 254, 254, .16); }
}
/* Las del fondo del valle solo se insinúan: no compiten con las cercanas. */
@keyframes titilaLejos {
  0%, 100% { fill: rgba(254, 254, 254, .08); }
  5%, 15%  { fill: rgba(255, 217, 160, .5); }
  22%      { fill: rgba(254, 254, 254, .08); }
}

/* Con el cursor encima, el mismo pueblo se pone ERRÁTICO: ciclos menos de
   la mitad de largos y, sobre todo, varias ráfagas por vuelta en tiempos
   irregulares en vez de un encendido tranquilo. Cada familia parpadea con
   un patrón distinto (dos ráfagas seguidas las cálidas, una tardía las
   frías, un pestañeo corto las lejanas): así el conjunto se lee inquieto,
   no sincronizado. Las ráfagas duran ~180ms y cada luz destella 3 veces en
   ~5s — muy por debajo del umbral de destello de WCAG, y son puntos de 2px
   en una esquina, no superficie. */
@keyframes nervioso {
  0%, 100% { fill: rgba(254, 254, 254, .16); }
  3%       { fill: #FFE9C4; }                    /* chispazo, más blanco que el titileo tranquilo */
  6%       { fill: rgba(254, 254, 254, .16); }
  27%      { fill: #FFD9A0; }
  30%      { fill: rgba(254, 254, 254, .16); }
  61%      { fill: #FFE9C4; }
  64%      { fill: rgba(254, 254, 254, .16); }
}
@keyframes nerviosoFrio {
  0%, 100% { fill: rgba(254, 254, 254, .16); }
  12%      { fill: #C7ECFB; }
  15%      { fill: rgba(254, 254, 254, .16); }
  44%      { fill: #A8E1F7; }
  47%      { fill: rgba(254, 254, 254, .16); }
  78%      { fill: #C7ECFB; }
  81%      { fill: rgba(254, 254, 254, .16); }
}
@keyframes nerviosoLejos {
  0%, 100% { fill: rgba(254, 254, 254, .08); }
  18%      { fill: rgba(255, 233, 196, .6); }
  21%      { fill: rgba(254, 254, 254, .08); }
  70%      { fill: rgba(255, 233, 196, .6); }
  73%      { fill: rgba(254, 254, 254, .08); }
}

@media (hover: hover) {
  /* El turno de cada luz se comprime a ×2 (0→3s) para que el panel entero
     reaccione al toque del cursor, no en cámara lenta. */
  .cifras__panel:hover .p {
    animation-name: nervioso;
    animation-duration: 5.5s;
    animation-delay: calc(var(--d, 0s) * 3);
    animation-timing-function: ease-out;
  }
  .cifras__panel:hover .campo--frio .p { animation-name: nerviosoFrio; }
  .cifras__panel:hover .p--lejos { animation-name: nerviosoLejos; }
  .cifras__panel:hover .p:nth-child(3n)   { animation-duration: 6.4s; }
  .cifras__panel:hover .p:nth-child(3n+1) { animation-duration: 7.3s; }

  /* El halo también sube: el pueblo entero se ve más despierto. */
  .cifras__panel:hover .campo { filter: drop-shadow(0 0 5px rgba(255, 198, 110, .75)); }
  .cifras__panel:hover .campo--frio { filter: drop-shadow(0 0 5px rgba(127, 209, 242, .75)); }
}

/* Latido de 7s apenas perceptible, desfasado por luz — decoración viva sin
   ruido. reduce-motion lo congela vía la regla global (animation-duration
   .01ms) con las luces encendidas (el keyframe termina en 1). */
@keyframes luzLate {
  from { opacity: .5; }
  to   { opacity: 1; }
}
.luces .luz { animation: luzLate 7s ease-in-out infinite alternate; }
.luces .luz--2 { animation-delay: 2.3s; }
.luces .luz--3 { animation-delay: 4.1s; }
.luces .luz--4 { animation-delay: 1.2s; }
.luces .luz--5 { animation-delay: 5.5s; }

/* Bento: la líder (25 años) ocupa la columna izquierda completa a escala
   display —jerarquía por tamaño, nunca por peso—; las otras tres se apilan
   a la derecha. Gap 16 (el gap de grillas del kit). */
.cifras__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  grid-auto-rows: minmax(0, auto);
  gap: 16px;
}

/* "Profundidad del mar": cada tarjeta toma una profundidad de la familia
   azul de la marca. Tres variables por modificador: --tinte (ícono, filete,
   borde al hover), --tinte-suave (chip del ícono) y --lavado (el tramo
   final del gradiente de fondo). El ámbar no participa: sigue racionado. */
.cifra--c1 { --tinte: #0095CF; --tinte-suave: #E0F2FA; --lavado: #EBF5FB; }  /* cian    */
.cifra--c2 { --tinte: #2FA3D6; --tinte-suave: #E8F6FC; --lavado: #F0F9FD; }  /* cielo   */
.cifra--c3 { --tinte: #10618C; --tinte-suave: #E4EDF3; --lavado: #EEF4F8; }  /* mar     */
.cifra--c4 { --tinte: #0A3D57; --tinte-suave: #E3E9EE; --lavado: #EDF1F4; }  /* profundo*/

/* El fondo es un gradiente casi imperceptible cuyo ÁNGULO persigue al cursor
   (--chase, lo escribe js/main.js en escritorio): la firma de las stat cards
   del referente. En reposo, 133deg — el ángulo del gradient_beige del kit. */
.cifra {
  background: linear-gradient(calc(var(--chase, 133) * 1deg), #FEFEFE 55%, var(--lavado, #F3EFE9));
  border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  padding: 28px 30px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  transition: border-color .3s ease-out;   /* nunca transition: all */
}

/* Al hover el borde toma el tinte de la tarjeta (sin lift: decisión del
   sistema — el color hace el trabajo). Si el navegador no conoce
   color-mix, la declaración se descarta y el borde queda en --c-line. */
.cifra:hover { border-color: color-mix(in srgb, var(--tinte, #0095CF) 40%, transparent); }

.cifra--lider {
  grid-row: 1 / 4;
  border-radius: var(--r-lg);
  padding: 40px;
  justify-content: space-between;
  gap: 28px;
  background: linear-gradient(calc(var(--chase, 133) * 1deg), #FEFEFE 45%, var(--lavado, #F3EFE9));
}

/* Chip del ícono: r9 (el radio de chips del censo del referente), lavado del
   color de su tarjeta. El SVG lleva el padding adentro. */
.cifra__ico {
  color: var(--tinte, var(--c-cyan));
  background: var(--tinte-suave, #E0F2FA);
  border-radius: var(--r-sm);
  width: 54px;
  height: 54px;
  padding: 13px;
  box-sizing: border-box;
  margin-bottom: 22px;
}
.cifra--lider .cifra__ico { margin-bottom: 0; width: 64px; height: 64px; padding: 15px; }

/* Capa duotono de los íconos: relleno del color al 12%. */
.cifra__ico .duo { opacity: .12; }

/* Filete de 4px (la puntuación tipográfica del referente: alto 4, radio 100)
   en el tinte de la tarjeta; crece al hover por transform (compositado). */
.cifra > div::before {
  content: '';
  display: block;
  width: 34px;
  height: 4px;
  border-radius: 100px;
  background: var(--tinte, var(--c-cyan));
  margin-bottom: 14px;
  transform-origin: left center;
  transition: transform .3s ease-out;
}
.cifra:hover > div::before { transform: scaleX(1.65); }

/* Dibujado de los trazos (.tz, con pathLength=1): sólo con JS vivo — sin él
   no hay is-in y los íconos deben verse completos desde el primer pintado.
   Cascada: cada tarjeta arranca con el stagger del sistema (200ms), y el
   relleno duotono aparece cuando su trazo ya va a medio camino. */
.js .cifras__grid .cifra__ico .tz { stroke-dasharray: 1; }
.js .cifras__grid:not(.is-in) .cifra__ico .tz { stroke-dashoffset: 1; }
.js .cifras__grid:not(.is-in) .cifra__ico .duo { opacity: 0; }
.js .cifras__grid.is-in .cifra__ico .tz { animation: trazoDibuja 900ms ease-out both; }
.js .cifras__grid.is-in .cifra__ico .duo { animation: duoAparece 500ms ease-out both; }

.js .cifras__grid.is-in .cifra:nth-child(2) .cifra__ico .tz,
.js .cifras__grid.is-in .cifra:nth-child(2) .cifra__ico .duo { animation-delay: .2s; }
.js .cifras__grid.is-in .cifra:nth-child(3) .cifra__ico .tz,
.js .cifras__grid.is-in .cifra:nth-child(3) .cifra__ico .duo { animation-delay: .4s; }
.js .cifras__grid.is-in .cifra:nth-child(4) .cifra__ico .tz,
.js .cifras__grid.is-in .cifra:nth-child(4) .cifra__ico .duo { animation-delay: .6s; }
/* El duo espera además el medio camino de su trazo. */
.js .cifras__grid.is-in .cifra__ico .duo { animation-duration: 500ms; animation-delay: .45s; }
.js .cifras__grid.is-in .cifra:nth-child(2) .cifra__ico .duo { animation-delay: .65s; }
.js .cifras__grid.is-in .cifra:nth-child(3) .cifra__ico .duo { animation-delay: .85s; }
.js .cifras__grid.is-in .cifra:nth-child(4) .cifra__ico .duo { animation-delay: 1.05s; }

@keyframes trazoDibuja {
  from { stroke-dashoffset: 1; }
  to   { stroke-dashoffset: 0; }
}
@keyframes duoAparece {
  from { opacity: 0; }
  to   { opacity: .12; }
}

@media (prefers-reduced-motion: reduce) {
  .js .cifras__grid .cifra__ico .tz {
    animation: none;
    stroke-dasharray: none;
    stroke-dashoffset: 0;
  }
  .js .cifras__grid .cifra__ico .duo { animation: none; opacity: .12; }
}

.cifra__n {
  font-size: clamp(2.1rem, 1.5rem + 1.9vw, 3rem);
  line-height: 1;
  margin-bottom: 8px;
  font-variant-numeric: tabular-nums;
}

/* La cifra insignia, a escala display (peso 400: la elegancia sale del
   tamaño). tabular-nums: los dígitos del contador no deben bailar.
   El número lleva el degradado cian→marino recortado al texto: la única
   licencia cromática grande de la sección, en la familia de la marca. */
.cifra--lider .cifra__n {
  font-size: clamp(4.2rem, 3rem + 4vw, 6.8rem);
  margin-bottom: 12px;
  background: linear-gradient(115deg, var(--c-cyan) 10%, var(--c-marine) 85%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.cifra__l { font-size: .98rem; color: var(--c-muted); text-wrap: balance; }
.cifra--lider .cifra__l { font-size: 1.05rem; color: var(--c-dark); }

.cifra__apoyo {
  font-size: .95rem;
  color: var(--c-muted);
  margin-top: 10px;
  max-width: 34ch;
  text-wrap: pretty;
}

/* Atribuir una cifra cuesta una línea y convierte una afirmación publicitaria
   en un dato declarado. Para una empresa que gestiona fondos públicos, esa
   diferencia importa. */
.cifras__fuente {
  grid-column: 1 / -1;
  margin-top: 20px;
  font-size: .94rem;
  color: var(--c-muted-fuerte);
}

/* El énfasis del sistema es por COLOR, no por peso: el 700 sobre un texto ya
   atenuado al 70% destacaba menos que el párrafo que lo rodea. */
.cifras__apoyo strong { font-weight: 400; color: var(--c-light); }

/* --------------------------------------------------------------------------
   10. Proceso — "el camino"
   Las 4 etapas dejaron de ser columnas sueltas (2026-07-25): ahora son
   estaciones de un riel continuo que va del cian al marino, la misma
   escala "profundidades del mar" de Fondos §13. El riel se dibuja dentro
   de cada parada, nunca en el contenedor: `.parada__riel` es una fila de
   altura fija (14px), así el punto y el tramo caen siempre a la misma
   altura aunque el número de arriba cambie de tamaño con el viewport.
   Contrastes sobre el blanco de la sección: los tintes pintan SOLO los
   números (texto grande, 4.17→11.45:1) y los puntos del riel; los títulos
   van en --c-dark (16.9:1) y los textos en --c-muted (4.75:1).
   -------------------------------------------------------------------------- */

.camino {
  --gap-camino: 32px;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gap-camino);
}

/* Cada parada hereda su tinte y el de la siguiente: el tramo de riel es un
   degradado entre ambos, así el color del camino avanza sin costuras. */
.camino > :nth-child(1) { --tinte: #0084B8; --tinte-sig: #036C98; }
.camino > :nth-child(2) { --tinte: #036C98; --tinte-sig: #075577; }
.camino > :nth-child(3) { --tinte: #075577; --tinte-sig: #0A3D57; }
.camino > :nth-child(4) { --tinte: #0A3D57; --tinte-sig: #0A3D57; }

.parada { position: relative; }

.parada__n {
  display: block;
  font-size: clamp(2.4rem, 1.9rem + 1.6vw, 3.4rem);
  font-weight: 400;
  line-height: 1;
  color: var(--tinte, var(--c-marine));
  font-variant-numeric: tabular-nums;
}

.parada__riel {
  display: block;
  position: relative;
  height: 14px;
  margin: 20px 0 22px;
}

/* La estación. */
.parada__riel::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: 14px;
  height: 14px;
  margin-top: -7px;
  border-radius: 50%;
  background: var(--tinte, var(--c-marine));
  transition: transform var(--t);
}

/* El tramo hasta la estación siguiente: se estira sobre el gap (de ahí el
   right negativo) para que el riel se lea continuo entre columnas. */
.parada__riel::after {
  content: '';
  position: absolute;
  left: 22px;
  top: 50%;
  right: calc(-1 * var(--gap-camino));
  height: 2px;
  margin-top: -1px;
  background: linear-gradient(90deg, var(--tinte), var(--tinte-sig));
}

.parada:last-child .parada__riel::after { display: none; }

@media (hover: hover) {
  .parada:hover .parada__riel::before { transform: scale(1.45); }
}

.parada__titulo {
  font-size: 1.2rem;
  color: var(--c-dark);
  margin-bottom: 8px;
}

.parada__texto { font-size: 1rem; color: var(--c-muted); }

/* El destino: cierra el riel con una estación marina del mismo tamaño. */
.camino__cierre {
  margin-top: 56px;
  padding-top: 30px;
  border-top: 1px solid var(--c-line);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
}

.camino__destino {
  display: flex;
  /* Arriba, no al centro: si el texto envuelve (celular), un punto centrado
     entre las dos líneas se lee desalineado del comienzo de la frase. */
  align-items: flex-start;
  gap: 14px;
  font-size: 1.05rem;
  color: var(--c-muted);
}

.camino__destino strong { font-weight: 400; color: var(--c-marine); }

.camino__nodo {
  flex: none;
  width: 14px;
  height: 14px;
  margin-top: 5px;        /* centra el punto en la PRIMERA línea */
  border-radius: 50%;
  background: var(--c-marine);
}

/* Responsive del camino, autocontenido (como Fondos §13 y Modelo §8): a dos
   columnas el riel no puede saltar de fila, así que el tramo de las paradas
   pares se corta; en celular el camino se pone de pie y el riel baja por la
   izquierda. */
@media (max-width: 1080px) {
  .camino { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 44px var(--gap-camino); }
  .parada:nth-child(2n) .parada__riel::after { display: none; }
}

@media (max-width: 720px) {
  .camino { grid-template-columns: 1fr; gap: 0; }

  .parada {
    padding-left: 40px;
    padding-bottom: 34px;
  }
  .parada:last-child { padding-bottom: 0; }

  .parada__n { font-size: 2rem; }

  /* El riel pasa a vertical: ocupa el alto completo de la parada, con la
     estación arriba y el tramo bajando hasta la siguiente. */
  .parada__riel {
    position: absolute;
    left: 0;
    top: 6px;
    width: 14px;
    height: calc(100% - 6px);
    margin: 0;
  }
  .parada__riel::before { top: 0; margin-top: 0; }
  .parada__riel::after {
    left: 6px;
    top: 22px;
    right: auto;
    bottom: 0;
    width: 2px;
    height: auto;
    margin-top: 0;
    background: linear-gradient(180deg, var(--tinte), var(--tinte-sig));
  }
  /* En vertical el riel SÍ continúa en las pares: revierte la regla de dos
     columnas, que también alcanza a este breakpoint. */
  .parada:nth-child(2n) .parada__riel::after { display: block; }
  .parada:last-child .parada__riel::after { display: none; }

  .camino__cierre { margin-top: 44px; }
}

/* --------------------------------------------------------------------------
   11. Servicios — las cinco familias
   El slider de catorce tarjetas se retiró (2026-07-25): obligaba a deslizar
   varias veces y las familias (Seguridad, Energía, Agua, Espacio público,
   Comunidad) sólo existían como etiqueta suelta dentro de cada tarjeta.
   Ahora cada familia encabeza su propia fila —nombre en su tinte de la
   escala azul de Fondos, filete y conteo— y sus servicios van al lado en
   tarjetas blancas sobre la arena. Se lee como un índice: el dirigente
   ubica su necesidad sin gesto previo. Con 2 servicios (Espacio público)
   la fila deja un hueco a la derecha a propósito: las tarjetas conservan
   el mismo ancho en todas las familias.
   -------------------------------------------------------------------------- */

.familia {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  gap: 44px;
  margin-top: 40px;
  padding-top: 40px;
  border-top: 1px solid var(--c-sand-deep);
}

/* La primera familia arranca pegada al encabezado de sección, sin filete
   de separación: no hay nada antes de qué separarla. */
.servicios .familia:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }

.servicios .familia:nth-of-type(1) { --tinte: #0084B8; }
.servicios .familia:nth-of-type(2) { --tinte: #036C98; }
.servicios .familia:nth-of-type(3) { --tinte: #056088; }
.servicios .familia:nth-of-type(4) { --tinte: #075577; }
.servicios .familia:nth-of-type(5) { --tinte: #0A3D57; }

.familia__filete {
  display: block;
  width: 34px;
  height: 4px;
  margin-bottom: 18px;
  border-radius: 100px;
  background: var(--tinte, var(--c-cyan));
}

/* Peso 400 como todo el sistema: la jerarquía la da el tamaño y el tinte.
   Sobre arena, los cinco tintes van de 3.51:1 (el más claro) a 9.63:1 —
   todos por encima del 3:1 que pide WCAG para texto grande. */
.familia__nombre {
  font-size: clamp(1.5rem, 1.24rem + .8vw, 2rem);
  line-height: 1.1;
  color: var(--tinte, var(--c-marine));
}

.familia__conteo {
  margin-top: 8px;
  font-size: .94rem;
  color: var(--c-muted-fuerte);   /* --c-muted falla AA aquí: ver tokens */
}

.familia__items {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

/* Plegado nativo <details>/<summary> (2026-07-26): a 375px Servicios medía 8,5
   pantallas (36% de la página) con las cinco familias siempre abiertas — las
   catorce fotos apiladas empujaban Cobertura, Fondos y Contacto fuera del
   alcance realista de una visita en celular. En escritorio nada cambia
   (las cinco quedan abiertas, ver js/main.js); en celular sólo la primera.
   El marcador triangular nativo no encaja con el sistema: se retira y se
   dibuja un chevron propio, que sólo se ve en celular (en escritorio no hace
   falta, ahí summary no es interactivo a la vista). */
.familia > summary { list-style: none; cursor: default; }
.familia > summary::-webkit-details-marker { display: none; }

.familia__chevron { display: none; }

@media (max-width: 720px) {
  .familia > summary {
    cursor: pointer;
    /* Ancla para el chevron absoluto de abajo. El filete/nombre/conteo NO
       se tocan: siguen en su apilado vertical original (bloque), sólo se
       les reserva aire a la derecha para que el chevron no les monte encima. */
    position: relative;
    padding-right: 28px;
    /* blanco tactil holgado para toda la fila de encabezado */
    min-height: 56px;
  }

  .familia__chevron {
    display: block;
    position: absolute;
    right: 0;
    top: 50%;
    width: 12px;
    height: 12px;
    border-right: 2px solid var(--c-cyan);
    border-bottom: 2px solid var(--c-cyan);
    transition: transform var(--t);
    transform: translateY(-50%) rotate(45deg);
  }

  .familia[open] .familia__chevron { transform: translateY(-50%) rotate(-135deg); }
}

@media (prefers-reduced-motion: reduce) {
  .familia__chevron { transition: none; }
}

/* Medido en vivo: una familia CERRADA sigue generando una segunda fila de
   grid para .familia__items (el navegador la reduce a 0px de alto, pero la
   fila existe) y el "gap" de la grilla se cobra igual entre dos filas
   existentes, aunque la segunda mida 0 — 22px por familia cerrada, sin
   ningún contenido visible que separar. Con las cuatro familias cerradas de
   celular, eran 88px regalados que empujaban Servicios de 2,97 a 3,08
   pantallas. Puesto fuera del media query: también corrige el caso borde de
   un summary cerrado a mano en escritorio. */
.familia:not([open]) { gap: 0; }

/* Tarjeta: la foto NO va a sangre (2026-07-25) sino montada como una lámina
   dentro de la tarjeta — margen uniforme de 14px y radio propio. Los radios
   son concéntricos: 28 fuera, 14 dentro (28 − 14 de margen), que es la resta
   exacta; con dos radios iguales o al azar la esquina se ve deformada. Es el
   gesto que separa una tarjeta de catálogo de una de producto. Sin sombra ni
   lift: el borde y el contraste blanco/arena hacen el trabajo. */
.serv {
  display: flex;
  flex-direction: column;
  background: var(--c-light);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  padding: 14px;
  transition: border-color var(--t);
}

/* El hover tiñe el borde y estira el filete de la familia. El TÍTULO no se
   tiñe: los tintes claros de la escala (#0084B8 = 4.17:1 sobre blanco) no
   alcanzan el 4.5:1 que pide texto de este tamaño. */
@media (hover: hover) {
  .serv:hover { border-color: var(--tinte, var(--c-cyan)); }
  .serv:hover .serv__media img { transform: scale(1.05); }
  .serv:hover .serv__filete { transform: scaleX(1.65); }
}

.serv__media {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 14px;
  overflow: hidden;         /* recorta el zoom de la foto al radio interior */
}

/* display:contents disuelve la caja del <picture> intermedio (mismo motivo
   que .hero__media picture, §7): el <img> de abajo usa height:100%, y un
   <picture> normal mide su alto por contenido (auto), no por el padre — ese
   porcentaje no tiene contra qué resolverse. Medido en vivo: sin esto el
   <img> pasa de 217px a 389px de alto (su proporción NATURAL 800×1072) y
   desborda el recorte 4/3, que el overflow:hidden del padre recorta desde
   arriba en vez del cubrimiento centrado que da object-fit:cover. */
.serv__media picture { display: contents; }

.serv__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s ease-in-out;
}

/* Sólo cuatro tarjetas llevan clip. Arranca en opacidad 0 sobre su propia
   foto: si el MP4 falta o no reproduce, la imagen queda intacta. */
.serv__clip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--t);
}

.serv__clip.is-on { opacity: 1; }

/* El filete de la familia, el mismo recurso 34×4 r100 que puntúa Cifras,
   Modelo, Fondos y Cobertura: es lo que ata la tarjeta a su familia sin
   necesidad de repetir la etiqueta de categoría. */
.serv__filete {
  display: block;
  width: 34px;
  height: 4px;
  margin: 20px 0 0 6px;
  border-radius: 100px;
  background: var(--tinte, var(--c-cyan));
  transform-origin: left center;
  transition: transform .3s ease-out;
}

.serv__body { padding: 14px 6px 6px; }

.serv__titulo {
  font-size: 1.16rem;
  font-weight: 400;
  line-height: 1.25;
  color: var(--c-dark);
  margin-bottom: 8px;
}

.serv p { font-size: .95rem; color: var(--c-muted); }

/* Tablet: el encabezado de familia se pone encima de sus tarjetas y éstas
   pasan a dos columnas. */
@media (max-width: 1080px) {
  .familia {
    grid-template-columns: 1fr;
    gap: 26px;
    margin-top: 36px;
    padding-top: 36px;
  }
  .familia__filete { margin-bottom: 14px; }
  .familia__items { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .familia { gap: 22px; margin-top: 32px; padding-top: 32px; }
  .familia__items { grid-template-columns: 1fr; gap: 14px; }
}

/* --------------------------------------------------------------------------
   12. Cobertura — el territorio
   El split 50/50 con la foto y las comunas como chips de arena se retiró
   (2026-07-25). Ahora manda la lista: las quince comunas en tipografía
   legible, agrupadas en tres columnas por provincia y en su orden
   geográfico real de norte a sur. Los tintes son tres pasos de la escala
   azul (los mismos extremos que Fondos y el camino de Proceso), y la
   fotografía pasa a banda de cierre como en Modelo. Contrastes sobre el
   blanco de la sección: los tintes pintan sólo nombres de provincia (texto
   grande, 4.17→11.45:1) y filetes; las comunas van en --c-dark.
   -------------------------------------------------------------------------- */

.cobertura__head { max-width: 46rem; }

.cobertura h2 { margin-bottom: 22px; }

.cobertura__lede {
  color: var(--c-muted);          /* 4.75:1 sobre blanco */
  font-size: 1.15rem;
  max-width: 52ch;
}

/* El dato de cobertura, antes en una ficha flotante sobre la foto (la única
   sombra suelta de la página). Ahora abre la sección, sin caja. */
.cobertura__cifras {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 56px;
  margin-top: 44px;
  padding-bottom: 40px;
  border-bottom: 1px solid var(--c-line);
}

.cobertura__cifras li {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.cobertura__cifras b {
  font-size: clamp(2rem, 1.6rem + 1.4vw, 2.8rem);
  font-weight: 400;               /* jerarquía por tamaño, nunca por peso */
  line-height: 1;
  color: var(--c-marine);
  font-variant-numeric: tabular-nums;
}

.cobertura__cifras span { font-size: 1rem; color: var(--c-muted); }

.provincias {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 40px 32px;
  margin-top: 48px;
}

.provincias > :nth-child(1) { --tinte: #0084B8; }
.provincias > :nth-child(2) { --tinte: #056088; }
.provincias > :nth-child(3) { --tinte: #0A3D57; }

.prov__filete {
  display: block;
  width: 34px;
  height: 4px;
  margin-bottom: 18px;
  border-radius: 100px;
  background: var(--tinte, var(--c-cyan));
}

.prov__nombre {
  font-size: clamp(1.5rem, 1.24rem + .8vw, 2rem);
  line-height: 1.1;
  color: var(--tinte, var(--c-marine));
}

.prov__conteo {
  margin-top: 6px;
  font-size: .94rem;
  color: var(--c-muted);
}

/* Las comunas, que es lo que el visitante viene a buscar: tipografía de
   lectura, no chips de formulario. Hairline entre cada una para que la
   columna se lea como un listado ordenado. */
.prov__comunas { margin-top: 22px; }

.prov__comunas li {
  padding: 13px 0;
  border-top: 1px solid var(--c-line);
  font-size: 1.1rem;
  color: var(--c-dark);
}

.prov__comunas li:last-child { border-bottom: 1px solid var(--c-line); }

/* La sede no se marca con un fondo de color: se marca diciéndolo. */
.prov__comunas .es-sede { color: var(--c-marine); }

.prov__comunas .es-sede span {
  display: inline-block;
  margin-left: 8px;
  padding: 3px 10px;
  border-radius: var(--r-sm);
  background: var(--c-sand);
  font-size: .94rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--c-muted-fuerte);   /* 5.38:1 sobre arena */
  vertical-align: 2px;
}

.cobertura__banda { margin-top: 64px; }

.cobertura__banda img {
  width: 100%;
  height: auto;        /* sin esto, el atributo height del HTML anula aspect-ratio */
  aspect-ratio: 21 / 9;
  object-fit: cover;
  border-radius: var(--r-lg);
}

@media (max-width: 1080px) {
  .provincias { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px 28px; }
  .cobertura__cifras { gap: 14px 40px; margin-top: 36px; }
  .cobertura__banda { margin-top: 52px; }
}

@media (max-width: 720px) {
  .provincias { grid-template-columns: 1fr; gap: 34px; margin-top: 40px; }
  .cobertura__cifras { gap: 12px 32px; }
  .cobertura__banda { margin-top: 44px; }
  .cobertura__banda img { aspect-ratio: 16 / 10; }
}

/* --------------------------------------------------------------------------
   13. Financiamiento — "El expediente"
   Lista editorial vertical: 9 filas que descienden del cian al marino
   ("profundidades del mar", la familia azul de las cifras, oscurecida para
   pasar WCAG AA sobre arena: el cian puro #0095CF da 2.82:1 y quedó fuera).
   El tinte pinta SOLO el número XXL (texto grande: 3.51–9.63:1, todos ≥3:1
   en reposo sobre arena y en hover sobre blanco) y el filete decorativo.
   Jerarquía por escala, nunca por peso. Sin sombras. El tinte va por
   nth-child: el descenso es POSICIONAL — pertenece a la fila, no al fondo.
   -------------------------------------------------------------------------- */

/* La escala se re-espació al pasar de 7 a 9 filas (2026-07-25, entran fondos
   municipales y royalty minero): mismos dos extremos —#0084B8 y --c-marine—
   repartidos ahora en 9 pasos iguales. El extremo claro NO cambió, así que el
   contraste sigue anclado donde ya estaba medido; las demás filas solo se
   oscurecen, que es la dirección segura sobre arena. */
.fondos__lista > :nth-child(1) { --tinte: #0084B8; }
.fondos__lista > :nth-child(2) { --tinte: #017BAC; }
.fondos__lista > :nth-child(3) { --tinte: #0372A0; }
.fondos__lista > :nth-child(4) { --tinte: #046994; }
.fondos__lista > :nth-child(5) { --tinte: #056188; }
.fondos__lista > :nth-child(6) { --tinte: #06587B; }
.fondos__lista > :nth-child(7) { --tinte: #084F6F; }
.fondos__lista > :nth-child(8) { --tinte: #094663; }
.fondos__lista > :nth-child(9) { --tinte: #0A3D57; }   /* = --c-marine: ancla en el token */

.fondo {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: clamp(28px, 4vw, 64px);
  align-items: start;
  padding: 34px 36px;                    /* ≥ r-lg: el contenido no roza las esquinas del hover */
  border-radius: var(--r-lg);
  transition: background-color .3s ease-out;
}

/* Hover escritorio: la fila "se enciende" en blanco. Solo con puntero real:
   en táctil el :hover queda pegado tras el tap y la fila no es un enlace. */
@media (hover: hover) {
  .fondo:hover { background: var(--c-light); }
  .fondo:hover .fondo__filete { transform: scaleX(1.65); }
}

/* Hairline entre filas, insetado al padding e independiente del radio del
   hover (un border-top se curvaría con r28). */
.fondo + .fondo::before {
  content: '';
  position: absolute;
  top: 0;
  left: 36px;
  right: 36px;
  border-top: 1px solid var(--c-line);
}

/* Número XXL: la escala del h2, peso 400 — jerarquía por tamaño, nunca
   por peso. Tabular para que 01–07 midan lo mismo y la columna no baile. */
.fondo__num {
  font-size: clamp(2.7rem, 1.95rem + 2.542vw, 5rem);
  font-weight: 400;
  line-height: .95;
  font-variant-numeric: tabular-nums;
  color: var(--tinte, var(--c-marine));
}

/* Filete 4px, radio 100: la puntuación tipográfica del referente, idéntica
   a la de las cifras (34×4, crece al hover por transform, compositado). */
.fondo__filete {
  display: block;
  width: 34px;
  height: 4px;
  border-radius: 100px;
  background: var(--tinte, var(--c-cyan));
  margin-bottom: 16px;
  transform-origin: left center;
  transition: transform .3s ease-out;
}

/* Sigla en la escala del h4 del sistema; marino, no el tinte (9.63:1). */
.fondo__sigla {
  font-size: clamp(1.8rem, 1.583rem + .764vw, 2.5rem);
  line-height: 1.1;
  color: var(--c-marine);
}

.fondo__nombre {
  margin-top: 10px;
  font-size: 1.06rem;
  color: var(--c-dark);
}

/* Tinta suave PROPIA del bloque: --c-muted da 3.99:1 sobre arena y falla
   AA; este gris pasa en reposo (5.38) y en hover sobre blanco (6.40). */
.fondo__detalle {
  margin-top: 4px;
  font-size: .95rem;
  color: var(--c-muted-fuerte);
}

/* Chip de institución: uppercase corto, r9. Marino en ambos estados
   (9.63 / 11.45); borde solo decorativo. */
.fondo__inst {
  align-self: center;
  padding: 7px 14px;
  border: 1px solid var(--c-sand-deep);
  border-radius: var(--r-sm);
  font-size: .94rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--c-marine);
  white-space: nowrap;
}

/* Cierre: empuja a contacto sin repetir la oferta (contacto ya dice
   "gratis"). El hover del enlace baja a un azul de la escala que pasa
   AA-normal sobre arena (4.86). */
.fondos__cierre {
  margin-top: 40px;
  padding-inline: 36px;
  font-size: 1.05rem;
  color: var(--c-muted-fuerte);
  max-width: 62ch;
}

.fondos__cierre a {
  color: var(--c-marine);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color var(--t);
}
.fondos__cierre a:hover { color: #036C98; }

@media (max-width: 1080px) {
  .fondo { padding: 30px 28px; }
  .fondo + .fondo::before { left: 28px; right: 28px; }
  .fondos__cierre { padding-inline: 28px; }
}

/* Móvil: lista apilada simple, sin hover (lo resuelve (hover: hover)),
   número menor, chip bajo el texto. Sin acordeón, sin JS. */
@media (max-width: 720px) {
  .fondo {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 18px;
    padding: 26px 2px;
    border-radius: 0;
  }

  .fondo + .fondo::before { left: 0; right: 0; }

  .fondo__num { font-size: 2rem; line-height: 1.2; }

  .fondo__filete { margin-bottom: 12px; }

  .fondo__sigla { font-size: 1.5rem; }

  .fondo__inst {
    grid-column: 2;
    justify-self: start;
    align-self: start;
    margin-top: 14px;
  }

  .fondos__cierre { padding-inline: 2px; margin-top: 32px; }
}

/* --------------------------------------------------------------------------
   13b. Páginas web — la otra línea de trabajo
   Banda breve entre Financiamiento (arena) y Contacto (marino), en BLANCO
   para conservar la alternancia de superficies. (La sección Requisitos que
   vivía aquí al lado se retiró el 2026-08-01 a pedido del cliente: los
   requisitos varían según cada proyecto.) Mismo lenguaje de fichas planas
   que .punto (§8) y .parada (§10). Los grises quedan en --c-muted-fuerte:
   sobre blanco también es el gris seguro (6.40:1), no hay que tocarlos.
   -------------------------------------------------------------------------- */

.pweb__puntos {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 48px 40px;
}

.pweb__filete {
  display: block;
  width: 34px;
  height: 4px;
  border-radius: 100px;
  background: var(--c-cyan);
  margin-bottom: 20px;
}

.pweb__titulo {
  font-size: 1.24rem;
  letter-spacing: -.02em;
  margin-bottom: 8px;
}

.pweb__texto { color: var(--c-muted-fuerte); max-width: 34ch; }

.pweb__cta {
  display: flex;
  align-items: center;
  gap: 28px;
  margin-top: 64px;
}

.pweb__nota { color: var(--c-muted-fuerte); max-width: 44ch; }

/* Tres fichas: bajo 900px pasan directo a columna única — con número impar,
   el paso intermedio a dos columnas dejaría una ficha huérfana. */
@media (max-width: 900px) {
  .pweb__puntos { grid-template-columns: 1fr; gap: 36px; }
}

@media (max-width: 720px) {
  .pweb__cta { margin-top: 44px; flex-direction: column; align-items: flex-start; gap: 16px; }
}

/* --------------------------------------------------------------------------
   14. Contacto — dos puertas
   El cierre de la página rima con Cifras: mismo anochecer marino (degradado
   145° + luces del pueblo, componente .luces compartido). Dos caminos
   explícitos en vez de un split con el formulario mandando: a la izquierda
   el teléfono a escala display —lo que el ICP realmente usa— y a la
   derecha el formulario en tarjeta clara.
   -------------------------------------------------------------------------- */

.contacto {
  position: relative;
  overflow: hidden;
  background: linear-gradient(145deg, #0D4A6B 0%, var(--c-marine) 48%, var(--c-marine-deep) 100%);
}

/* Las luces se anclan arriba a la derecha, lejos del formulario: aquí sólo
   titilan (el modo errático al hover vive sólo en el panel de Cifras: una
   sección entera reaccionando al cursor sería ruido). */
.contacto__luces {
  position: absolute;
  right: -20px;
  top: -10px;
  width: 380px;
  height: auto;
  pointer-events: none;
  z-index: 0;
}

.contacto .wrap { position: relative; z-index: 1; }

.contacto__head { max-width: 46rem; margin-bottom: 56px; }

.contacto h2 { margin-bottom: 24px; }

.contacto__lede {
  color: rgba(254, 254, 254, .74);
  font-size: 1.15rem;
  max-width: 46ch;
}

/* stretch, no start: la tarjeta del formulario es bastante más alta que la
   columna del teléfono, y con align-items:start ésta dejaba medio metro de
   marino vacío debajo. Estirándola, los datos de apoyo bajan al pie y las
   dos puertas terminan a la misma altura. */
.contacto__puertas {
  display: grid;
  grid-template-columns: minmax(0, .85fr) minmax(0, 1fr);
  gap: 24px;
  align-items: stretch;
}

/* Etiqueta común a las dos puertas: nombra el camino antes de mostrarlo. */
.puerta__label {
  font-size: .94rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  margin-bottom: 22px;
}

.puerta--directa {
  display: flex;
  flex-direction: column;
  padding: 8px 4px 0;
}
.puerta--directa .puerta__label { color: rgba(254, 254, 254, .78); }  /* 4.04 → 6.6:1 */

/* El teléfono es la pieza mayor de la sección: escala de titular, peso 400
   —la jerarquía la da el tamaño— y tabular para que los dígitos no bailen.
   Es enlace tel:, así que en celular abre el marcador de una. */
.puerta__fono {
  display: inline-flex;
  align-items: center;
  /* min-height + padding: el número es texto grande pero su CAJA táctil era
     de 35px. En celular es el enlace más importante de la página. */
  min-height: 56px;
  padding: 6px 0;
  font-size: clamp(2rem, 1.3rem + 2.4vw, 3.1rem);
  line-height: 1.1;
  color: var(--c-light);
  font-variant-numeric: tabular-nums;
  transition: color var(--t);
}

.puerta__fono:hover { color: #7FD1F2; }

/* align-self: la columna es flex, y sin esto el botón se estiraría a todo
   su ancho (medio metro de botón en escritorio). */
.puerta__wa { margin-top: 28px; align-self: flex-start; }

.puerta__nota {
  margin-top: 18px;
  font-size: .95rem;
  color: rgba(254, 254, 254, .6);
}

/* Correo y base: datos de apoyo, en hairlines como el resto del sistema.
   El margin-top:auto los ancla al pie de la columna (ver el stretch de
   .contacto__puertas). */
.puerta__datos {
  margin-top: auto;
  padding-top: 40px;
  display: grid;
  gap: 2px;
}

.puerta__datos li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
  padding: 16px 0;
  border-top: 1px solid var(--c-line-light);
}

.puerta__datos li:last-child { border-bottom: 1px solid var(--c-line-light); }

.puerta__datos span {
  flex: none;
  min-width: 74px;
  font-size: .94rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(254, 254, 254, .72);   /* 3.62 → 5.9:1 */
}

.puerta__datos strong { font-weight: 400; font-size: 1.02rem; }

/* El correo es un método de contacto, no un dato decorativo: necesita el
   mismo blanco táctil de 44px que ya tienen el teléfono y el pie. Su caja
   medía 24px, que es fallar el objetivo con el dedo. */
.puerta__datos a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: 1.02rem;
  color: var(--c-light);
  transition: color var(--t);
}

.puerta__datos a:hover { color: #7FD1F2; }

/* Puerta 2: tarjeta clara. El formulario deja de ser campos translúcidos
   sobre el fondo y pasa a leerse como un documento sobre la mesa. */
.puerta--form {
  background: var(--c-light);
  border-radius: var(--r-lg);
  padding: 34px 32px 32px;
}

/* Puerta 2 es una tarjeta blanca DENTRO de la sección marina: sin esto, sus
   campos y el botón heredan el anillo blanco de ".section--marine" y quedan
   blanco sobre blanco, invisibles. Selector más específico que esa regla
   para ganar siempre, sin depender del orden en la hoja. */
.puerta--form input:focus-visible,
.puerta--form select:focus-visible,
.puerta--form textarea:focus-visible,
.puerta--form button:focus-visible {
  outline-color: var(--c-cyan);
}

.puerta--form .puerta__label { color: var(--c-muted-fuerte); }

/* Formulario */
.form { display: grid; gap: 16px; }

.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

.field { display: grid; gap: 8px; }

.field label {
  font-size: .94rem;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--c-muted-fuerte);          /* 6.40:1 sobre blanco */
}

.field input, .field select, .field textarea {
  padding: 15px 17px;
  border-radius: var(--r-sm);
  border: 1px solid var(--c-line);
  background: #FAF9F7;     /* un punto de arena: el campo se ve hundido */
  color: var(--c-dark);
  font-size: 1rem;
  letter-spacing: -.02em;
  transition: border-color var(--t), background var(--t);
}

.field input::placeholder, .field textarea::placeholder { color: #8A9096; }

/* El borde cian de 1px se conserva como señal de color, pero ya no es el
   ÚNICO indicador: la regla global de :focus-visible pone además el anillo. */
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible {
  border-color: var(--c-cyan);
  background: var(--c-light);
}

.field textarea { resize: vertical; min-height: 104px; }

.form .btn { justify-content: center; margin-top: 4px; }

.form__note { font-size: .95rem; color: var(--c-muted-fuerte); }

/* Sin JavaScript el formulario no puede armar el mensaje de WhatsApp — el
   submit recargaría la página con el nombre y el teléfono del vecino
   expuestos en la URL, sin enviar nada. Así que sin JS el formulario se
   retira y este aviso ofrece las dos vías directas (patrón .js, como el
   revelado progresivo). */
html:not(.js) .form { display: none; }
.js .form__sinjs { display: none; }
.form__sinjs { font-size: 1rem; color: var(--c-dark); }
.form__sinjs a { text-decoration: underline; }

.form__ok {
  display: none;
  padding: 15px 18px;
  border-radius: var(--r-sm);
  background: rgba(0, 149, 207, .1);
  border: 1px solid var(--c-cyan);
  color: var(--c-dark);
  font-size: .96rem;
}
.form__ok.is-visible { display: block; }

@media (max-width: 1080px) {
  .contacto__puertas { grid-template-columns: 1fr; gap: 34px; }
  .contacto__head { margin-bottom: 44px; }
  .contacto__luces { width: 300px; right: -40px; }
  .puerta--directa { padding: 0; }
  .puerta__datos { margin-top: 32px; }
}

@media (max-width: 720px) {
  .contacto__luces { width: 240px; right: -50px; top: -20px; }
  .puerta--form { padding: 26px 22px 24px; }
  /* Dos columnas de campos no caben con holgura en 375px. */
  .form__row { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   15. Pie de página
   -------------------------------------------------------------------------- */

.footer {
  background: var(--c-marine-deep);
  color: rgba(254, 254, 254, .62);
  padding-block: 72px 40px;
  font-size: .95rem;
}

.footer__top {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
  gap: 48px;
  padding-bottom: 44px;
  border-bottom: 1px solid rgba(254, 254, 254, .12);
}

.footer__logo { height: 28px; width: auto; filter: brightness(0) invert(1); margin-bottom: 20px; }

.footer__blurb { max-width: 40ch; }

/* Antes era un h6 y saltaba desde los h2 del contenido (escalón que el lector
   de pantalla anuncia); ahora es un h2 con este rótulo. El .94rem respeta el
   piso de 15px del sistema (los .82rem eran 13,9px). */
.footer__rotulo {
  font-size: .94rem;
  font-weight: 400;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--c-light);
  margin-bottom: 16px;
}

/* El reset sólo quita viñetas a ul[class]; estas listas no llevan clase. */
.footer ul { display: grid; gap: 2px; list-style: none; }

/* Los ítems del pie eran blancos de 22px. Se les da altura de dedo sin
   cambiar el ritmo visual: el gap baja de 10 a 2 y el alto lo pone el padding. */
.footer li { display: flex; align-items: center; min-height: 44px; }
.footer li a { display: flex; align-items: center; width: 100%; min-height: 44px; }

.footer a { transition: color var(--t); }
.footer a:hover { color: var(--c-light); }

.footer__bottom {
  padding-top: 26px;
  display: flex;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  font-size: .95rem;
  color: rgba(254, 254, 254, .6);    /* 3.75 → 6.1:1 sobre marine-deep */
}

/* Iba dentro de .footer__bottom con flex-basis:100%/flex:0 0 100%, pero
   ninguna combinación de flex-basis/grow/shrink logra fila propia + 62ch a
   la vez: el ancho que decide el salto de línea es el flex-basis YA
   recortado por max-width (68px de ~1265px caben igual junto a las otras
   dos columnas), y flex-shrink no participa en esa decisión — sólo en el
   reparto de espacio DESPUÉS de que el ítem ya quedó asignado a una fila.
   Verificado en vivo: probado con flex:0 0 100% y no bajaba de fila.
   Por eso ahora es un bloque aparte, fuera del flex (ver el HTML). */
.footer__legal {
  margin-top: 20px;
  max-width: 62ch;
  font-size: .95rem;
  color: rgba(254, 254, 254, .6);    /* mismo tono que .footer__bottom */
}

/* --------------------------------------------------------------------------
   15b. Barra de contacto en celular
   La página mide casi 24 pantallas en móvil: sin esto, quien se decide a
   mitad de camino no tiene dónde tocar. Sólo bajo 721px — en escritorio el
   botón "Conversemos" del header cumple ese papel.
   -------------------------------------------------------------------------- */

.barra-contacto { display: none; }

/* [hidden] es display:none por hoja del NAVEGADOR, y el display:grid de
   arriba es CSS de autor: gana el autor. Sin esta regla, sin JavaScript la
   barra queda invisible pero tabulable, con el foco saliéndose de pantalla. */
.barra-contacto[hidden] { display: none; }

@media (max-width: 720px) {
  /* La barra es fixed y no reserva espacio en el flujo: sus ~68px (12px de
     margen + 56px de alto) tapan la última línea del pie al llegar al
     final del scroll. Con dos líneas el padding base de 40px alcanzaba;
     con las tres de ahora (al sumarse .footer__legal) ya no — se
     detectó comprobando el pie en el navegador, no se veía a simple vista
     en el código. */
  .footer { padding-bottom: 110px; }

  .barra-contacto {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    position: fixed;
    left: 12px;
    right: 12px;
    /* safe-area: en iPhone la franja del gesto de inicio se come el borde */
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    z-index: 60;
    opacity: 0;
    transform: translateY(120%);
    transition: opacity var(--t), transform var(--t);
    pointer-events: none;
  }

  .barra-contacto.is-visible {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }

  .barra-contacto__accion {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    /* 56px: por encima del mínimo de 44px, con holgura para dedo grande */
    min-height: 56px;
    border-radius: var(--r-md);
    font-size: 1.05rem;
    box-shadow: var(--shadow-flotante);
    transition: transform var(--t);
  }

  .barra-contacto__accion:active { transform: scale(.97); }

  /* Llamar es la acción principal: se lleva el ámbar, coherente con G3. */
  .barra-contacto__accion--llamar { background: var(--c-amber); color: var(--c-sobre-amber); }
  .barra-contacto__accion--wa     { background: var(--c-marine); color: var(--c-light); }

  .barra-contacto__accion:focus-visible {
    outline: 3px solid var(--c-marine);
    outline-offset: 3px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .barra-contacto { transition: none; }
}

/* --------------------------------------------------------------------------
   16. Revelado al hacer scroll
   Traducción del --hero-transition-time: 1000ms del referente.
   -------------------------------------------------------------------------- */

/* El ocultamiento inicial se aplica SÓLO si el JS confirmó estar vivo (clase .js
   puesta por un script en línea en el <head>). Sin JavaScript, todo el contenido
   se ve de inmediato en vez de quedar invisible para siempre. */
.js .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 1s var(--ease-reveal), transform 1s var(--ease-reveal);
}

.js .reveal.is-in { opacity: 1; transform: none; }

/* Variante escalonada: el contenedor se observa igual, pero quienes se
   esconden son los HIJOS, que van llegando de a uno cada 200ms — la textura
   del referente (su stagger de 0.2s). Hasta 9 hijos: los toca la lista de
   Financiamiento, que pasó de 7 a 9 filas el 2026-07-25. Si esta lista vuelve a
   crecer hay que extender la escalerilla de abajo — sin su --i, los hijos nuevos
   caen al 0 por omisión y entran ANTES que los anteriores, no después. */
.js .reveal--stagger > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 1s var(--ease-reveal), transform 1s var(--ease-reveal);
  transition-delay: calc(var(--i, 0) * 200ms);
}

.js .reveal--stagger.is-in > * { opacity: 1; transform: none; }

.js .reveal--stagger > :nth-child(2) { --i: 1; }
.js .reveal--stagger > :nth-child(3) { --i: 2; }
.js .reveal--stagger > :nth-child(4) { --i: 3; }
.js .reveal--stagger > :nth-child(5) { --i: 4; }
.js .reveal--stagger > :nth-child(6) { --i: 5; }
.js .reveal--stagger > :nth-child(7) { --i: 6; }
.js .reveal--stagger > :nth-child(8) { --i: 7; }
.js .reveal--stagger > :nth-child(9) { --i: 8; }

/* Tarjetas del slider de servicios: se observan una a una y el JS les asigna
   --i por lote visible (el equivalente casero del ScrollTrigger.batch del
   referente): la primera tanda entra 0/200/400/600ms; al deslizar, cada
   tarjeta nueva entra sin espera. */
.js .serv {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 1s var(--ease-reveal), transform 1s var(--ease-reveal);
  transition-delay: calc(var(--i, 0) * 200ms);
}

.js .serv.is-in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .js .reveal,
  .js .reveal--stagger > *,
  .js .serv { opacity: 1; transform: none; }
  /* Sin pin en absoluto: 1500px de scroll "congelado" desorientan. El
     !important gana a la regla móvil de 700px, que llega después en la hoja. */
  .js .hero-pin { --pin-d: 0px !important; }
}

/* --------------------------------------------------------------------------
   17. Adaptación a pantallas menores
   -------------------------------------------------------------------------- */

@media (max-width: 1080px) {
  :root { --section-y: 128px; --gutter: 28px; }

  .sec-head { grid-template-columns: 1fr; gap: 20px; align-items: start; margin-bottom: 52px; }

  .footer__top { grid-template-columns: 1fr 1fr; }
  .footer__brand { grid-column: 1 / -1; }
}

@media (max-width: 720px) {
  :root { --section-y: 100px; --gutter: 20px; }

  body { font-size: 16.5px; }
}

/* Navegación desplegable — hasta 1279px, no solo en el celular: entre 721 y
   1279 la barra centrada nunca cupo (el logo se encogía y los enlaces se
   partían en dos líneas; medido en vivo el 2026-08-01). En esa franja la
   cabecera queda logo + Conversemos + hamburguesa, y el panel lleva la lista
   completa de secciones. */
@media (max-width: 1279px) {
  .burger { display: block; }

  /* Panel móvil con la cascada MEDIDA del referente: contenedor 600ms
     ease-in-out → lista 500ms ease-out con delay 300ms → CTA 500ms ease-out
     con delay 500ms.
     TARJETA FLOTANTE calcada del menú móvil del referente (captura lado a lado):
     anclada arriba a la derecha sin llegar a los bordes, r28 en las CUATRO
     esquinas, la página sigue viéndose por la izquierda. El botón X del
     header (fixed, esquina superior derecha) queda visualmente DENTRO de la
     primera fila de la tarjeta — el mismo truco del referente — y un filete
     la separa de los ítems. La sombra es la única del kit (flotantes). */
  .nav {
    position: fixed;
    top: 8px;
    right: 8px;
    left: auto;
    /* El ancho del referente, FIJO: su tarjeta mide ~220px en el iPhone.
       min(60vw, 250px) daba 250px en pantallas de 430px — seguía ancha. */
    width: 224px;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 68px 20px 20px;
    background: var(--c-light);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-flotante);
    transform: translateY(-16px);
    opacity: 0;
    pointer-events: none;
    /* visibility saca del tabulador y del lector de pantalla a los enlaces
       del panel cerrado: opacity sola los deja invisibles pero enfocables
       (el foco desaparecía de la pantalla al tabular). El retardo de .6s la
       aplica recién al terminar el fundido de salida; al abrir, .is-open la
       devuelve sin retardo. */
    visibility: hidden;
    transition: opacity .6s ease-in-out, transform .6s ease-in-out,
                visibility 0s linear .6s;
  }

  /* La fila superior lleva el logo pequeño en tinta (el papel de la
     fila-marca del referente): el PNG es blanco —el del header sobre
     video—, brightness(0) lo vuelve tinta oscura sobre la tarjeta blanca. */
  .nav__logo {
    display: block;
    position: absolute;
    top: 22px;
    left: 20px;
    height: 17px;
    width: auto;
    filter: brightness(0) opacity(.88);
  }

  /* El filete bajo la fila del cierre, a todo el ancho de la tarjeta
     (el referente lo lleva bajo su fila superior). */
  .nav::before {
    content: '';
    position: absolute;
    top: 60px;
    left: 0;
    right: 0;
    border-top: 1px solid var(--c-line);
  }

  .nav.is-open {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    visibility: visible;
    transition-delay: 0s;
  }

  .nav__link {
    color: var(--c-dark);
    font-size: 1.35rem;
    padding: 13px 4px;
    border-radius: 0;              /* en el panel móvil no hay píldora */
    /* Sin divisores entre ítems: en el referente el único filete es el de
       la fila superior; el aire hace la separación. */
    /* Estado de cascada: cada apertura parte oculto y sube. */
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .5s ease-out .3s, transform .5s ease-out .3s;
  }
  .nav.is-open .nav__link { opacity: 1; transform: none; }

  /* CTA propio del panel (como el resp-menu__cta del referente): cierra la
     cascada a los 500ms, ámbar a todo el ancho de la tarjeta. */
  .nav__menu-cta {
    display: inline-flex;
    justify-content: center;
    margin-top: 16px;
    /* En la tarjeta angosta el texto largo debe caber en una línea. */
    padding-inline: 12px;
    font-size: 1rem;
    white-space: nowrap;
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .5s ease-out .5s, transform .5s ease-out .5s,
                background var(--t);
  }
  .nav.is-open .nav__menu-cta { opacity: 1; transform: none; }

  /* En el panel, los enlaces que la barra de escritorio no puede alojar. */
  .nav__link--panel { display: block; }

  /* En tablet el CTA sigue en la barra, empujado junto a la hamburguesa
     (sin el grid de escritorio, space-between lo dejaría flotando al
     centro). Se apaga con el panel abierto, igual que el logo: la tarjeta
     se despliega justo debajo y quedaría un botón pisando la lista. */
  .nav__cta { margin-left: auto; }
  .header.is-menu .nav__cta { opacity: 0; pointer-events: none; }
}

@media (max-width: 720px) {
  /* En el celular el CTA del bar sí se oculta: el panel lleva el suyo y la
     barra fija de Llamar/WhatsApp cubre el llamado permanente. */
  .nav__cta { display: none; }

  /* Con pin, el héroe móvil vuelve a 100svh: el asomo del 92svh ya no aplica
     (la siguiente sección queda a --pin-d de distancia). Recorrido y tarjeta
     final más cortos, como hace el referente en pantallas chicas. */
  .js .hero-pin { --pin-d: 700px; }
  /* min((N/10·baseline)svh) como en escritorio, con baseline 714px: en un
     iPhone SE (667 de alto) la tarjeta rozaba el titular de la promesa
     (+21px medidos); en teléfonos normales (≥714) no cambia nada. */
  .hero__media { --card-w: min(150px, 21svh); --card-h: min(200px, 28svh); --card-r: 16px; }

  /* Como hace el referente en celular: los CTAs bajan al pie del héroe para
     despejar el centro, donde el video encoge a tarjeta. El titular queda
     centrado en el espacio que queda sobre ellos (dos márgenes auto).
     align-self: stretch y NO height: 100%: Safari (iPhone) no resuelve el
     porcentaje contra el área de grilla centrada (Chrome sí) y el alto
     colapsaba a auto — los margin-top: auto quedaban sin espacio y los CTAs
     aparecían pegados al texto en vez de al pie. */
  .hero__inner {
    display: flex;
    flex-direction: column;
    align-self: stretch;
    height: auto;
  }
  .hero__inner h1 { margin-top: auto; }
  .hero__actions { flex-direction: column; align-items: stretch; margin-top: auto; gap: 12px; }
  .hero__actions .btn { justify-content: center; }

  /* Calco del héroe móvil del referente (captura del iPhone lado a lado):
     los CTAs casi tocan el borde inferior (~18px, no los 80px de escritorio),
     separados 12px, y son rectángulos de esquina suave r18 —el radio de botón
     canónico del kit—, no píldoras. Algo más esbeltos, sin bajar de los 44px
     de zona táctil. El safe-area evita que la barra de gestos los tape. */
  .hero { padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
  .hero__actions .btn {
    border-radius: 18px;
    min-height: 46px;
    padding: 12px 24px;
  }


  /* Cifras: el panel pasa de vertical a apaisado. La líder conserva su
     protagonismo (número grande, primera de la pila); las normales pasan a
     filas completas con el ícono a la izquierda. Otra composición, no la
     misma grilla con menos columnas. */
  .cifras__layout { grid-template-columns: 1fr; gap: 14px; }
  .cifras__panel { padding: 32px 26px; }
  .cifras__luces { width: 250px; right: -30px; bottom: -14px; }
  .cifras__grid { grid-template-columns: 1fr; gap: 12px; }
  .cifra {
    display: grid;
    grid-template-columns: 54px 1fr;
    align-items: center;
    gap: 16px;
    padding: 22px 20px;
  }
  .cifra__ico { margin-bottom: 0; }

  /* En las filas compactas el filete estorba entre chip y texto: sólo la
     líder lo conserva (sigue en composición vertical). */
  .cifra:not(.cifra--lider) > div::before { display: none; }

  .cifra--lider {
    grid-row: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 18px;
    padding: 28px 24px;
  }
  .cifra--lider .cifra__n { font-size: clamp(3.4rem, 2.6rem + 4vw, 4.4rem); }

  .form__row { grid-template-columns: 1fr; }

  .footer__top { grid-template-columns: 1fr; gap: 36px; }
}
