/* =============================================================================
   NexKey365 — Hero claro estilo "Ari" (réplica adaptada)
   Composición a TODA la anchura: izquierda la bienvenida ("Soft" negro /
   "Imperio" verde), centro el producto protagonista en 3D con la constelación
   del catálogo, derecha las cifras reales apiladas con divisores + CTA verde,
   y abajo-izquierda la pista "Desliza · Descubre el catálogo".
   Progresivo: sin WebGL queda la misma retícula con el panel de activación al
   centro. hero3d.js añade .hero--live (pista alta + sticky) y .hero--on (canvas).
   Capas dentro de .hero__sticky: bg(0) < canvas(1) < shade(2) < contenido(3+).
   ============================================================================= */

.hero--3d {
  display: block;
  padding: 0;
  overflow: visible;
  background: none;
}

.hero--3d::after {
  content: none;
}

.hero--3d .hero__sticky {
  position: relative;
  display: flex;
  /* Contenido abajo: la constelación se queda con la franja alta (hero3d.js
     la sube con heroY) y el titular vive debajo, sin que le pasen logos por
     encima. Es la composición "producto arriba / mensaje abajo". */
  align-items: flex-end;
  justify-content: center;
  min-height: clamp(600px, 92vh, 900px);
  /* El relleno inferior reserva la banda donde viven la pista de scroll y la
     tira de cifras, para que ninguna de las dos pise a los botones. */
  padding-block: clamp(2rem, 5vh, 3.5rem) clamp(7rem, 19vh, 11rem);
  overflow: hidden;
  isolation: isolate;
  /* Escenario OSCURO. El lienzo WebGL es transparente (setClearColor con
     alpha 0), así que este fondo es literalmente lo que se ve detrás de la
     constelación. Va en Dark Navy #0A1117 porque es el único entorno donde el
     Cyber Teal puro se puede usar de verdad (13.2:1 de contraste). */
  background:
    radial-gradient(120% 92% at 50% 6%, oklch(0.235 0.028 205) 0%, transparent 60%),
    radial-gradient(85% 55% at 50% 106%, oklch(0.30 0.055 178 / 0.45) 0%, transparent 72%),
    oklch(0.174 0.017 245);
}

/* OJO: aquí NO puede entrar .hero__ticker. Esta regla tiene 3 clases y le
   ganaría al position:absolute de su propia regla (1 clase); la tira dejaría
   de estar fuera de flujo y se comería media fila flex al contenedor. */
.hero--3d .hero__sticky>.container {
  position: relative;
  z-index: 3;
}

.hero--3d .hero__bg {
  display: none;
}

.hero--3d .hero__watermark {
  display: none;
}

/* --- Escenario central --------------------------------------------------------
   Sustituye a la retícula de tres columnas (bienvenida | producto | cifras) que
   venía de la plantilla de origen: era lo que más la delataba. Ahora la
   constelación ocupa TODO el ancho y el texto flota centrado encima. */
/* OJO con la especificidad: home.css trae
     .hero .hero__sticky>.container { grid-template-columns: 1fr 0.8fr }
   (tres clases). Hay que igualar o superar eso o el contenido se va a una
   columna izquierda de dos. Por eso el selector largo y el 1fr explícito. */
.hero--3d .hero__sticky>.container.hero__center {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  align-content: end;
  text-align: center;
  gap: clamp(1.25rem, 3vh, 2.25rem);
}

/* Ancho generoso: el titular a 6.2rem necesita sitio. La lede se estrecha
   aparte (54ch) para que la línea no se haga incómoda de leer. */
.hero__center .hero__content {
  max-width: 74ch;
  padding-block: 0;
}

/* Con el 3D en camino (h3d-wait) o ya vivo (hero--live), el panel de respaldo
   NO ocupa sitio: en esta composición es una segunda fila de la rejilla y
   empujaba el titular hacia arriba, justo debajo de la constelación. La
   constelación ES el visual. Si el 3D falla, las clases se quitan solas y el
   panel recupera su hueco. */
html.h3d-wait .hero--stage .hero__visual,
.hero--stage.hero--live .hero__visual {
  display: none;
}

