/* =====================================================================
   Norus — HÉROE: mensaje a la izquierda, producto a la derecha
   ---------------------------------------------------------------------
   Sustituye al "mazo" de pantallas giratorias (2026-09-21). Aquel mazo
   repetía dentro de un carrusel las mismas seis secciones que ya están,
   más desarrolladas, al bajar por la página: el visitante tenía que
   elegir entre dos formas de leer lo mismo, y la portada gastaba toda su
   altura en repetirse en vez de en enganchar.

   La portada ahora hace una sola cosa: dice qué hacemos (columna
   izquierda, alineada al mismo raíl que el logo de la cabecera) y lo
   ENSEÑA (columna derecha, el producto real funcionando dentro de la
   pantalla de un ordenador de sobremesa). A partir de ahí la página es
   un scroll continuo.

   POR QUÉ CSS 3D Y NO WEBGL
   El vídeo tiene que leerse nítido: es un informe con cifras y texto
   pequeño. Como textura de un plano de Three.js se remuestrea dos veces
   (vídeo → textura → lienzo) y pierde justo eso. Como `<video>` del DOM
   lo pinta el decodificador del sistema a resolución nativa, se puede
   pausar, subtitular y ampliar, y no depende de que WebGL arranque. El
   volumen del monitor —perspectiva, chasis con canto, peana y sombra de
   contacto— lo dan transformaciones CSS, que es lo más pequeño que
   resuelve el problema (ver skill pragmatic-code). El fondo 3D de la
   página sigue siendo WebGL: ahí sí aporta.

   Geometría en `nsa-hero.js`; aquí solo el estado en reposo.
===================================================================== */

:root {
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-press: cubic-bezier(0.23, 1, 0.32, 1);
}

/* Una propiedad personalizada es, por defecto, una cadena de texto: el
   navegador no sabe que `-19deg` y `-9deg` son dos puntos de una misma
   recta, así que una transición entre ambos DA UN SALTO en lugar de
   interpolar. Registrarlas con `@property` les pone tipo (`<angle>`,
   `<length>`) y a partir de ahí se animan como cualquier otra.
   `inherits: true` es obligatorio aquí: los valores se declaran en
   `.hero-rig` y se leen en `.rig-scene`, que es su hija.
   Si el navegador no soporta `@property` (muy minoritario ya), los
   ángulos se aplican igual — solo se pierde la interpolación. */
@property --rig-yaw     { syntax: "<angle>";  inherits: true; initial-value: 0deg; }
@property --rig-pitch   { syntax: "<angle>";  inherits: true; initial-value: 0deg; }
@property --rig-yaw-p   { syntax: "<angle>";  inherits: true; initial-value: 0deg; }
@property --rig-pitch-p { syntax: "<angle>";  inherits: true; initial-value: 0deg; }
@property --rig-lift    { syntax: "<length>"; inherits: true; initial-value: 0px; }
@property --rig-fade    { syntax: "<percentage>"; inherits: true; initial-value: 100%; }

/* ---------------------------------------------------------
   ARMAZÓN
--------------------------------------------------------- */
.hero {
  padding: 112px 0 48px;
  /* `svh` = alto de ventana con la barra del navegador VISIBLE. Con `vh`
     el móvil reserva sitio para una barra que sí está, el héroe se pasa
     de alto y el botón principal cae por debajo del pliegue. */
  min-height: 100svh;
  display: flex;
  /* `stretch` (y no el `center` de styles.css) para que el contenedor
     ocupe todo el alto del héroe: es lo que permite repartir el sobrante
     entre las dos columnas y la invitación a bajar, en vez de dejarlo
     todo amontonado en el centro con un hueco muerto debajo. */
  align-items: stretch;
}
.hero > .container {
  width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.hero-split {
  /* Se come el alto libre y centra dentro su propio contenido: en una
     pantalla alta las dos columnas quedan a media altura y la invitación
     a bajar cae justo en el pliegue; en una baja, todo se compacta sin
     que nada se solape. Un único reparto para los dos casos. */
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 56px;
  align-items: center;
  align-content: center;
}
/* El reparto no es 50/50: la columna del producto pesa algo más porque
   una pantalla apaisada necesita ancho para leerse, y el texto pierde
   legibilidad por encima de ~620 px de línea. */
@media (min-width: 1040px) {
  .hero-split {
    grid-template-columns: minmax(0, 0.94fr) minmax(0, 1.06fr);
    gap: 52px;
  }
}
/* A partir de 1240 px el contenedor deja de crecer, así que cada píxel
   que se le quite al texto se lo lleva el monitor — y en el monitor un
   píxel más de ancho es un píxel menos de reducción del vídeo, que es de
   donde sale la nitidez del informe. 0,90/1,10 es el reparto donde el
   titular todavía respira (≈525 px de columna) y la pantalla llega a su
   máximo sin salirse del raíl derecho. */
@media (min-width: 1240px) {
  .hero-split {
    grid-template-columns: minmax(0, 0.90fr) minmax(0, 1.10fr);
    gap: 64px;
  }
}

/* ---------------------------------------------------------
   COLUMNA IZQUIERDA — el mensaje
   Todo alineado a la izquierda, contra el mismo raíl que el logo.
--------------------------------------------------------- */
.hero-copy {
  position: relative;
  z-index: 3;
  text-align: left;
  max-width: 620px;
}
.hero-copy .badge { margin-bottom: 24px; }
.hero-copy h1 {
  /* Escala fluida atada al ancho de VENTANA, no del contenedor: por
     encima de 1280 px el contenedor deja de crecer y el titular tiene
     que dejar de crecer con él o se come la columna. */
  /* Escala fluida atada al ancho de VENTANA. El tope sube a 58 px: ahora
     que el contenedor crece con la pantalla, un titular congelado en 52
     se quedaba pequeño dentro de su propia columna en un monitor
     grande. */
  font-size: clamp(33px, 2.2vw + 16px, 58px);
  line-height: 1.06;
  letter-spacing: -0.025em;
  margin-bottom: 18px;
}
.hero-copy p.lead {
  font-size: clamp(16px, 0.5vw + 13px, 19px);
  line-height: 1.58;
  max-width: 560px;
  margin: 0 0 26px;
}

/* Los cuatro pilares. Mismo formato de tarjeta de cristal que el resto
   de la página (ver "SUPERFICIES" en nsa.css) para que la portada no
   invente un lenguaje propio que luego no se repite en ningún sitio. */
.hero .hero-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  max-width: 560px;
  margin: 0 0 28px;
}
.hero .stat {
  /* styles.css da a `.stat` un filete a la izquierda pensado para la
     fila de cuatro cifras del diseño anterior. Aquí son tarjetas. */
  border: 1px solid rgba(167, 139, 250, 0.16);
  border-radius: 14px;
  padding: 13px 16px 14px;
  text-align: left;
  background:
    linear-gradient(158deg, rgba(30, 37, 57, 0.82) 0%, rgba(14, 18, 30, 0.92) 60%, rgba(11, 14, 23, 0.96) 100%);
  box-shadow:
    0 18px 40px -26px rgba(0, 0, 0, 0.9),
    inset 0 1px 0 rgba(255, 255, 255, 0.06);
  transition: border-color 0.3s ease, transform 0.35s var(--ease-out-expo), box-shadow 0.35s ease;
}
@media (hover: hover) and (pointer: fine) {
  .hero .stat:hover {
    border-color: rgba(167, 139, 250, 0.42);
    transform: translateY(-3px);
    box-shadow:
      0 26px 50px -26px rgba(0, 0, 0, 0.95),
      inset 0 1px 0 rgba(255, 255, 255, 0.1);
  }
}
.hero .stat .num {
  display: block;
  font-size: 14px;
  font-weight: 800;
  letter-spacing: -0.005em;
  color: var(--text);
  margin-bottom: 5px;
}
.hero .stat .label {
  display: block;
  margin-top: 0; /* styles.css lo separaba de una cifra grande; aquí no hay cifra */
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--text-dim);
  text-transform: none;
  letter-spacing: 0;
}

/* Llamada a la acción: un botón sólido (el compromiso) y uno de cristal
   (la curiosidad). Sin `margin-bottom`, que la rejilla ya separa. */
.hero .hero-cta {
  justify-content: flex-start;
  gap: 14px;
  margin-bottom: 0;
}
.hero .hero-cta .btn { padding: 14px 24px; }

/* Línea de confianza bajo los botones. */
.hero-trust {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 18px;
  font-size: 13px;
  color: var(--text-dimmer);
}
.hero-trust svg { width: 15px; height: 15px; color: var(--lavender); flex: none; }

