/* ══════════════════════════════════════════════════════════════════════
   HEXA GROUP · GEOMETRÍA DE LA INTRO SCROLL-DRIVEN
   ──────────────────────────────────────────────────────────────────────
   Este archivo es dueño de UNA sola cosa: las medidas del tramo fijado de
   la introducción. La apariencia (colores, tipografías, sombras, la
   animación del indicador de scroll) sigue en el <style> de index.html y
   no se toca.

   Se carga después de ese <style>, así que sus reglas ganan en empate de
   especificidad. Por eso repite al final el bloque de reduced-motion: si
   no lo hiciera, pisaría el que ya existe y rompería la accesibilidad.

   ── EL BUG QUE ARREGLA ──

   Antes, la altura del viewport se medía una vez con JavaScript al cargar
   la página y se guardaba en --svh:

       document.documentElement.style.setProperty('--svh', lastH + 'px');

   En un celular, al cargar, la barra de URL del navegador está desplegada.
   Esa medición captura entonces el viewport CHICO (~640px). Al scrollear,
   la barra se retrae y la pantalla real pasa a ~720px, pero el escenario
   sigue midiendo 640: quedan ~80px de fondo desnudo abajo. Al scrollear
   hacia arriba la barra vuelve y el video llena la pantalla otra vez. Ese
   vaivén es lo que se veía como "el video se mueve y se agranda".

   En la PC no pasaba porque no hay barra que se retraiga.

   ── LA REGLA QUE LO REEMPLAZA ──

   Nada de medir el viewport con JavaScript. Se usan las unidades del
   navegador, pero eligiendo la correcta para cada trabajo:

     · lo que tiene que CUBRIR  →  lvh  (viewport grande, barra retraída)
     · lo que tiene que VERSE   →  svh  (viewport chico, barra desplegada)

   Las dos son estables por definición: describen los dos extremos del
   viewport, no su estado actual. Por eso no tiemblan.

   dvh sería el error opuesto: sigue el estado actual, cambia en cada
   cuadro mientras la barra se mueve, y produce exactamente el temblor que
   estamos sacando. No se usa dvh en ningún lado de este archivo.

   El respaldo de cada regla es vh, que en móvil equivale a lvh: si un
   navegador viejo no entiende lvh, se comporta igual de bien.
   ══════════════════════════════════════════════════════════════════════ */


/* ══ 1 · EL RECORRIDO Y EL ESCENARIO ═══════════════════════════════════
   Los dos en lvh. Que compartan unidad es lo que hace que el progreso del
   scroll no pueda saltar: la resta que lo calcula (recorrido − escenario)
   da siempre el mismo número, se mueva o no la barra del navegador. */

.intro {
  position: relative;
  height: 360vh;
  background: var(--night);
}

/* position: fixed, NO sticky.
   Es la diferencia que hace que el video quede realmente quieto en el
   celular, y es lo que hace por dentro el pin de GSAP en el otro sitio.

   sticky sigue participando del scroll: el navegador recalcula su posición
   en cada cuadro, y en móvil ese cálculo va por el hilo principal mientras
   el compositor ya movió la pantalla. El elemento persigue al scroll con
   retraso — eso era "el video se corre de lugar al scrollear". En una PC el
   hilo principal va tan sobrado que nunca se nota.

   fixed no participa del scroll. Está clavado al viewport y el scroll pasa
   por debajo. El translateZ lo manda a su propia capa del compositor, así
   el navegador no lo repinta mientras la página se mueve. */
.intro-stage {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 100vh;
  z-index: 1;
  overflow: hidden;
  background: var(--night);
}

/* NO poner transform ni will-change acá.
   Un transform promueve el elemento a su propia capa del compositor, y en
   varios GPU móviles un <video> dentro de una capa promovida deja de
   actualizar su textura: se ve el primer cuadro congelado para siempre
   aunque currentTime siga avanzando. Era una optimización innecesaria —
   position:fixed ya evita el recálculo por scroll, que es lo que
   buscábamos. */

@supports (height: 100lvh) {
  .intro       { height: 360lvh; }
  .intro-stage { height: 100lvh; }
}

/* Al ser fixed queda fuera del flujo, así que no desaparece solo cuando la
   introducción termina: lo apaga el JS cuando el recorrido sale de pantalla.
   Sin esto seguiría pintando y decodificando video el resto de la página. */
.intro-stage[data-off] {
  visibility: hidden;
}

/* El video cubre el escenario completo. Como el escenario está en lvh y no
   cambia de tamaño, object-fit ya no recorta distinto en cada cuadro — que
   era la otra mitad del efecto de "zoom". */
.intro-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}