/* Ceja con línea: lleva el eslogan de la identidad de marca */
.hero--3d .hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 0;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: oklch(0.86 0.158 178);   /* Cyber Teal — 13.2:1 sobre el escenario */
  /* Halo propio: la ceja es la línea más alta del bloque y es la que puede
     quedar sobre un logo de la constelación. Con esto se lee siempre, sin
     depender de dónde caiga exactamente el 3D. */
  text-shadow:
    0 0 14px oklch(0.174 0.017 245),
    0 0 26px oklch(0.174 0.017 245),
    0 1px 3px oklch(0.174 0.017 245);
}

.he-line {
  width: 2.2rem;
  height: 1px;
  background: currentColor;
  opacity: 0.7;
  flex: none;
}

/* Tinta FIJA (no var(--ink)): el escenario es oscuro en los dos temas, así que
   el titular va siempre en el gris claro de la marca (#F3F6F8). */
.hero--3d .hero__brand {
  margin-top: 1rem;
  font-family: var(--font-display);
  font-weight: 620;
  line-height: 1;
  letter-spacing: -0.03em;
  font-size: clamp(2.8rem, 1.5rem + 4vw, 5.3rem);
  color: oklch(0.971 0.004 236);
  text-shadow: none;
}

/* En UNA línea, como el logotipo del tablero de marca (antes iban apilados
   uno sobre otro, que era la composición de la plantilla original). */
.hero--3d .hero__brand span,
.hero--3d .hero__brand em {
  display: inline;
}

.hero--3d .hero__brand em {
  font-style: normal;
  color: oklch(0.86 0.158 178);   /* el "365" en Cyber Teal, igual que el logo */
}

/* Sin la línea animada del hero anterior bajo el <em> */
.hero--3d .hero__brand em::after {
  content: none;
}

.hero--3d .hero__content {
  color: oklch(0.79 0.008 240);
  padding-block: 0;
}

.hero--3d .hero__lede {
  margin-top: 1.15rem;
  margin-inline: auto;
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.14rem);
  line-height: 1.6;
  color: oklch(0.79 0.008 240);   /* 9.8:1 sobre el escenario */
  max-width: 54ch;
}

/* --- Cifras: tira horizontal al pie del escenario -----------------------------
   Antes era un riel vertical pegado a la derecha (la firma de la plantilla
   original). Ahora es una banda de cuatro celdas anclada abajo, que además
   ENTRA al hacer scroll en vez de aparecer al cargar (ver hero3d.js). */
.hero__ticker {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  border-top: 1px solid oklch(0.32 0.026 246);
  background: oklch(0.174 0.017 245 / 0.72);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  will-change: opacity, transform;
}

/* Arranca invisible SOLO cuando el 3D está vivo (.hero--on lo pone hero3d.js):
   a partir de ahí su opacidad la gobierna el scroll. Sin WebGL, sin JS o con
   movimiento reducido esta regla no se aplica y la tira se ve de entrada. */
.hero--on .hero__ticker {
  opacity: 0;
}

.hero__stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  align-items: center;
  text-align: center;
}

.hstat {
  padding: clamp(0.8rem, 2vh, 1.2rem) 0.4rem;
  border-top: 0;
  border-left: 1px solid oklch(0.32 0.026 246);
}

.hstat:first-child {
  border-top: 0;
  border-left: 0;
}

.hstat b {
  display: block;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  font-size: clamp(1.15rem, 0.85rem + 1.1vw, 2rem);
  color: oklch(0.971 0.004 236);
  font-variant-numeric: tabular-nums;
}

.hstat b i {
  font-style: normal;
  font-size: 0.42em;
  font-weight: 700;
  color: oklch(0.55 0.101 178);
  vertical-align: super;
  margin-left: 0.15em;
}

/* OJO: hijo DIRECTO (>): dentro del <b> ahora viven los spans del tambor de
   cifras y no deben heredar el estilo de la leyenda. */
.hstat > span {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: oklch(0.66 0.012 242);   /* 6.1:1 sobre el escenario */
}