/* ---------------------------------------------------------
   COLUMNA DERECHA — el ordenador
   ---------------------------------------------------------
   El panel es una CAJA, no un rectángulo con sombras pintadas: cara
   frontal + cuatro cantos + trasera + la joroba del alojamiento, cada
   uno un plano real girado 90° dentro de la misma escena en perspectiva.
   Con `backface-visibility: hidden` solo se pinta el canto que mira a la
   cámara, así que el mismo marcado vale gire el monitor hacia donde gire
   y no hay que mantener a mano qué lado se ve.

   PROPORCIONES: son las de un monitor real de 27", no las que "quedan
   bien". Marco de 10 px sobre 610 de ancho ≈ 8 mm sobre 600; canto de
   24 px ≈ 23 mm. Un canto más gordo se lee enseguida como televisor de
   2008, y es el error más común de estas maquetas.

   ÁNGULO: 16° de giro y 4° de picado.

   EL SIGNO ES EL PUNTO DE VISTA, y conviene dejarlo escrito porque se
   presta a confusión. Con el giro NEGATIVO el canto que se pinta es el
   IZQUIERDO (`.panel-left`): el borde izquierdo del monitor se adelanta,
   el derecho se va al fondo, y eso es exactamente lo que se ve estando
   de pie a la izquierda del aparato. Con el signo positivo pasa lo
   contrario y se pinta `.panel-right`. Comprobado pintando cada canto de
   un color y mirando cuál sale, no deducido del papel.
   (El comentario anterior decía «canto derecho». Estaba mal.)

   SUBIDO de 11° a 16° el 2026-09-22, a petición: más sensación de mirar
   desde la izquierda. Los 11° eran el mínimo para que el canto midiera
   lo justo para leerse (≈5,3 px sobre 28 de grosor); 16° lo llevan a
   7,7 px, o sea casi la mitad más de volumen visible.
   El techo lo pone el informe, no el gusto: el escorzo comprime el vídeo
   en horizontal por cos θ, y ahí se juega la nitidez de unas cifras que
   ya van pequeñas. A 11° la compresión era del 1,8 %; a 16° es del
   3,9 %; a partir de ~20° (6 %) las columnas de números empiezan a
   emborronarse. 16 es el punto donde se gana perspectiva sin pagarlo en
   legibilidad.
--------------------------------------------------------- */
.hero-rig {
  position: relative;
  z-index: 2;

  /* EL ANCHO MÁXIMO DEL MONITOR, y ahora es fluido.
     Era un tope fijo de 680 px: a partir de ~1500 px de ventana el
     monitor dejaba de crecer y en un 1920 o un 2560 se quedaba pequeño en
     medio de la página. El motivo original de congelarlo era bueno —la
     peana era de tamaño FIJO, así que un panel más grande dejaba un pie
     proporcionalmente diminuto— pero ese motivo desaparece ahora que el
     pie escala con el panel (ver `--foot` en `.rig-scene`).
     El techo de 900 px no es estético: el vídeo del informe es de
     1280 px de ancho nativo y el hueco de pantalla se lleva el ancho
     menos los dos marcos, así que por encima de ~1300 el navegador
     empezaría a AMPLIAR el vídeo y las cifras se emborronarían. 900 deja
     un margen cómodo por debajo de ese límite.
     El suelo de 560 px y el 52vw son para que entre ambos extremos el
     crecimiento sea continuo y no a saltos. */
  --rig-w: clamp(560px, 52vw, 900px);

  --rig-yaw: -16deg;
  /* PICADO A CERO (2026-09-22). Combinar un giro en X con uno en Y no da
     «giro + picado»: da giro, picado Y ALABEO. El alabeo es el producto
     de los dos ángulos (4° × 16° ≈ 1,1°), y en pantalla es lo que hace
     que los cantos horizontales del marco dejen de estar a nivel — o sea,
     que la pantalla parezca torcida en vez de girada.
     Y lo que se pagaba por él era nada: con 4° de picado, la cara
     superior del panel mide 28 · sen 4° = 1,95 px. Dos píxeles de cara a
     cambio de un grado de inclinación en TODO el marco.
     Con el picado a cero, el único giro es el de Y, y un `rotateY` puro
     deja los horizontales horizontales: lo que queda es la convergencia
     de la perspectiva —el canto cercano un poco más alto que el lejano,
     que es lo correcto— y no una inclinación en bloque. */
  --rig-pitch: 0deg;
  --rig-yaw-p: 0deg;
  --rig-pitch-p: 0deg;
  --rig-lift: 0px;
  --rig-fade: 100%;

  /* EL RELLENO QUE SALVA LA MESA (2026-09-22, quinta pasada).
     `.hero-rig` es quien lleva la máscara de disolución al bajar, y el
     `mask-clip` por defecto es `border-box`: RECORTA a cuadro todo lo que
     se salga de su caja. La mesa sobresale 121 px por debajo de la escena
     (medido a 780 px de ventana: canto de `.hero-rig` en 989, canto de la
     mesa en 1110), y el `--rig-lift` del paralaje la baja hasta 64 px
     más. Resultado: en cuanto la página se movía un píxel, la mitad de
     abajo de la mesa —el arco delantero y la luz de contacto— desaparecía
     tras una horizontal seca. No era la disolución: era el recorte de la
     máscara, que aparecía de golpe con ella.
     200 px de relleno cubren los 121 + 64 con margen. El margen negativo
     los devuelve: la caja de margen mide lo mismo que antes, así que la
     rejilla del héroe no se entera. */
  padding-bottom: 200px;
  margin-bottom: -200px;
  /* La caja ahora sobra por abajo, y ahí no hay nada que pulsar. Sin esto
     taparía el enlace «Sigue bajando» cuando el monitor va debajo del
     texto (por debajo de 1040 px). Los clics que sí importan —la pantalla
     y los dos botones de la barbilla— los recupera `.rig-scene`. */
  pointer-events: none;
}
/* La caja de tamaño ORIGINAL, la que no ve el relleno de `.hero-rig`.
   Existe para que los porcentajes de `.rig-glow` sigan midiéndose contra
   la escena y no contra la caja estirada: con el relleno y sin esto, el
   resplandor crecía un 40 % y se derramaba sobre la mesa.

   AQUÍ VIVE LA CÁMARA, y tiene que vivir aquí obligatoriamente.
   `perspective` solo afecta a los HIJOS DIRECTOS del elemento que la
   declara. Estuvo en `.hero-rig` hasta el 2026-09-22 y funcionaba porque
   `.rig-scene` colgaba directamente de él; al meter `.rig-stage` por
   medio, la escena pasó a ser NIETA y se quedó sin perspectiva sin que
   saltara ningún error. El monitor dejó de estar en perspectiva y pasó a
   estar simplemente SESGADO: los cantos de arriba y de abajo caían
   exactamente paralelos a −4,12° (medido colocando marcas en las cuatro
   esquinas y leyendo sus posiciones), las dos verticales medían lo mismo
   al píxel y no había ni un punto de fuga. Eso es una lámina girada, no
   una caja — y se ve como una pantalla «doblada».
   Lección: cada vez que se interponga un elemento entre la cámara y la
   escena, la cámara se muda con la escena.

   De paso se arregla algo que iba con el mismo fallo: los porcentajes de
   `perspective-origin` se resuelven contra la caja de relleno del
   elemento que la declara. En `.hero-rig`, con sus 200 px de relleno
   inferior, el 40 % vertical caía en 276 px en vez de en 196 — el ojo se
   había bajado 80 px y miraba el monitor desde ABAJO. Aquí vuelve a
   medirse contra la escena.

   Distancia del ojo: larga (2000 px sobre un monitor de ~630) porque la
   perspectiva aquí tiene que insinuar volumen, no deformar. Un valor
   corto abre las verticales en abanico y delata la maqueta al instante.

   Y la CÁMARA va corrida a la izquierda (40 %, antes 44). Girar el objeto
   y dejar el ojo donde estaba es media verdad: lo que de verdad dice
   «estoy mirando esto desde la izquierda» es que el punto de fuga caiga a
   la izquierda del aparato. */
.rig-stage {
  position: relative;
  perspective: 2000px;
  perspective-origin: 40% 40%;

  /* El tope de ancho se muda aquí desde `.rig-scene`, y no es cosmético:
     así la caja de la escena y la del escenario miden SIEMPRE lo mismo, y
     eso es lo que hace que `cqw` sirva de regla. */
  width: min(100%, var(--rig-w));
  margin-left: auto;

  /* LA REGLA. `1cqw` = el 1 % del ancho de esta caja, o sea del ancho real
     del monitor — que es `min(columna disponible, --rig-w)` y por tanto no
     se puede escribir en `vw` ni en `%` desde dentro.
     Con esto, cada pieza del pie se expresa como una fracción del monitor
     y la proporción se mantiene sola en cualquier pantalla, en vez de
     reajustarse a mano por breakpoint.
     Va en `.rig-stage` y NO en `.rig-scene` a propósito: `container-type`
     aplica `contain: layout`, que obliga al elemento a aplanarse, y
     aplanar `.rig-scene` destruiría la caja 3D del panel. Aquí no estorba
     porque `.rig-stage` ya era un plano. */
  container-type: inline-size;
}