/* ══ 2 · LA ZONA SEGURA ════════════════════════════════════════════════
   El escenario mide lvh, así que su franja inferior queda debajo de la
   barra del navegador cuando está desplegada. Todo lo que el visitante
   tiene que leer —los textos, la barra de progreso, el indicador de
   scroll— vive dentro de esta caja, que mide svh y por lo tanto está
   siempre a la vista.

   Al ser una caja de altura conocida, el posicionamiento interno sigue
   siendo en porcentajes y nada de lo que ya estaba escrito cambia. */

.intro-safe {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 100vh;
  pointer-events: none;
  z-index: 3;
}

@supports (height: 100svh) {
  .intro-safe { height: 100svh; }
}

/* Los textos iban anclados a --svh; ahora es un porcentaje de la zona
   segura, que es exactamente lo mismo pero sin depender de JavaScript. */
.intro-captions {
  bottom: 13%;
}


/* ══ 3 · EL SOLAPAMIENTO DEL HERO ══════════════════════════════════════
   El hero se sube una pantalla entera para montarse sobre el video fijado.
   Ese margen negativo tiene que usar LA MISMA unidad que el escenario: si
   uno mide lvh y el otro svh, el hero se solapa de más o de menos y se ve
   un salto justo en la transición. Es el acoplamiento menos evidente de
   todo el efecto y el más fácil de romper sin darse cuenta. */

.hero {
  margin-top: -100vh;
  padding-top: 52vh;
}

@supports (height: 100lvh) {
  .hero {
    margin-top: -100lvh;
    padding-top: 52lvh;
  }
}


/* ══ 4 · SIN DESBORDE HORIZONTAL ═══════════════════════════════════════
   De esto depende que el escenario fijo tenga el tamaño correcto, así que
   vive acá aunque el elemento sea del hero.

   Un position:fixed no se dimensiona contra la pantalla: se dimensiona
   contra el bloque contenedor inicial. Y si algún elemento ensancha el
   documento, ese bloque se ensancha con él — entonces el video pasa a ser
   más ancho que la pantalla y el navegador aleja el zoom para que entre.
   Se ve como si la página entera se hubiera achicado.

   .hero-bg es un resplandor decorativo de 1300px de ancho fijo, centrado
   con left:50% y translate:-50%. En una pantalla de 375px eso son 462px
   sobresaliendo por cada lado. El desborde ya existía desde antes, pero
   era invisible: position:sticky se dimensiona contra su contenedor y lo
   ignoraba. Al pasar a fixed quedó expuesto.

   Acotarlo al ancho disponible lo resuelve en el origen. Es un degradado
   radial suave, así que verlo más angosto en el celular no cambia nada
   perceptible — sólo se difumina en menos distancia.

   Se usa 100% y no 100vw a propósito: 100vw incluye el ancho de la barra
   de desplazamiento y volvería a desbordar, apenas, en escritorio. */

.hero-bg {
  width: min(1300px, 100%);
}


/* ══ 5 · EL SELECTOR DE PRODUCTOS ══════════════════════════════════════
   No es parte de la intro, pero tenía el mismo bug latente: su escenario
   también se dimensionaba con --svh. Al eliminar esa variable había que
   convertirlo o quedaba roto, así que se le aplica la misma regla.

   El escenario cubre (lvh) y el mazo de tarjetas —que es lo que hay que
   mirar— se dimensiona contra el viewport chico (svh) para no quedar
   nunca por debajo de la barra del navegador. */

.selector-stage {
  height: 100vh;
}

.deck {
  height: min(560px, 76vh);
}

@supports (height: 100lvh) {
  .selector-stage { height: 100lvh; }
  .deck           { height: min(560px, 76svh); }
}

@media (max-width: 1040px) {
  .deck { height: min(520px, 66vh); }
  @supports (height: 100svh) { .deck { height: min(520px, 66svh); } }
}

@media (max-width: 620px) {
  .deck { height: min(480px, 68vh); }
  @supports (height: 100svh) { .deck { height: min(480px, 68svh); } }
}


/* ══ 6 · ACCESIBILIDAD ═════════════════════════════════════════════════
   index.html ya trae un bloque de reduced-motion que desarma la intro. Se
   repite acá porque este archivo carga después y, sin esto, las reglas de
   arriba le ganarían y dejarían el efecto activo para alguien que pidió
   explícitamente que no haya movimiento. */

@media (prefers-reduced-motion: reduce) {
  .intro          { height: auto; }
  .intro-stage    { position: static; height: auto; }
  .intro-safe     { display: none; }
  .intro-video    { display: none; }
  .hero           { margin-top: 0; padding-top: 140px; }
  .selector-stage { position: static; height: auto; }
  .deck           { height: auto; }
}