/* --- Tambor de cifras (slot machine, home.js statOdometer) -------------------
   Cada dígito es una ventanita de 1em con una columna 0-9 que gira (transform)
   y cae en su valor. Los signos (+, –, espacio) van en la misma caja de 1em
   para que toda la cifra alinee pareja. */
.odo {
  display: inline-block;
  overflow: hidden;
  height: 1em;
  line-height: 1;
  white-space: pre;
}

.odo__reel {
  display: block;
  transition: transform 1s cubic-bezier(0.16, 0.9, 0.24, 1);
  will-change: transform;
}

.odo__reel > span {
  display: block;
  height: 1em;
  line-height: 1;
}

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

/* Bloque de acción centrado bajo el titular: buscador + atajos. */
.hero__cta {
  margin-top: clamp(1.4rem, 3.5vh, 2.25rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
}

/* --- Buscador del hero -------------------------------------------------------
   Es un <form> GET de verdad a /productos?q=…: si el JS falla, sigue buscando. */
.hero__search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: min(560px, 100%);
  padding: 0.4rem 0.4rem 0.4rem 1rem;
  border-radius: var(--r-pill);
  background: oklch(0.235 0.021 246 / 0.82);
  border: 1px solid oklch(0.40 0.03 242);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: border-color var(--t), box-shadow var(--t);
}

.hero__search:focus-within {
  border-color: oklch(0.86 0.158 178 / 0.75);
  box-shadow: var(--ring);
}

.hero__search > i {
  display: inline-flex;
  flex: none;
  color: oklch(0.66 0.012 242);
}

.hero__search > i svg {
  width: 19px;
  height: 19px;
}

.hero__search input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.6rem 0;
  border: 0;
  background: none;
  color: oklch(0.971 0.004 236);
  font: inherit;
  font-size: 0.95rem;
}

.hero__search input::placeholder {
  color: oklch(0.62 0.014 244);
}

.hero__search input:focus {
  outline: none;
}

/* El aspa nativa de type=search desentona sobre el fondo oscuro */
.hero__search input::-webkit-search-cancel-button {
  -webkit-appearance: none;
}

.hero__search button {
  flex: none;
  border-radius: var(--r-pill);
  padding-inline: 1.35rem;
}

/* --- Atajos a lo más buscado ------------------------------------------------ */
.hero__chips {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.45rem;
}

.hero__chips a {
  display: inline-block;
  padding: 0.36rem 0.85rem;
  border-radius: var(--r-pill);
  border: 1px solid oklch(0.32 0.026 246);
  background: oklch(0.20 0.019 246 / 0.6);
  font-size: 0.79rem;
  font-weight: 600;
  color: oklch(0.79 0.008 240);
  text-decoration: none;
  transition: color var(--t), border-color var(--t), background var(--t);
}

.hero__chips a:hover,
.hero__chips a:focus-visible {
  color: oklch(0.86 0.158 178);
  border-color: oklch(0.86 0.158 178 / 0.5);
  background: oklch(0.275 0.024 246 / 0.8);
}

.hero__ghostpill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.62rem 1.2rem;
  border-radius: var(--r-pill);
  background: oklch(0.275 0.024 246 / 0.55);
  border: 1px solid oklch(0.40 0.03 242);
  font-size: 0.85rem;
  font-weight: 600;
  color: oklch(0.90 0.006 240);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: none;
  transition: color var(--t), border-color var(--t), background var(--t);
}

.hero__ghostpill:hover {
  color: oklch(0.86 0.158 178);
  border-color: oklch(0.86 0.158 178 / 0.55);
  background: oklch(0.275 0.024 246 / 0.8);
}

/* Velos oscuros: fusión con los bordes + un halo central que garantiza que el
   titular se lea aunque le pase por detrás un logo de la constelación.
   El halo va PRIMERO (capa superior) y es suave para no tapar el 3D. */