.rig-scene {
  position: relative;
  /* Contrapeso del `pointer-events: none` de `.hero-rig`: aquí dentro
     están la pantalla (que abre la demostración) y los dos botones. */
  pointer-events: auto;

  /* LA MEDIDA MAESTRA DEL PIE: el ancho del disco. Todo lo demás de la
     peana —alto del conjunto, cuello, casquillo, penumbra, y hasta dónde
     se centra la mesa— sale de aquí multiplicado por una fracción fija.
     Las fracciones son las del diseño original medido a 637 px de
     monitor: disco 218, cuello 72×79, alto 100, etc.

     34,22cqw mantiene el disco en el 34 % del ancho del panel, que es la
     proporción de un monitor de 27" real y justo lo que se perdía cuando
     la peana era de tamaño fijo y el panel crecía.

     LOS DOS TOPES SON LOS QUE IMPORTAN:
     · 170 px de suelo. Por debajo de ~500 px de monitor (o sea, en un
       teléfono) el 34 % daría un pie de 117 px, y a ese tamaño la peana
       desaparece y el monitor flota. 170 es exactamente el valor que
       estaba escrito a mano en el breakpoint de móvil — ahora sale de la
       fórmula, y de paso desaparece el salto que había justo en 720 px.
     · 290 px de techo, para que en una pantalla muy grande el pie no se
       convierta en una plataforma.

     Y el GROSOR del panel escala con lo mismo (28/218 = 12,84 %): si no,
     un monitor de 900 px de ancho se vería con el mismo canto de 28 px
     que uno de 560 y parecería una lámina. */
  --foot: clamp(170px, 34.22cqw, 290px);
  --panel-depth: calc(var(--foot) * 0.1284);
  --hump-depth: calc(var(--foot) * 0.1376);

  transform-style: preserve-3d;
  transform:
    translateY(var(--rig-lift))
    rotateX(calc(var(--rig-pitch) + var(--rig-pitch-p)))
    rotateY(calc(var(--rig-yaw) + var(--rig-yaw-p)));
  /* SIN `will-change: transform`. Le dice al navegador que rasterice la
     capa una vez y la reutilice transformada — justo lo contrario de lo
     que quiere un vídeo que tiene que salir nítido. */
}

/* Luz ambiente por detrás y derrame de la pantalla sobre la mesa. Fuera
   del `preserve-3d`: es luz, no un objeto de la escena. */
.rig-glow {
  position: absolute;
  left: -16%;
  right: -16%;
  top: -18%;
  bottom: -10%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(ellipse 56% 46% at 52% 34%, rgba(139, 92, 246, 0.36), transparent 70%),
    radial-gradient(ellipse 38% 30% at 42% 58%, rgba(96, 165, 250, 0.15), transparent 72%);
  filter: blur(36px);
}
/* El derrame: la pista que convence de que la pantalla está encendida y
   de que delante de ella hay una superficie. */
.rig-glow::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: 6%;
  height: 90px;
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(125, 211, 252, 0.20) 0%, rgba(139, 92, 246, 0.13) 46%, transparent 74%);
}

/* =========== EL PANEL: una caja de seis caras =========== */
.panel {
  position: relative;
  transform-style: preserve-3d;
}

.panel-face,
.panel-back,
.panel-hump {
  position: absolute;
  /* Solo se pinta la cara cuyo frente mira a la cámara. Es lo que hace
     que no haya que decidir por CSS si el monitor gira a un lado o al
     otro: el navegador descarta sola la que queda de espaldas. */
  backface-visibility: hidden;
  pointer-events: none;
}

/* --- Cantos laterales ---
   `transform-origin` en el borde que toca la cara frontal + un giro de
   90° que los manda HACIA ATRÁS (el signo importa: con el contrario
   saldrían como dos aletas clavadas hacia el espectador). */
.panel-left,
.panel-right {
  top: 3px;
  bottom: 3px;
  width: var(--panel-depth);
}
.panel-left {
  left: 0;
  transform-origin: left center;
  transform: rotateY(90deg);
  /* Su borde izquierdo es el que queda delante: el degradado va de la
     luz (frente) a la sombra (fondo). */
  background: linear-gradient(to right, #3D4763 0%, #1C2231 46%, #0C0F18 100%);
}
.panel-right {
  right: 0;
  transform-origin: right center;
  transform: rotateY(-90deg);
  /* Aquí es al revés: el borde derecho es el de delante. */
  background: linear-gradient(to right, #0C0F18 0%, #1C2231 54%, #3D4763 100%);
}

.panel-top,
.panel-bottom {
  left: 3px;
  right: 3px;
  height: var(--panel-depth);
}
.panel-top {
  top: 0;
  transform-origin: center top;
  transform: rotateX(-90deg);
  /* Mira al techo: es la cara que más luz recibe, y con 3,5° de picado
     es la que de verdad cuenta que esto tiene fondo. */
  background: linear-gradient(to bottom, #6D7A9B 0%, #313A51 44%, #14192400 100%);
}
.panel-bottom {
  bottom: 0;
  transform-origin: center bottom;
  transform: rotateX(90deg);
  /* Mira al suelo: sombra propia, casi negra. */
  background: linear-gradient(to bottom, #05070C 0%, #0A0D15 66%, #171D2A 100%);
}

/* Trasera y alojamiento. No se ven de frente, pero recortan la silueta
   por el lado por el que asoma el monitor. */
.panel-back {
  inset: 0;
  transform: translateZ(calc(var(--panel-depth) * -1));
  border-radius: 14px;
  background: linear-gradient(168deg, #1A2130 0%, #0E121B 56%, #05070C 100%);
}
.panel-hump {
  left: 15%;
  right: 15%;
  top: 11%;
  bottom: 16%;
  transform: translateZ(calc((var(--panel-depth) + var(--hump-depth)) * -1));
  border-radius: 12px;
  background: linear-gradient(170deg, #141A26 0%, #0A0D14 58%, #04060A 100%);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.03);
}

/* --- Cara frontal: el aluminio --- */
.panel-front {
  position: relative;
  z-index: 2;
  padding: 10px 10px 0;
  border-radius: 14px;
  /* Aluminio anodizado: la luz entra por arriba a la izquierda, cae
     rápido y el marco se apaga hacia abajo. Las paradas van juntas
     arriba (el metal tiene un brillo CORTO, no un degradado suave) y
     separadas abajo. */
  background: linear-gradient(
    166deg,
    #58648333 0%,
    #4B5673 3%,
    #303954 10%,
    #222939 26%,
    #1A2030 52%,
    #141926 78%,
    #0D1119 100%
  );
  box-shadow:
    /* El chaflán del canto superior: un filo de luz de UN píxel. Es el
       detalle que más dice "metal mecanizado" por lo que cuesta, y el
       primero que se pierde cuando se sustituye por un degradado suave. */
    inset 0 1px 0 rgba(255, 255, 255, 0.42),
    inset 2px 0 0 rgba(255, 255, 255, 0.05),
    inset -1px 0 0 rgba(0, 0, 0, 0.6),
    inset 0 -1px 0 rgba(0, 0, 0, 0.72),
    /* sombra proyectada sobre la página */
    0 54px 100px -44px rgba(0, 0, 0, 0.96),
    0 18px 40px -24px rgba(0, 0, 0, 0.7);
}

/* --- La pantalla --- */
.monitor-screen {
  position: relative;
  /* Proporción nativa del vídeo (1280×716): declararla evita el salto de
     maquetación entre que llega el HTML y llega el primer fotograma. */
  aspect-ratio: 1280 / 716;
  border-radius: 4px;
  overflow: hidden;
  /* Azul marino del propio informe: mientras el vídeo carga, el hueco ya
     es del color que va a tener, no un rectángulo negro. */
  background: linear-gradient(170deg, #17364B 0%, #0E2334 55%, #0A1927 100%);
  /* Máscara negra entre el marco y el cristal + el cristal hundido
     respecto al aluminio. Los dos detalles que separan una pantalla de
     una foto pegada sobre un rectángulo. */
  box-shadow:
    inset 0 0 0 1px #000,
    inset 0 2px 12px rgba(0, 0, 0, 0.5);
  cursor: zoom-in;
}
.monitor-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* SIN `transform: scale()`. Escalar por transformación obliga al
     compositor a remuestrear el fotograma ya decodificado; el resultado
     es exactamente la falta de nitidez que se veía en las cifras del
     informe. Si hiciera falta recortar el borde de la grabación, se hace
     con el TAMAÑO de la caja (que lo resuelve el decodificador a
     resolución nativa), nunca con `transform`. */
}

/* Reflejo especular del cristal. `screen` sobre un fondo oscuro solo
   puede aclarar, así que nunca ensucia los negros del informe — pero
   aclararlos de más le quita contraste, y el contraste es la mitad de la
   sensación de nitidez. De ahí que sea una banda estrecha y floja. */
.screen-sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background: linear-gradient(
    104deg,
    transparent 34%,
    rgba(255, 255, 255, 0.045) 44%,
    rgba(214, 229, 255, 0.018) 52%,
    transparent 62%
  );
}
/* Reflejo del entorno: el cristal devuelve el violeta de la propia
   página. Sutil hasta el límite de lo perceptible; se nota al quitarlo. */
.screen-env {
  position: absolute;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  background: linear-gradient(to bottom, rgba(167, 139, 250, 0.055) 0%, transparent 32%);
}
/* Viñeta. Antes llegaba a 0.42 de negro en las esquinas y se estaba
   comiendo el informe; ahora solo toca el último tramo de la esquina. */
.screen-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 104% 104% at 50% 44%, transparent 64%, rgba(0, 0, 0, 0.26) 100%);
}

/* --- Barbilla: los dos controles, a la derecha --- */
.monitor-chin {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 7px;
  height: 34px;
  padding: 0 5px;
}
/* Obligatorio, no decorativo: hay movimiento automático de más de cinco
   segundos y la WCAG 2.2 (2.2.2 «Pausar, detener, ocultar») exige poder
   pararlo. El de ampliar va a su derecha porque dentro del marco el
   informe se ve pero no se LEE. */
.chin-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 25px;
  height: 25px;
  flex: none;
  padding: 0;
  border: 1px solid rgba(248, 250, 252, 0.13);
  border-radius: 7px;
  background: rgba(248, 250, 252, 0.05);
  color: rgba(248, 250, 252, 0.55);
  cursor: pointer;
  transition: color 0.2s ease, background 0.2s ease, border-color 0.2s ease, transform 0.16s var(--ease-press);
}
.chin-btn svg { width: 12px; height: 12px; }
.chin-btn .ico-pause { display: block; }
.chin-btn .ico-play { display: none; }
.chin-btn[data-state="paused"] .ico-pause { display: none; }
.chin-btn[data-state="paused"] .ico-play { display: block; }
@media (hover: hover) and (pointer: fine) {
  .chin-btn:hover {
    color: var(--text);
    background: rgba(167, 139, 250, 0.18);
    border-color: rgba(167, 139, 250, 0.55);
  }
}
.chin-btn:active { transform: scale(0.92); }
.chin-btn:focus-visible { outline: 2px solid var(--lavender); outline-offset: 2px; }

/* =========== LA PEANA ===========
   CORREGIDO 2026-09-21 (segunda pasada): el cuello y el disco se veían
   como DOS PIEZAS SUELTAS, y no era una impresión — estaba medido. El
   cuello terminaba en y=643,9 y el disco arrancaba en y=654,6: once
   píxeles de aire en el centro y casi catorce en los costados del
   cuello, porque el disco se tumba con `rotateX` alrededor del 32 % de
   su alto y esa rotación lo baja respecto de donde lo pone `top`. Un
   monitor cuyo pie no toca su propia base es justo lo que delata la
   maqueta.

   La regla es la de cualquier pie real: el cuello no se posa ENCIMA del
   disco, se planta EN él.

   REVISADO 2026-09-22 (tercera pasada). Hasta ahora el disco iba después
   en el marcado y por tanto se pintaba SOBRE el cuello, tapándole los
   últimos 16 px. Funcionaba para cerrar la unión, pero la lectura era
   falsa: una columna que desaparece detrás de su propia base parece una
   pegatina puesta delante de un óvalo, no una pieza que sale de ella.
   En un pie de monitor real la columna nace del CENTRO de la base, así
   que tapa la mitad TRASERA del disco y solo la mitad delantera queda
   por delante de ella. El orden del marcado quedó invertido —disco
   primero, cuello encima— y eso se mantiene.

   REHECHO 2026-09-22 (cuarta pasada). Lo que cerraba la unión era un
   casquillo elíptico dibujado APARTE (`.stand-neck::after`, 94×26 px,
   degradado radial propio y un filo de luz en su borde superior). Dos
   piezas con dos materiales distintos y un filo horizontal entre ellas
   es, literalmente, la definición de «tiene algo puesto delante»: se
   veía como una pastilla pegada sobre el pie, no como el pie.

   Ahora el cuello es UNA SOLA PIEZA. Tres decisiones:

   · EL FONDO DEL CUELLO ES CURVO, no un corte recto. Se consigue con
     `border-radius` elíptico en las dos esquinas de abajo (50 % en
     horizontal, 13 % en vertical), que dibuja un arco continuo de lado a
     lado. No hace falta ningún pseudoelemento: la curva es del mismo
     elemento y por tanto del mismo degradado, así que no hay costura
     posible.
   · ESA CURVA ES LA SECCIÓN REAL DEL PIE. Un cilindro de 66 px de
     diámetro, tumbado en el plano de la peana (72°), se proyecta como
     una elipse de 66 × 66·cos 72° = 20,4 px. Media elipse son 10,2 px,
     que es el 13 % de los 78 px de alto del cuello — de ahí el 13 %.
   · EL PUNTO MÁS ANCHO CAE EN EL CENTRO DEL DISCO. La silueta de un
     cilindro es más ancha justo en el plano de su sección: 78 − 10,2 =
     67,8, y el centro visual del disco está en 68,1. Cuadran, y por eso
     el pie se lee plantado EN la base y no apoyado encima.

   El ancho baja de 88 a 66 px, y no es estética: 88 sobre una peana de
   128 px de fondo es el 69 % — un pie que se come su propia base. Con
   66 quedan ~10 px de labio delantero por delante del cuello, que es la
   proporción de un monitor real (columna ≈ 70 mm, fondo de peana
   ≈ 200 mm) y lo que hace que se vea base POR DELANTE del pie.
--------------------------------------------------------- */
.stand {
  position: relative;
  /* 100/218. Todas las fracciones de este bloque son medidas del diseño
     original divididas por el ancho del disco; con `--foot` fijo en
     218 px salen exactamente los píxeles de antes. */
  height: calc(var(--foot) * 0.4587);
  /* Nace por detrás del panel, no en su plano: un cuello que arranca a
     ras de la cara frontal es el fallo que hace que el monitor parezca
     una pegatina de pie. */
  transform: translateZ(calc(var(--panel-depth) * -0.85));

  /* LA TRANSLUCIDEZ VA AQUÍ, UNA VEZ Y PARA LAS DOS PIEZAS.
     Es la diferencia entre un pie translúcido y un pie de otro material:
     con una sola opacidad sobre el grupo, el cuello y el disco conservan
     intactas sus relaciones de luz —siguen siendo el mismo metal del
     panel, solo que más tenue— y además, al componerse juntos ANTES de
     mezclarse con la página, donde se solapan no se oscurecen dos veces.
     Repartir alfas gradiente a gradiente hace lo contrario: cada pieza
     coge su propio tono y vuelven a leerse como dos objetos.

     0,72 es donde el pie sigue leyéndose como aparato pero ya no compite
     con la pantalla, que es lo que tiene que mandar en el primer pliegue:
     el fondo de estrellas se intuye a través del metal y el conjunto se
     asienta en la página en vez de recortarse contra ella. */
  opacity: 0.72;

  /* Y el remate de abajo se alarga. Antes era un corte casi seco en los
     últimos seis píxeles, por debajo del disco, donde no había nada que
     desvanecer: el canto de la peana seguía terminando en un arco nítido.
     Ahora la caída empieza en el 58 % —o sea dentro del propio disco— y
     llega al 30 % en el labio. El pie se apaga de arriba abajo y el
     último contorno se deshace contra el fondo en vez de recortarse.
     El mínimo no es cero a propósito: por debajo de ~0,25 el labio
     delantero desaparece y el monitor vuelve a flotar.
     Va SOLO aquí. El vídeo no lleva máscara: enmascarar obliga al
     navegador a recomponer la capa y eso le cuesta nitidez justo a lo
     único que tiene que salir nítido. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 58%, rgba(0, 0, 0, 0.82) 74%, rgba(0, 0, 0, 0.55) 86%, rgba(0, 0, 0, 0.3) 96%, rgba(0, 0, 0, 0.16) 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 58%, rgba(0, 0, 0, 0.82) 74%, rgba(0, 0, 0, 0.55) 86%, rgba(0, 0, 0, 0.3) 96%, rgba(0, 0, 0, 0.16) 100%);
}
.stand-neck {
  display: block;
  position: absolute;
  left: 50%;
  top: 0;
  /* 72/218. Y 72 es la CAJA, no la columna: la columna ocupa el 75 %
     central (54 px) y el resto lo usa el acuerdo con la peana. */
  width: calc(var(--foot) * 0.3303);
  /* 79/218. Y 79 ≈ 68,1 (centro visual del disco) + 11,1 (media sección
     del cilindro escorzada). O sea: el borde de abajo de la caja es el
     labio DELANTERO de la sección, y el arco de `border-radius` lo
     dibuja. La identidad se conserva a cualquier escala porque las dos
     medidas son fracciones del mismo número. */
  height: calc(var(--foot) * 0.3624);
  transform: translateX(-50%);
  /* El fondo curvo. Horizontal 50 % (los dos arcos se encuentran exactos
     en el centro, sin tramo recto entre ellos) y vertical 14 % = 11,1 px
     = media sección. El `clip-path` de abajo llega a ancho completo antes
     del 88 %, así que no toca esta curva: cada uno recorta su tramo. */
  border-radius: 0 0 50% 50% / 0 0 14% 14%;
  /* LA COLUMNA ES DE ANCHO CONSTANTE, y esto es lo que separa un pie de
     monitor de un pie de lámpara. La primera versión de esta cuarta
     pasada iba abriéndose desde arriba (32 px → 66) y a tamaño real
     colaba, pero ampliada 3× la silueta era una trompeta: el ojo lee la
     PROPORCIÓN de apertura, no los píxeles.
     Ahora son 54 px rectos hasta el 70 % del recorrido, y el acuerdo con
     la peana se concentra en el último 18 % (54 → 72, un factor de 1,33
     contra el 2,08 de antes). Un acuerdo corto y marcado lee como una
     pieza mecanizada; una apertura larga y suave, como una lámpara.
     Tres vértices en el acuerdo por lado, no uno: con uno solo el quiebro
     se ve facetado a este tamaño. */
  clip-path: polygon(
    12.5% 0%, 87.5% 0%,
    87.5% 70%, 90% 77%, 95% 83.5%, 100% 88%,
    100% 100%, 0% 100%,
    0% 88%, 5% 83.5%, 10% 77%, 12.5% 70%
  );
  /* EL MATERIAL ES EL DEL PANEL, y eso no es una analogía: son los mismos
     valores. El cuerpo sale de `.panel-left` (#3D4763 → #1C2231 →
     #0C0F18) y los tramos oscuros de `.panel-front` (#222939, #141926,
     #0D1119). Un pie de otro material —por transparente o por bonito que
     sea— rompe justo lo que se está contando: que la pantalla y su
     soporte son un mismo aparato.
     La translucidez NO va aquí: va en `.stand`, de una vez y para las dos
     piezas. Repartirla por degradado obliga a cuadrar catorce alfas entre
     el cuello y el disco, y basta que una no case para que vuelvan a
     leerse como dos objetos. */
  background:
    /* 1 · Penumbra de contacto: la sombra que la propia base devuelve
       sobre el último tramo del pie. Hace que la curva se lea como una
       pieza que SE METE en la peana y no como un canto redondeado posado
       encima. */
    radial-gradient(ellipse 112% 24% at 50% 100%,
      rgba(0, 0, 0, 0.5) 0%,
      rgba(0, 0, 0, 0.26) 46%,
      transparent 76%),
    /* 2 · La caída de luz de arriba abajo, la misma que lleva la cara
       frontal del panel: filo claro en el canto de arriba y el metal
       apagándose hacia el suelo. Va en su propia capa para poder dejar la
       de abajo en horizontal puro. */
    linear-gradient(to bottom,
      rgba(255, 255, 255, 0.06) 0%,
      rgba(255, 255, 255, 0) 16%,
      rgba(0, 0, 0, 0.16) 70%,
      rgba(0, 0, 0, 0.3) 100%),
    /* 3 · El cilindrado. Las paradas están colocadas para que el tramo
       oscuro caiga DENTRO del 12,5–87,5 % que ocupa la columna: si no,
       los extremos oscuros se los lleva el recorte y la columna sale con
       los cantos grises, o sea plana. Los extremos de la caja (0 y 100 %)
       quedan casi negros, y eso sombrea el reverso del acuerdo con la
       peana.
       Va en `to right` y no en 96deg como el panel: 6° sobre 79 px de
       alto corren las paradas 8 px, un 11 % del ancho, y con el recorte
       tan ceñido a los cantos eso despega el brillo del canto. La
       inclinación de la luz la pone la capa 2. */
    linear-gradient(to right,
      #05070C 0%,
      #0C0F18 10%,
      #222939 26%,
      #3D4763 50%,
      #1C2231 74%,
      #0D1119 90%,
      #05070C 100%);
}
/* Oclusión donde el cuello se mete bajo el panel. Gana trabajo al
   volverse translúcida la pieza: es lo que impide que el pie parezca
   despegado del panel. Por eso se alarga de 15 a 19 px. */
.stand-neck i {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: calc(var(--foot) * 0.0872); /* 19/218 */
  background: linear-gradient(to bottom, rgba(0, 0, 0, 0.84) 0%, rgba(0, 0, 0, 0.32) 54%, transparent 100%);
}
/* El disco se tumba de verdad: `rotateX` lo escorza igual que lo
   escorzaría la cámara. Va en posición absoluta porque en flujo ocuparía
   sus 128 px de alto de maqueta cuando visualmente mide 40, y dejaría un
   agujero debajo. Ancho ≈ 35 % del panel, que es la proporción real de
   un monitor de 27". */
.stand-base {
  display: block;
  position: absolute;
  left: 50%;
  /* 20, no 36. `rotateX` gira alrededor del 32 % del alto del disco, así
     que la mitad de arriba se «pliega» hacia abajo y el labio trasero
     acaba 16 px más bajo de lo que dice `top`: ese desfase era el hueco.
     Con 20 px, el labio cruza el cuello a media altura y el cuello sigue
     16 px por debajo, dentro del disco. */
  top: calc(var(--foot) * 0.0917);    /* 20/218 */
  width: var(--foot);
  height: calc(var(--foot) * 0.5872); /* 128/218 */
  transform: translateX(-50%) rotateX(72deg);
  transform-origin: center 32%;
  border-radius: 50%;
  /* Claro por el borde de delante (el que mira a la luz de la escena) y
     apagándose hacia el fondo.
     EL FOCO SE ADELANTA del 78 % al 90 % (2026-09-22, cuarta pasada).
     Al 78 % la zona clara del disco caía en y = 237 de la escena, que es
     exactamente donde termina el cuello: o sea que lo único iluminado de
     la peana quedaba TAPADO por el pie, y el labio delantero —los 9 px
     que cuentan que hay base por delante— se pintaba con el tramo oscuro
     del degradado. Se veía un bulto negro, no un apoyo.
     Al 90 % la zona clara cae ya por delante del cuello.

     Mismo metal que el cuello y que el panel: #414C6C y #262E42 son los
     claros de `.panel-left`, #141926 y #080B13 los oscuros de
     `.panel-front`. El anillo de 1 px es el chaflán mecanizado, el mismo
     recurso que el filo de luz del canto superior del marco. */
  background:
    radial-gradient(ellipse 62% 78% at 50% 90%, #414C6C 0%, #262E42 32%, #141926 66%, #080B13 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}
/* Oclusión ambiental alrededor del pie: la penumbra que cualquier
   columna deja sobre su propia base.
   VA AL 50 %, y ahora sí se calcula en una línea: el cuello entra por el
   CENTRO del disco, y el centro de la elipse coincide con el centro de
   su propia caja sin rotar. Antes iba al 58 % porque perseguía al
   casquillo, que estaba 10 px por delante del centro — la penumbra
   quedaba descentrada hacia el espectador y ayudaba a que el conjunto se
   leyera como dos piezas.
   En este plano un tramo vertical se estira ~3× (1 / cos 72°), de ahí
   que la elipse sea mucho más alta que ancha sin rotar.
   Suave a propósito: con más peso el disco se lee como una rosquilla. */
.stand-base i {
  position: absolute;
  left: 50%;
  top: 50%;
  /* Más pequeña que antes (124×84). Una penumbra que ocupa casi todo el
     fondo del disco se come el labio delantero, y el labio es lo único
     que cuenta que hay base POR DELANTE del pie. */
  width: calc(var(--foot) * 0.4771);  /* 104/218 */
  height: calc(var(--foot) * 0.3486); /* 76/218 */
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.44) 0%, rgba(0, 0, 0, 0.22) 46%, transparent 76%);
}

/* RETIRADAS el 2026-09-22: `.rig-contact` (sombra de contacto) y
   `.rig-floor` (línea de horizonte). Las dos existían para insinuar una
   superficie cuando no había ninguna; ahora que hay mesa, estorban.

   · La sombra era una elipse ancha y desenfocada bajo la peana. Esa
     forma —penumbra ancha y floja, sin núcleo apretado— es justamente
     la firma visual de un objeto que LEVITA, no de uno que apoya: es la
     distinción clásica entre *key shadow* (apretada, asienta) y
     *ambient shadow* (difusa, separa del fondo). Encima, sobre CRISTAL
     una sombra proyectada es físicamente dudosa: la luz atraviesa.
     Lo que ancla un objeto sobre una superficie reflectante no es la
     sombra, es el REFLEJO que arranca en el punto de contacto — y de
     eso se encarga ahora `.rig-table::after`.
   · La línea de horizonte era un filo de luz RECTO. Con una mesa
     ovalada contradice la forma que se está contando: el canto de un
     óvalo es una curva. Su trabajo lo hace ahora el filo del propio
     óvalo, que además sí lo describe bien. */

/* =========== LA MESA DE CRISTAL ===========
   REHECHA el 2026-09-22. La primera versión (21/09) era un degradado
   suave bajo el monitor, y no bastaba: el disco de la peana seguía
   terminando en un arco nítido con el campo de estrellas llegando justo
   hasta él. Una luz difusa sobre el fondo no es una superficie — no se
   sabe si el monitor está APOYADO o simplemente iluminando el vacío.

   Lo que de verdad convence de que algo descansa sobre una mesa no es la
   luz: es que la mesa VELE lo que hay detrás y DEVUELVA lo que hay
   delante. Aquí lo hacen dos cosas:

   1. El velo. Sobre un fondo casi negro, una capa fría translúcida no
      tapa las estrellas: las deja pasar con MENOS contraste, que es
      exactamente lo que hace un vidrio. La zona de la mesa es la que
      tiene el fondo un punto más lechoso, y el ojo lo lee como una
      superficie interpuesta, no como una luz encima.
   2. El reflejo. Sobre cristal, en una habitación oscura, de una
      pantalla encendida no se ve la imagen: se ve una mancha luminosa
      estirada hacia el espectador. Eso es `::before`, y es lo que ancla
      el monitor a la superficie.

   PROBADO Y DESCARTADO: `backdrop-filter: blur()`. Es la forma «buena»
   de hacer un cristal —desenfoca de verdad las estrellas de detrás— y
   se ve algo mejor que el velo pintado. Se descarta por una razón
   estructural, no por ajuste fino: el desenfoque de fondo hay que
   recalcularlo cada vez que cambia lo que hay detrás, y lo que hay
   detrás es un canvas de partículas que se repinta CADA FOTOGRAMA. O
   sea, un filtro a pantalla parcial en bucle permanente, y encima justo
   en la portada, que es donde peor sienta perder fluidez.
   (No hay cifra aquí a propósito: medirlo dentro del panel de vista
   previa no vale, porque ese panel congela `requestAnimationFrame`
   cuando no está visible y los números salen inventados. Quien quiera el
   dato, que lo saque del panel de rendimiento de un navegador de
   verdad.)
   Si algún día el fondo deja de animarse, el coste desaparece y merece
   la pena recuperarlo.

   FORMA: OVALADA, con el monitor en su CENTRO (2026-09-22). Antes era
   una cuña que arrancaba en el disco y se iba hacia el espectador, o
   sea que el monitor quedaba en el BORDE TRASERO de la mesa — de pie en
   el canto, que es una postura que nadie adopta con un ordenador. Un
   óvalo centrado en el punto de apoyo resuelve las dos cosas a la vez:
   el monitor queda en medio, y la forma se lee sola.
   Y es más barato de lo que parece: una elipse vista desde 4° de picado
   se proyecta como otra elipse, así que basta un `border-radius: 50%`
   sobre una caja achatada. No hace falta rotar nada.
   La mitad trasera del óvalo queda TAPADA por el panel, que es opaco y
   va delante en Z — igual que en una foto real, donde de la mesa solo
   ves lo que el aparato no oculta.

   DÓNDE VIVE, y no es opcional: dentro de `.rig-scene`. Estuvo colgando
   de `.hero-rig` hasta el 2026-09-22 y ahí era imposible que funcionara:
   `.hero-rig` lleva la `mask-image` que disuelve el monitor al hacer
   scroll, y el `mask-clip` por defecto (`border-box`) RECORTA todo lo
   que se salga de su caja — un canto que además cae ~24 px POR ENCIMA
   del labio del disco. O sea que la mesa se cortaba antes incluso de
   llegar al punto de apoyo: de 300 px de superficie sobrevivían unos 60,
   en forma de banda con un corte recto. Eso era lo que se veía como «la
   mesa empieza después del soporte».
   (`mask-clip: no-clip` en `.hero-rig` también lo arregla y está
   soportado en Chromium, pero deja la mesa a merced de una propiedad con
   soporte desigual para algo que aquí se resuelve colocándola en el sitio
   correcto.)

   Se ordena en profundidad con `translateZ`: dentro de un `preserve-3d`
   el orden de pintado lo decide la Z, no el `z-index`. Es un plano SIN
   rotar, así que no atraviesa a nadie y no hay ordenado ambiguo que
   pueda salir mal. */
.rig-table {
  position: absolute;
  left: 50%;
  /* El CENTRO del óvalo cae en el centro visual del disco, que está 32 px
     por encima del canto inferior de la escena. No es una estimación: el
     disco ocupa de 48,3 a 87,9 dentro de `.stand` (alto 100), o sea
     centro en 68,1 → 100 − 68 = 32. Con `translate(-50%, -50%)` el
     centro de la caja aterriza justo ahí.
     32/218 del ancho del disco. Antes iba en píxeles fijos y funcionaba
     porque la peana también lo era; ahora que el pie escala, la mesa
     tiene que seguirlo o el óvalo se descentra del punto de apoyo. */
  top: calc(100% - var(--foot) * 0.1468);
  /* EL CORTE LATERAL (arreglado 2026-09-22, cuarta pasada).
     Con 176 %/1120 px el óvalo medía 1097 px y arrancaba en x = 498 con
     la ventana en 1430: se salía 165 px por la derecha y `overflow:
     hidden` de `.hero` lo cortaba con una vertical limpia, justo por
     encima del filo encendido. Eso era «la mesa tiene un corte» — y
     cambiaba de sitio con cada ancho de ventana, que es lo que hacía que
     la forma no fuese la misma de una pantalla a otra.
     Ahora es el 138 % de la escena con tope de 860 px. Los dos números
     están medidos, no elegidos: con el 152 % que se probó primero, a
     1040 px de ventana —el ancho donde el monitor está MÁS escorado a la
     derecha, justo al entrar en dos columnas— lo que se salía era el
     15,9 % del óvalo, o sea pegado al borde de la zona transparente de la
     máscara. Con el 138 % el peor caso baja al 12,3 % y queda holgura.
     De paso, el 138 % fijo hace que la mesa mida siempre lo mismo EN
     PROPORCIÓN AL MONITOR, que es la otra mitad de «que se vea igual en
     cualquier pantalla».
     El tope sube de 860 a 1100 px al hacerse fluido el monitor: con 860,
     en una pantalla de 1920 la mesa se quedaba en el 101 % del ancho del
     panel y dejaba de leerse como superficie. Con 1100, y medido en los
     anchos críticos, lo que se sale del canto de la ventana nunca pasa
     del 12 % del óvalo — por debajo del 16 % donde la máscara horizontal
     ya está a cero. */
  width: min(138%, 1100px);
  /* Achatamiento del óvalo. Coherente con el del disco de la peana
     (cos 72° ≈ 0,31): las dos elipses las ve la MISMA cámara, así que
     tienen que tener la misma proporción o una de las dos miente. */
  aspect-ratio: 1 / 0.32;
  transform: translate(-50%, -50%) translateZ(calc(var(--panel-depth) * -1.7));
  border-radius: 50%;
  pointer-events: none;
  /* CAÍDA DE LUZ, de delante hacia atrás. Sin esto el óvalo se ve entero
     y por igual, y un anillo cerrado y uniforme no se lee como mesa: se
     lee como portal iluminado o como foco de teatro. En una escena real
     la luz sale de la pantalla y cae HACIA DELANTE, así que el canto
     trasero se pierde en la oscuridad y solo el delantero y los costados
     devuelven algo.
     El desvanecido del extremo inferior hace además un segundo trabajo:
     el `overflow: hidden` de `.hero` corta el óvalo unos 17 px por abajo,
     y si el filo siguiera encendido ahí ese corte se vería.

     Y AHORA TAMBIÉN DE LADO A LADO, que es la otra mitad del arreglo del
     corte. Estrechar el óvalo solo no bastaba: dónde cae el canto de la
     ventana depende del ancho de pantalla, así que cualquier medida fija
     acierta en un tamaño y falla en el siguiente. Apagando los extremos
     izquierdo y derecho, el óvalo VISIBLE deja de depender del recorte:
     es siempre el mismo trozo central, simétrico respecto del monitor, y
     por eso la forma ya no cambia al pasar de una pantalla a otra.
     Además es lo correcto físicamente: la luz sale de la pantalla y cae
     hacia delante, así que los costados de una mesa oscura se pierden en
     la penumbra — no terminan en punta iluminada.

     Las dos máscaras se MULTIPLICAN (`intersect` estándar,
     `source-in` en WebKit). Es la forma soportada de cruzar dos
     desvanecidos; encadenarlos en un solo degradado no se puede porque
     van en ejes distintos.

     La zona ya transparente del todo sube del 16 % al 20 % de cada
     extremo (2026-09-22, sexta pasada). Al hacerse fluido el ancho del
     monitor, el peor caso medido pasó a ser una tableta de 768 px, donde
     lo que se sale por la derecha llega al 13,2 % — demasiado cerca del
     antiguo margen. Con el 20 %, ese peor caso cae en alfa 0,03 y sobra
     holgura en todos los demás anchos. */
  -webkit-mask-image:
    linear-gradient(to bottom, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.48) 26%, #000 52%, rgba(0,0,0,0.88) 72%, rgba(0,0,0,0.4) 92%, rgba(0,0,0,0.16) 100%),
    linear-gradient(to right, transparent 0%, rgba(0,0,0,0.05) 20%, rgba(0,0,0,0.3) 30%, rgba(0,0,0,0.72) 40%, #000 50%, rgba(0,0,0,0.72) 60%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0.05) 80%, transparent 100%);
  mask-image:
    linear-gradient(to bottom, rgba(0,0,0,0.2) 0%, rgba(0,0,0,0.48) 26%, #000 52%, rgba(0,0,0,0.88) 72%, rgba(0,0,0,0.4) 92%, rgba(0,0,0,0.16) 100%),
    linear-gradient(to right, transparent 0%, rgba(0,0,0,0.05) 20%, rgba(0,0,0,0.3) 30%, rgba(0,0,0,0.72) 40%, #000 50%, rgba(0,0,0,0.72) 60%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0.05) 80%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  background:
    /* EL FILO. El canto pulido de un cristal devuelve luz, y es lo que
       hace que se lea la FORMA de la mesa en vez de una mancha. Va a
       ~93 % de los semiejes, o sea siguiendo la misma elipse que el
       `border-radius`, y bajísimo de opacidad: tiene que insinuar el
       contorno, no dibujarlo. */
    radial-gradient(ellipse 50% 50% at 50% 50%,
      transparent 82%,
      rgba(182, 200, 240, 0.036) 93%,
      rgba(150, 170, 214, 0.014) 97.5%,
      transparent 100%),
    /* EL VELO. Más denso en el centro —donde está el monitor y donde cae
       su luz— y disolviéndose hacia el canto. Muere en el 92 % de los
       semiejes, justo por dentro del filo, para que entre los dos quede
       un tramo de cristal limpio: es ese hueco el que hace que el filo
       se lea como canto y no como halo. */
    radial-gradient(ellipse 50% 50% at 50% 50%,
      rgba(154, 174, 218, 0.092) 0%,
      rgba(140, 158, 202, 0.058) 28%,
      rgba(116, 128, 176, 0.029) 54%,
      rgba(94, 102, 148, 0.011) 76%,
      transparent 92%);
}
/* EL REFLEJO de la pantalla sobre el cristal. Estirado hacia el
   espectador porque un reflejo en un plano casi rasante se alarga, y
   desenfocado porque el cristal no es un espejo. Los colores son los del
   propio informe —el azul del panel— y los del resplandor de la página.
   Arranca en el 56,6 %, que es donde está el labio delantero del disco.
   Y el número no depende del tamaño de la mesa, que es lo que lo hace
   fiable al cambiar de pantalla: el labio cae 19,8 px por debajo del
   centro del óvalo, el óvalo mide 0,32 de su ancho de alto, y las dos
   cosas escalan juntas → 19,8 / (860 · 0,32) = 6,6 puntos por debajo del
   50 %. En móvil, con la peana al 0,78 y la mesa también, sale el mismo
   6,6. Por eso ya no hay que reajustarlo por breakpoint.
   Un reflejo tiene que NACER PEGADO al objeto que lo produce; separarlo
   un par de píxeles es exactamente lo que vuelve a hacer que levite. */
.rig-table::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 56.6%;
  width: 40%;
  height: 26%;
  transform: translateX(-50%);
  background: linear-gradient(
    to bottom,
    rgba(152, 206, 242, 0.20) 0%,
    rgba(126, 168, 228, 0.115) 28%,
    rgba(146, 128, 246, 0.055) 54%,
    rgba(139, 92, 246, 0.02) 76%,
    transparent 94%
  );
  filter: blur(11px);
}
/* LA LUZ DE CONTACTO bajo el labio de la peana.
   CAMBIADA el 2026-09-22 (cuarta pasada). Hasta ahora esto era el
   «reflejo de la peana» y estaba pintado con negros —rgba(20,26,39,0.5)
   sobre un fondo casi negro— o sea que en pantalla no se leía como un
   reflejo: se leía como una MANCHA OSCURA debajo de la base. Y una
   mancha oscura debajo de un objeto es una sombra, diga lo que diga el
   nombre de la clase. Sobre cristal eso es justamente lo que delata el
   montaje: la luz atraviesa el vidrio, no se queda en un charco.
   Lo que sí devuelve un cristal pulido en una habitación oscura es LUZ:
   una línea corta y clara donde el canto iluminado del objeto toca la
   superficie. Eso es lo que ancla ahora — y sin oscurecer nada.
   Empieza en el 56,3 %, tres décimas por encima del labio (56,6), para
   que nazca PEGADA a él y no separada. */
.rig-table::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 56.3%;
  width: 17%;
  height: 4.6%;
  transform: translateX(-50%);
  border-radius: 50% / 45%;
  background: linear-gradient(
    to bottom,
    rgba(186, 206, 244, 0.17) 0%,
    rgba(150, 172, 220, 0.085) 34%,
    rgba(128, 140, 196, 0.03) 66%,
    transparent 92%
  );
  filter: blur(4px);
}

/* ---------------------------------------------------------
   ENTRADA
   El monitor llega girado de más y se asienta.
--------------------------------------------------------- */
.hero-rig {
  opacity: 0;
  transition: opacity 0.9s ease;
}
.hero-rig.is-in { opacity: 1; }
/* La entrada conserva su DIFERENCIA de 10°, no su valor absoluto: lo que
   se percibe al asentarse es cuánto gira, no desde dónde. Con el reposo
   en −16, el arranque va a −26. */
.hero-rig:not(.is-in) .rig-scene {
  --rig-yaw: -26deg;
  --rig-lift: 28px;
}
.hero-rig.is-in .rig-scene {
  transition: --rig-yaw 1.15s var(--ease-out-expo), --rig-pitch 1.15s var(--ease-out-expo);
}

/* ---------------------------------------------------------
   DISOLUCIÓN AL BAJAR
   Al salir la portada por arriba, el monitor no se va: se deshace en un
   degradado que sube desde la peana. La máscara SOLO existe mientras se
   baja (`.is-fading`, que pone nsa-hero.js en el primer píxel de
   scroll); en reposo el monitor no lleva ninguna, y el vídeo se compone
   directo y a resolución nativa.

   LA CURVA DEL DESVANECIDO (2026-09-22, quinta pasada). Antes eran dos
   paradas: opaco hasta `--rig-fade` y transparente 24 puntos después. Un
   tramo recto entre dos paradas es una rampa LINEAL de opacidad, y una
   rampa lineal no se ve como algo que se deshace: se ve como una banda
   con un canto arriba y otro abajo barriendo la imagen — sobre todo sobre
   el marco de aluminio, que es una superficie de tono plano.
   Ahora son cinco paradas con la caída concentrada al principio (0,72 a
   los 8 puntos, 0,30 a los 18, 0,08 a los 27) y una cola larga hasta los
   36. Es la misma forma que una `ease-out`: mucho al principio, casi nada
   al final, que es como se apaga cualquier cosa de verdad.
   Va en una variable porque la declaración es la misma dos veces y
   mantenerla a mano en las dos es pedir que se desincronicen. */
.hero-rig.is-fading {
  --rig-fade-mask: linear-gradient(to bottom,
    #000 0%,
    #000 var(--rig-fade),
    rgba(0, 0, 0, 0.72) calc(var(--rig-fade) + 8%),
    rgba(0, 0, 0, 0.3) calc(var(--rig-fade) + 18%),
    rgba(0, 0, 0, 0.08) calc(var(--rig-fade) + 27%),
    transparent calc(var(--rig-fade) + 36%));
  -webkit-mask-image: var(--rig-fade-mask);
  mask-image: var(--rig-fade-mask);
}

/* ---------------------------------------------------------
   COSTURA HÉROE → SERVICIOS: el embudo
   ---------------------------------------------------------
   El corte seco entre la portada y la primera sección tenía una causa
   concreta: `.hero-bg` pinta unos resplandores que llegan hasta el
   borde inferior del héroe, y `.hero` recorta lo que se sale. El
   degradado moría de golpe contra una línea horizontal perfecta.

   Se arregla en dos pasos:
   1. Se apaga `.hero-bg` ANTES de llegar a su propio canto, con una
      máscara. Sin eso, cualquier cosa que se ponga encima sigue
      dejando ver la raya por debajo.
   2. Se cruza la costura con un embudo: ancho bajo el monitor y
      estrechándose al bajar, como si la luz de la pantalla cayera
      hacia la sección siguiente. No tapa el corte: lo sustituye por
      una dirección de lectura.
--------------------------------------------------------- */
.hero .hero-bg {
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 52%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 52%, transparent 100%);
}

/* Caja de alto CERO justo en la junta entre las dos secciones: así sus
   hijos, en posición absoluta, se reparten a un lado y a otro sin que
   ninguna de las dos los recorte (las dos llevan `overflow: hidden`) y
   sin empujar ni un píxel de maquetación. */
.scroll-funnel {
  position: relative;
  z-index: 1; /* por debajo del monitor (2) y del texto del héroe (3) */
  height: 0;
  pointer-events: none;
}
.scroll-funnel > span {
  position: absolute;
  left: 50%;
  display: block;
  pointer-events: none;
}
/* El haz. El recorte lo estrecha hacia abajo —de ahí el embudo— y el
   desenfoque posterior le quita los cantos rectos del recorte, que son
   lo que delataría la figura. */
/* El haz va en DOS capas, y el motivo es de orden de operaciones: CSS
   aplica `filter` ANTES que `clip-path`, así que poniendo los dos en el
   mismo elemento el recorte vuelve a dejar cantos rectos sobre lo ya
   desenfocado — el embudo se leía como un foco de teatro recortado en
   cartulina. Con el recorte en el pseudoelemento y el desenfoque en el
   padre, el orden se invierte: primero la figura, después la luz. */
.sf-beam {
  top: -280px;
  width: min(1020px, 86vw);
  height: 430px;
  transform: translateX(-50%);
  filter: blur(54px);
}
.sf-beam::before {
  content: "";
  position: absolute;
  inset: 0;
  /* Arranca TRANSPARENTE. Con opacidad plena en el 0 % el haz empezaba
     con una raya horizontal propia — se cambiaba un corte por otro. */
  background: linear-gradient(
    to bottom,
    transparent 0%,
    rgba(167, 139, 250, 0.15) 28%,
    rgba(139, 92, 246, 0.09) 56%,
    transparent 100%
  );
  clip-path: polygon(0% 0%, 100% 0%, 67% 100%, 33% 100%);
}
/* Neblina ancha que amortigua el propio embudo contra el fondo, para
   que el haz no aparezca recortado sobre un cielo limpio. */
.sf-haze {
  top: -170px;
  width: min(1560px, 100vw);
  height: 340px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse 58% 100% at 50% 0%, rgba(139, 92, 246, 0.095), transparent 74%);
  filter: blur(40px);
}
@media (max-width: 720px) {
  .sf-beam { top: -220px; height: 360px; }
  .sf-haze { top: -120px; height: 240px; }
}

/* ---------------------------------------------------------
   INVITACIÓN A SEGUIR BAJANDO
   La página es un scroll continuo; conviene decirlo en el primer pliegue.
--------------------------------------------------------- */
.hero-scroll {
  display: inline-flex;
  align-items: center;
  /* En una columna flex un hijo se estira a todo el ancho; esto lo deja
     del tamaño de su contenido y pegado al raíl izquierdo. */
  align-self: flex-start;
  flex: none;
  gap: 10px;
  margin-top: 32px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-dimmer);
  transition: color 0.25s ease;
}
.hero-scroll:hover { color: var(--text-dim); }
.hero-scroll .hs-rail {
  position: relative;
  width: 20px;
  height: 32px;
  border: 1.5px solid rgba(167, 139, 250, 0.4);
  border-radius: 999px;
  flex: none;
}
.hero-scroll .hs-rail::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 6px;
  width: 3px;
  height: 6px;
  margin-left: -1.5px;
  border-radius: 2px;
  background: var(--lavender);
  animation: heroScrollHint 1.9s var(--ease-out-expo) infinite;
}
@keyframes heroScrollHint {
  0%, 12%   { transform: translateY(0); opacity: 0; }
  30%       { opacity: 1; }
  70%, 100% { transform: translateY(12px); opacity: 0; }
}