.hero__shade {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    /* Banda densa sobre el bloque de texto (elipse ancha y baja) + halo suave
       alrededor. Garantiza el contraste del titular pase lo que pase por
       detrás; el 3D asoma por encima y por los lados, que es la gracia. */
    radial-gradient(70% 30% at 50% 72%, oklch(0.174 0.017 245 / 0.95) 0%, oklch(0.174 0.017 245 / 0.78) 55%, transparent 100%),
    radial-gradient(60% 46% at 50% 76%, oklch(0.174 0.017 245 / 0.7) 0%, transparent 76%),
    linear-gradient(90deg, oklch(0.174 0.017 245 / 0.8) 0%, transparent 20%),
    linear-gradient(270deg, oklch(0.174 0.017 245 / 0.8) 0%, transparent 20%),
    linear-gradient(180deg, oklch(0.174 0.017 245 / 0.75), transparent 18%),
    linear-gradient(0deg, oklch(0.174 0.017 245 / 0.9), transparent 24%);
}

@media (max-width: 960px) {
  .hero__shade {
    background:
      linear-gradient(180deg, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0.82) 55%, rgba(255, 255, 255, 0.96) 100%);
  }

  /* Con el 3D activo, el velo deja LIBRE la banda superior (ahí vive la
     constelación) y solo protege la lectura del texto de abajo. */
  .hero--on .hero__shade {
    background:
      linear-gradient(180deg,
        rgba(255, 255, 255, 0.2) 0%,
        rgba(255, 255, 255, 0.06) 18%,
        rgba(255, 255, 255, 0.1) 34%,
        rgba(255, 255, 255, 0.78) 48%,
        rgba(255, 255, 255, 0.93) 62%,
        rgba(255, 255, 255, 0.97) 100%);
  }
}

/* Lienzo WebGL: entra con fundido cuando las texturas están listas.
   pointer-events none es OBLIGATORIO: en modo tour el lienzo es fijo a pantalla
   completa y sin esto se tragaba los clics del footer (los clics sobre las
   cajas 3D se resuelven por raycast en document, no en el canvas). */
.hero__gl {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 1s var(--ease-out);
  pointer-events: none;
}

.hero--on .hero__gl.is-on {
  opacity: 1;
}

/* Relevo del hero: la constelación NO se oculta por umbral de scroll (eso
   dejaba un tramo VACÍO al subir del catálogo al hero, en celular y en
   escritorio: el lienzo seguía escondido hasta retroceder media pista). En su
   lugar, la vitrina llega con fondo propio y borde superior en degradado
   (regla .s-productos más abajo): al bajar CUBRE al hero y al subir lo
   DESCUBRE al instante, sin huecos en ninguna dirección. */
.s-productos {
  background: var(--bg);
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg) 0%, transparent), var(--bg) clamp(90px, 16vh, 150px));
}

/* --- Modo vivo (solo escritorio): hero de un viewport --------------------------
   Sin acto 2: al bajar, la constelación viaja en tornado al lado libre de cada
   sección (modo tour, ver bloque html.h3d-tour abajo). En ≥1101px se suma una
   pista corta de relevo (bloque siguiente) que fija el hero y lo disuelve. */
@media (min-width: 961px) {

  /* La altura de "modo vivo" se aplica SIEMPRE (no solo con .hero--live): el
     3D arranca diferido tras la carga y, si el hero creciera recién entonces,
     toda la página daba un salto de layout al refrescar (el "parpadeo"). */
  .hero--3d .hero__sticky {
    min-height: calc(100vh - var(--headerH, 4.5rem));
    min-height: calc(100svh - var(--headerH, 4.5rem));
  }

  .hero--live .hero__content,
  .hero--live .hero__stats {
    will-change: transform, opacity;
  }

  /* El texto deja pasar el puntero al lienzo; botones y enlaces siguen vivos */
  .hero--live .hero__content,
  .hero--live .hero__stats {
    pointer-events: none;
  }

  .hero--live :is(.hero__content, .hero__stats) :is(a, button) {
    pointer-events: auto;
  }

  /* Relevo suave: el panel de respaldo se funde mientras el lienzo 3D entra
     (antes era display:none y el cambio se veía como un destello). */
  .hero__visual {
    transition: opacity 0.6s var(--ease-out);
  }

  .hero--on .hero__visual {
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.6s var(--ease-out), visibility 0s 0.6s;
  }

  /* Y si la sonda de index.html ya sabe que el 3D viene (html.h3d-wait), el
     panel de respaldo NO se pinta nunca: el centro queda limpio y la
     constelación aparece directa con su fundido. Si el 3D falla, la clase se
     quita y el panel entra fundiéndose (transición de arriba). */
  html.h3d-wait .hero__visual {
    opacity: 0;
  }
}