/* ---------------------------------------------------------
   VENTANA DE DEMOSTRACIÓN A PANTALLA COMPLETA
   Dentro del monitor el informe se ve, pero no se LEE: son cifras de
   ocho dígitos en 600 px. `<dialog>` nativo — trae por defecto el foco
   atrapado, el cierre con Esc y el fondo inerte, que es justo lo que
   habría que reimplementar a mano y mal.
--------------------------------------------------------- */
.demo-modal {
  width: min(1180px, 94vw);
  max-width: none;
  padding: 0;
  border: 1px solid rgba(167, 139, 250, 0.28);
  border-radius: 18px;
  background: #080B12;
  color: var(--text);
  overflow: hidden;
  box-shadow: 0 60px 140px -40px rgba(0, 0, 0, 0.95);
}
.demo-modal::backdrop {
  background: rgba(4, 6, 11, 0.82);
  backdrop-filter: blur(6px);
}
.demo-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--line);
}
.demo-modal-head h3 { font-size: 15px; font-weight: 700; margin: 0; }
.demo-modal-head p { font-size: 12.5px; color: var(--text-dimmer); margin: 4px 0 0; }
.demo-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: none;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: none;
  color: var(--text-dim);
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}
.demo-close:hover { color: var(--text); border-color: var(--violet); background: rgba(139, 92, 246, 0.12); }
.demo-modal video {
  display: block;
  width: 100%;
  height: auto;
  background: #0A1927;
}