/* --- Relevo del hero (tour ≥1101px, con movimiento permitido) ------------------
   El hero se queda QUIETO (sticky) mientras una pista corta de scroll extra lo
   disuelve en su propio sitio; recién cuando terminó de fundirse, el catálogo
   sube y toma su lugar. Sin esto, el home se escapaba hacia arriba a velocidad
   de scroll y el apartado siguiente "se posicionaba arriba de inmediato" (el
   salto agresivo). La pista existe desde la primera pintura (no depende de
   .hero--live) para no dar saltos de layout cuando el 3D arranca diferido; el
   fundido lo hace hero3d.js (updateDom) o, sin WebGL, cinematic.js. Con
   movimiento reducido no hay pista: hero clásico de un viewport. */
@media (min-width: 1101px) and (prefers-reduced-motion: no-preference) {
  /* SIN pista de relevo (20-jul-2026, tras varias vueltas con el dueño): el
     hero fijado siempre dejaba una cola fea — iconos sobrepuestos al catálogo
     al bajar, o un tramo vacío al subir. Ahora el hero FLUYE con el scroll
     como cualquier sección (la constelación sube con él, siempre visible) y
     la vitrina llega enseguida, fundiendo la unión con su degradado. */
  .hero--3d {
    min-height: calc(100vh - var(--headerH, 4.5rem));
  }

  /* Solape corto: la vitrina muerde apenas el borde inferior del hero para
     que el degradado cosa la unión (sin tapar el contenido). */
  .s-productos {
    position: relative;
    z-index: 2;
    margin-top: -5vh;
  }
}

/* --- Relevo del hero en móvil y tablet (con movimiento permitido) --------------
   Misma sensación que en escritorio: un espaciador tras el sticky (::after,
   neutralizando la capa decorativa absoluta de home.css) da una pista corta en
   la que el hero queda QUIETO disolviéndose en su sitio; el fundido lo hace
   updateDom() de hero3d.js (o cinematic.js sin WebGL) leyendo la pista real. */
@media (max-width: 1100px) and (prefers-reduced-motion: no-preference) {
  /* Sin espaciador de relevo (misma razón que en escritorio): el ::after solo
     queda para NEUTRALIZAR la capa decorativa absoluta de home.css. El hero
     fluye con el scroll y la vitrina llega justo detrás, cosida por su
     degradado con un mordisco mínimo. */
  .hero--3d::after {
    content: "";
    position: static;
    inset: auto;
    display: block;
    height: 0;
    background: none;
    z-index: auto;
  }

  .s-productos {
    position: relative;
    z-index: 2;
    margin-top: -2vh;
  }
}

/* --- Tour 3D por toda la página (hero3d.js pone html.h3d-tour en ≥1101px) ------
   El lienzo pasa a ser FIJO a pantalla completa (z 1). Los contenedores de las
   secciones suben a z 2 (el 3D pasa por detrás del contenido y por delante de
   los fondos). Cada sección [data-h3d] deja libre la mitad donde vive el 3D. */
html.h3d-tour .hero__gl {
  position: fixed;
  inset: 0;
  z-index: 1;
}

html.h3d-tour main .container {
  position: relative;
  z-index: 2;
}

/* Ya no existe crossfade por scroll: no reservamos capas grandes de composición
   permanentemente, reduciendo memoria gráfica y repintados. */