/* ---------------------------------------------------------
   ADAPTACIÓN
--------------------------------------------------------- */
/* Por debajo del punto en el que caben dos columnas, el orden natural de
   lectura manda: primero qué hacemos, después la demostración. */
@media (max-width: 1039px) {
  .hero { padding: 132px 0 72px; min-height: 0; }
  .hero-copy { max-width: 640px; }
  /* Mismo salto proporcional que en escritorio (×1,45): −8 → −12, y la
     cámara se corre un punto a la izquierda. Aquí el monitor va centrado
     bajo el texto y no puede irse tanto como arriba —el giro le come
     ancho a una pantalla que ya es más estrecha— pero el punto de vista
     tiene que ser el mismo de una pantalla a otra. */
  /* Aquí el monitor ya no comparte fila con el texto, así que puede usar
     casi todo el ancho — pero sigue teniendo tope, y fluido como arriba:
     de ~600 px en una tableta de 768 a 700 en el límite de 1040. Antes
     estaba congelado en 620 para todo el tramo, que es justo lo que hacía
     que una tableta grande y una pequeña enseñaran el mismo monitor. */
  .hero-rig { --rig-yaw: -12deg; --rig-w: clamp(300px, 88vw, 700px); }
  .rig-stage { perspective: 1700px; perspective-origin: 46% 44%; margin: 0 auto; }
  .hero-scroll { margin-top: 48px; }
}
@media (max-width: 720px) {
  .hero { padding: 116px 0 56px; }
  .hero-split { gap: 44px; }
  .hero-copy p.lead { font-size: 16px; }
  .hero .hero-stats { gap: 10px; }
  .hero .stat { padding: 13px 14px 14px; }
  .hero .stat .num { font-size: 13px; }
  .hero .stat .label { font-size: 11.5px; }
  .hero .hero-cta { gap: 10px; }
  .monitor-chin { height: 28px; }
  /* AQUÍ YA NO SE TOCA LA PEANA (2026-09-22, sexta pasada). Había ocho
     declaraciones escritas a mano —alto 78, cuello 56×62, disco 170×100,
     penumbra 81×59, centro de la mesa a 25— que eran el pie de escritorio
     multiplicado por 0,78. Ahora eso lo hace solo el `clamp` de `--foot`
     en `.rig-scene`: su suelo de 170 px ES este disco de 170, así que la
     fórmula reproduce estos mismos valores sin escribirlos.
     Se gana además quitar un salto real: con el bloque a mano, a 721 px
     de ventana el pie medía 218 y a 720 pasaba de golpe a 170. */
  .rig-caption { margin-top: 26px; font-size: 12px; }
  .hero-scroll { display: none; } /* en móvil el gesto de bajar no hay que explicarlo */
}
/* Por debajo de ~600 px los dos botones ya no caben en una línea (≈495 px
   de contenido) y `flex-wrap` los partía dejando el segundo a media
   anchura, colgando. Apilados y a todo el ancho se leen como dos
   opciones equivalentes, que es lo que son. */
@media (max-width: 600px) {
  .hero .hero-cta .btn { width: 100%; }
  /* Y el escorzo deja de compensar: la pantalla es ya pequeña y girarla
     se come justo los píxeles que el informe necesita para leerse. */
  .hero-rig { --rig-yaw: 0deg; }
  .rig-stage { perspective: none; }
  .hero-rig:not(.is-in) .rig-scene { --rig-yaw: 0deg; --rig-lift: 18px; }
}

@media (max-width: 420px) {
  /* Los cuatro pilares se quedan en DOS columnas y solo con el nombre.
     Con la descripción, cada tarjeta se parte en tres líneas y las
     cuatro suman casi 300 px que empujan los botones fuera del primer
     pliegue; en una sola columna, cuatro tarjetas de dos palabras se
     leen como una lista vacía. El texto íntegro sigue estando en la
     sección de Servicios, unos centímetros más abajo. */
  .hero .hero-stats { gap: 9px; }
  .hero .stat .label { display: none; }
  .hero .stat { padding: 12px 13px; }
  .hero .stat .num { margin-bottom: 0; font-size: 12.5px; }
}

/* ---------------------------------------------------------
   MOVIMIENTO REDUCIDO (WCAG 2.2 · 2.3.3)
   Quien lo pide no quiere que las cosas se muevan solas: ni giro, ni
   paralaje, ni vídeo en marcha. La demostración sigue estando — con su
   botón de reproducir, cuando la persona decida.
--------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .hero-rig {
    opacity: 1;
    --rig-yaw: 0deg;
  }
  .rig-stage { perspective: none; }
  .hero-rig:not(.is-in) .rig-scene {
    --rig-yaw: 0deg;
    --rig-lift: 0px;
  }
  .rig-scene, .hero-rig.is-in .rig-scene { transition: none; }
  .hero-scroll .hs-rail::after { animation: none; opacity: 1; }
}