@media (min-width: 1101px) {

  /* Cada apartado ocupa ~58vw pegado a su lado (el 3D vive en el otro) y se
     extiende hacia el CENTRO para aprovechar el vacío (petición del dueño:
     "así como está en nuestros productos, en todos los apartados"). */
  html.h3d-tour [data-h3d="left"]>.container {
    width: min(58vw, 1400px);
    margin-inline: auto clamp(1.5rem, 4vw, 4.5rem);
  }

  html.h3d-tour [data-h3d="right"]>.container {
    width: min(58vw, 1400px);
    margin-inline: clamp(1.5rem, 4vw, 4.5rem) auto;
  }

  /* Capítulos con la constelación disuelta (data-h3d-hide): no hay 3D al
     costado que respetar, así que el contenido vuelve a centrarse a lo
     ancho (la vitrina de productos vive aquí desde el 20-jul-2026). */
  html.h3d-tour [data-h3d][data-h3d-hide]>.container {
    width: 100%;
    margin-inline: auto;
  }

  /* Cabecera editorial en TODAS las secciones: titular grande a la izquierda
     y su párrafo al lado derecho (aplica también al sub-título de la demo). */
  html.h3d-tour [data-h3d] .sec-head {
    align-items: center;
  }

  html.h3d-tour [data-h3d] .sec-head__t {
    display: grid;
    grid-template-columns: auto minmax(22ch, 34ch);
    gap: 0.4rem clamp(2rem, 4vw, 4.5rem);
    align-items: center;
  }

  html.h3d-tour [data-h3d] .sec-head__t .sec-eyebrow {
    grid-column: 1 / -1;
  }

  html.h3d-tour [data-h3d] .sec-head__t p {
    margin-top: 0;
  }

  /* Si el enlace baja de línea (anchos medios), que siga pegado a la derecha */
  html.h3d-tour [data-h3d] .sec-head>.btn-link {
    margin-left: auto;
  }

  html.h3d-tour .s-productos .product-grid {
    grid-template-columns: repeat(2, minmax(0, 340px));
  }

  /* Cómo funciona: los 5 pasos en 3 columnas (3 + 2), sin la línea punteada */
  html.h3d-tour .flow {
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem 2.25rem;
  }

  html.h3d-tour .flow::before {
    display: none;
  }

  /* Demo: la lista Eliges→Activas va HORIZONTAL sobre la pantalla simulada */
  html.h3d-tour .demo {
    grid-template-columns: 1fr;
  }

  html.h3d-tour .demo__steps {
    position: static;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 0.25rem 1.75rem;
  }

  html.h3d-tour .demo-step:not(:last-child)::after {
    display: none;
  }

  /* Soporte y FAQ conservan sus DOS columnas de siempre (texto+chat /
     aside+lista): con el bloque a 58vw vuelven a caber con holgura. */
}

/* En pantallas muy anchas, rejilla 3×2 centrada (6 destacados parejos) */
@media (min-width: 2000px) {
  html.h3d-tour .s-productos .product-grid {
    grid-template-columns: repeat(3, minmax(0, 340px));
  }
}

/* --- Ficha del producto bajo el cursor (hover sobre una caja) ----------------- */
.hero__tip {
  position: fixed;
  z-index: 320;
  left: 0;
  top: 0;
  pointer-events: none;
  padding: 0.55rem 0.8rem;
  border-radius: var(--r);
  background: oklch(0.235 0.021 246 / 0.94);
  border: 1px solid oklch(0.40 0.03 242);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 14px 34px oklch(0.06 0.01 245 / 0.55);
  color: oklch(0.971 0.004 236);
  font-size: 0.82rem;
}

.hero__tip b {
  display: block;
  font-family: var(--font-display);
  font-size: 0.92rem;
  letter-spacing: -0.01em;
}

.hero__tip span {
  color: oklch(0.86 0.158 178);
  font-weight: 700;
}

.hero__tip small {
  display: block;
  color: var(--ink-faint);
  margin-top: 2px;
  font-size: 0.72rem;
}

/* --- Pista de scroll: centrada sobre la tira de cifras (antes abajo-izquierda).
   Es la invitación a bajar, y bajar es lo que revela el resto del intro. ------ */
.hero__cue {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  /* Justo encima de la franja de la tira de cifras (que mide ~6rem), para que
     no se solapen cuando la tira entra al bajar. */
  bottom: 6.5rem;
  z-index: 4;
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: oklch(0.66 0.012 242);
  white-space: nowrap;
}

@media (min-width: 961px) {
  .hero--on .hero__cue {
    display: inline-flex;
  }
}

/* Línea vertical con un destello que baja en bucle: refuerza "desliza". */
.cue__line {
  width: 1px;
  height: 1.5rem;
  background: linear-gradient(180deg, transparent, oklch(0.86 0.158 178 / 0.75));
  flex: none;
  order: 2;
  position: relative;
  overflow: hidden;
}

.cue__line::after {
  content: "";
  position: absolute;
  inset-inline: -1px;
  height: 45%;
  background: oklch(0.86 0.158 178);
  animation: cue-drop 1.9s var(--ease-out-soft) infinite;
}

@keyframes cue-drop {
  0% { top: -50%; opacity: 0; }
  35% { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cue__line::after { animation: none; opacity: 0.6; top: 40%; }
}

/* --- Móvil: escenario 3D arriba (a plena vista) + contenido compacto debajo ---- */
@media (max-width: 960px) {
  .hero--on .hero__gl.is-on {
    opacity: 1;
  }

  .hero__act2,
  .hero__cue,
  .hero__tip {
    display: none !important;
  }

  /* Sin 3D en el celular (three.js pesaba varios segundos de carga ahí), la
     tarjeta compacta de activación vuelve a ser el visual del hero: es DOM +
     CSS puro, no cuesta nada y mantiene el hero con vida. home.css la oculta
     en angosto por defecto; aquí se re-activa solo para el hero 3D. */
  .hero--3d .hero__visual {
    display: block;
    width: min(400px, 100%);
    /* margen superior corto: en el celular el hero debe sentirse compacto */
    margin: 1.25rem auto 0.4rem;
  }

  /* Con el 3D en camino (sonda h3d-wait) la tarjeta no parpadea: invisible
     pero guardando su sitio. Con el 3D ya VIVO (hero--live) se retira del
     todo — en el celular el visual del hero es la constelación (20-jul-2026);
     la banda superior --h3dStage toma su lugar con transición. Si el 3D
     falla, las clases se quitan y la tarjeta vuelve sola. */
  html.h3d-wait .hero--3d .hero__visual {
    opacity: 0;
  }

  .hero--live .hero__visual {
    display: none;
  }

  .hero--3d .hero__beam {
    display: none;
  }

  /* hero3d.js fija --h3dStage (alto de la banda del 3D) y centra ahí la
     constelación; sin WebGL la variable no existe y no se reserva nada.
     La banda se reserva desde .hero--live (apenas hay 3D seguro) y con
     transición: el contenido baja suave una sola vez, no de golpe. */
  .hero__center {
    transition: padding-top 0.5s var(--ease-out);
  }

  .hero--live .hero__center {
    padding-top: var(--h3dStage, 0px);
  }

  /* En celular la tira de cifras no va anclada al pie (comería el poco alto
     disponible): fluye al final del contenido, en rejilla de 2×2. */
  .hero--3d .hero__sticky {
    padding-block: 1.5rem 1.5rem;
    min-height: 0;
  }

  .hero--live .hero__sticky {
    padding-block: 1.25rem 1.5rem;
  }

  .hero__ticker {
    position: static;
    margin-top: 1.4rem;
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-top: 1px solid oklch(0.32 0.026 246);
  }

  /* Sin scroll que la revele en celular (el cue está oculto): visible siempre. */
  .hero--on .hero__ticker {
    opacity: 1;
  }

  .hero__brand {
    font-size: clamp(2.6rem, 14vw, 3.4rem);
  }

  .hero--3d .hero__lede {
    margin-top: 0.9rem;
  }

  /* Con CUATRO cifras, en el celular van en rejilla de 2×2: dos por fila,
     divisor solo en la columna derecha. */
  .hero__stats {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.9rem 1rem;
    margin-top: 0.9rem;
    text-align: left;
  }

  .hstat {
    border-top: 0;
    border-left: 1px solid oklch(0.32 0.026 246);
    padding: 0.2rem 0 0.2rem 1rem;
  }

  .hstat:nth-child(odd) {
    border-left: 0;
    padding-left: 0;
  }

  .hstat b {
    font-size: 1.5rem;
  }

  .hstat > span {
    font-size: 0.58rem;
    letter-spacing: 0.12em;
  }

  .hero__cta {
    margin-top: 1.2rem;
    width: 100%;
  }

  /* En celular el botón "Buscar" se come el ancho del campo: se queda solo la
     lupa y el usuario envía con la tecla Enter (enterkeyhint="search"). */
  .hero__search button {
    display: none;
  }

  .hero__search {
    padding-right: 1rem;
  }

  .hero__cta .btn {
    width: 100%;
    justify-content: center;
  }

  .hero__ghostpill {
    justify-content: center;
  }
}

/* --- Portátil de pantalla baja (1366×768, 1440×900) --------------------------
   La constelación se coloca en proporción al alto (heroY = WORLD_H * 0.325),
   pero el bloque de texto mide lo mismo en píxeles siempre. En una pantalla
   corta ese bloque se come proporcionalmente mucho más y acaba tocando el 3D.
   Aquí se compacta el texto para devolverle aire a la constelación. */
@media (min-width: 961px) and (max-height: 900px) {
  .hero--3d .hero__brand {
    margin-top: 0.6rem;
    font-size: clamp(2.3rem, 3.6vw, 3.5rem);
  }

  .hero--3d .hero__lede {
    margin-top: 0.75rem;
    font-size: 0.95rem;
    max-width: 60ch;
  }

  .hero__cta {
    margin-top: 1.05rem;
    gap: 0.6rem;
  }

  .hero--3d .hero__sticky {
    padding-block: 1.5rem clamp(5.5rem, 13vh, 7rem);
  }

  /* Sin sitio para la pista de scroll: se cruzaba con los chips. La tira de
     cifras que entra al bajar ya cumple esa función de "hay más abajo". */
  .hero--on .hero__cue {
    display: none;
  }
}

/* Con movimiento reducido, hero3d.js no arranca; por si acaso, el lienzo fuera. */
@media (prefers-reduced-motion: reduce) {
  .hero__gl {
    display: none;
  }
}

/* --- Formato VERTICAL ancho (monitor rotado, ventana alta, ≥961px) -------------
   La constelación SÍ corre, pero con composición propia: vive en la mitad
   superior del hero y el contenido baja en dos columnas (marca | cifras). El
   tour queda apagado (hero3d.js): en vertical las secciones no tienen costado
   libre. Sin pista de relevo: min-height 100svh más 40–60vh de pista, pensados
   para paisaje, dejaban un vacío enorme en un viewport tan alto. Van al final
   del archivo a propósito: ganan por orden a las reglas de arriba. */
@media (min-width: 961px) and (max-aspect-ratio: 9/10) {
  .hero--3d {
    min-height: 0;
  }

  .hero--3d::after {
    content: none;
  }

  .hero--3d .hero__sticky {
    position: relative;
    top: auto;
    min-height: min(calc(100svh - var(--headerH, 4.5rem)), 720px);
  }

  .s-productos {
    margin-top: 0;
  }

  /* Con el 3D vivo (o en camino: h3d-wait), el hero crece a media pantalla
     alta y el contenido se alinea ABAJO; la banda superior es del 3D. Si el
     3D falla, h3d-wait se quita y vuelve el hero compacto con su panel. */
  .hero--live .hero__sticky,
  html.h3d-wait .hero__sticky {
    min-height: min(calc(88svh - var(--headerH, 4.5rem)), 1460px);
    align-items: flex-end;
  }

  .hero--live .hero__center,
  html.h3d-wait .hero__center {
    padding-bottom: clamp(1.5rem, 4svh, 4rem);
  }

  /* El panel de respaldo no se pinta: el escenario es del lienzo. */
  .hero--on .hero__center .hero__visual,
  html.h3d-wait .hero__center .hero__visual {
    display: none;
  }
}