/* =========================================================================
   IAbyLio, home
   Taller oscuro con aire editorial. Un solo tema (dark), un solo acento.

   Tipografia
     display  Bricolage Grotesque (variable 400..800)
     texto    Instrument Sans (variable 400..600)
     mono     IBM Plex Mono (400 / 500), solo donde hay trabajo real que ver

   Radios (bloqueado, no mezclar fuera de esta escala)
     --r-sm  6px   botones, inputs, chips
     --r-md  12px  planos de la escena, celdas chicas
     --r-lg  18px  paneles grandes
   ========================================================================= */

/* ------------------------------------------------------------- tipografia */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../assets/fonts/bricolage-grotesque-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('../assets/fonts/bricolage-grotesque-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('../assets/fonts/instrument-sans-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
}

/* ----------------------------------------------------------------- tokens */
:root {
  --base: #0b0f1e;
  --base-hondo: #080b17;
  --superficie: #131829;
  --superficie-alta: #171d31;
  --azul: #0a8fd0;
  --azul-claro: #4fb4e8;
  --texto: #e6e6e1;
  --apagado: #6e93a8;
  --ambar: #e8a15c;

  --linea: rgba(110, 147, 168, 0.2);
  --linea-fuerte: rgba(110, 147, 168, 0.34);

  --r-sm: 6px;
  --r-md: 12px;
  --r-lg: 18px;

  --ancho: 1240px;
  --margen: clamp(1.25rem, 5vw, 4rem);

  /* Personalidad de movimiento: Corporate con duraciones premium.
     Una sola curva firma para el 80% de la pagina. */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --rapido: 170ms;
  --medio: 320ms;
  --lento: 780ms;

  --f-display: 'Bricolage Grotesque', 'Trebuchet MS', sans-serif;
  --f-texto: 'Instrument Sans', 'Helvetica Neue', sans-serif;
  --f-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', monospace;
}

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

html {
  -webkit-text-size-adjust: 100%;
  /* La escena 3D asoma fuera de su caja. Sin esto el documento se ensancha y
     mobile queda con una banda vacia a la derecha. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--base);
  color: var(--texto);
  font-family: var(--f-texto);
  font-size: clamp(1.0625rem, 0.4vw + 0.97rem, 1.1875rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* Atmosfera: una sola fuente de luz azul arriba a la derecha, del lado en el
   que vive la escena. No es un gradiente decorativo, orienta la lectura. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(58rem 40rem at 78% -8%, rgba(10, 143, 208, 0.16), transparent 62%),
    radial-gradient(42rem 34rem at 4% 22%, rgba(10, 143, 208, 0.07), transparent 60%);
}

body > * { position: relative; z-index: 1; }

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3 {
  font-family: var(--f-display);
  font-weight: 600;
  letter-spacing: -0.028em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0; text-wrap: pretty; }
ul { margin: 0; padding: 0; list-style: none; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--azul-claro);
  outline-offset: 3px;
  border-radius: 3px;
}

/* Los anclas del nav no tienen que pegar el titulo contra el borde. */
#contenido,
#instrumental,
#seguir { scroll-margin-top: 2.5rem; }

.saltar {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--azul);
  color: var(--base);
  padding: 0.7rem 1.1rem;
  border-radius: var(--r-sm);
  font-weight: 600;
  z-index: 50;
}
.saltar:focus { left: 1rem; top: 1rem; }

/* --------------------------------------------------------------- utilidad */
.titulo-seccion {
  font-size: clamp(1.85rem, 3vw, 2.75rem);
  line-height: 1.08;
  max-width: 20ch;
}

.codigo {
  font-family: var(--f-mono);
  font-size: 0.8125rem;
  line-height: 1.85;
  color: var(--apagado);
  margin: 0;
  white-space: pre;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.codigo code { font: inherit; color: inherit; }

/* ------------------------------------------------------------------ barra */
.barra {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  height: 72px;
  padding: 0 var(--margen);
  max-width: var(--ancho);
  margin: 0 auto;
}

.marca {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  white-space: nowrap;
}
.marca__mark { width: 30px; height: 30px; }
.marca__nombre {
  font-family: var(--f-display);
  font-weight: 600;
  font-size: 1.0625rem;
  letter-spacing: -0.02em;
}

.barra__nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.4vw, 2rem);
  white-space: nowrap;
}
.barra__nav a {
  text-decoration: none;
  font-size: 0.9375rem;
  color: var(--apagado);
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: color var(--rapido) var(--ease), border-color var(--rapido) var(--ease);
}
.barra__nav a:hover { color: var(--texto); border-bottom-color: var(--azul); }

/* ----------------------------------------------------------------- botones */
.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  font-family: var(--f-texto);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1;
  padding: 0.95rem 1.5rem;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--rapido) var(--ease),
    background-color var(--rapido) var(--ease),
    border-color var(--rapido) var(--ease),
    color var(--rapido) var(--ease);
}
.boton--primario {
  background: var(--azul);
  /* Tinta oscura sobre el azul: 5.3:1. El blanco sobre este azul no llega a AA. */
  color: var(--base);
}
.boton--primario:hover { background: var(--azul-claro); }
.boton--fantasma {
  background: transparent;
  color: var(--texto);
  border-color: var(--linea-fuerte);
}
.boton--fantasma:hover { border-color: var(--azul); color: var(--azul-claro); }
@media (hover: hover) {
  .boton:hover { transform: translateY(-1px); }
}
.boton:active { transform: translateY(1px); }
.boton[disabled] { opacity: 0.78; cursor: progress; }

/* ------------------------------------------------------------------- hero */
.hero {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: clamp(1.5rem, 3vw, 2.5rem) var(--margen) clamp(2.25rem, 3.5vw, 3rem);
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  align-items: center;
  align-content: center;
  gap: clamp(2rem, 4vw, 3.5rem);
  /* El hero ocupa el resto de la ventana MENOS una banda: esa banda es la que
     deja asomar el arranque de "Soy Lio." dentro del primer pantallazo. Sin
     ella el 1440x900 termina en el CTA y la mitad de abajo queda muerta. */
  min-height: calc(100svh - 72px - 15.5rem);
}

.hero__titulo {
  font-size: clamp(2.2rem, 4.2vw, 3.5rem);
  line-height: 1.04;
  font-weight: 600;
  max-width: 20ch;
}

.hero__bajada {
  margin-top: 1.4rem;
  max-width: 40ch;
  color: var(--apagado);
  font-size: clamp(1.0625rem, 0.5vw + 0.95rem, 1.25rem);
  line-height: 1.6;
}

.hero__acciones {
  margin-top: 2.2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* --------------------------------------------------- escena (CSS 3D real) */
.escena {
  position: relative;
  aspect-ratio: 9 / 8;
  min-height: 400px;
  perspective: 1150px;
  perspective-origin: 50% 46%;
}

/* --tx / --ty son el tilt que sigue al cursor (los escribe app.js con lerp).
   Van adentro del calc para que la MISMA formula sirva quieta, con mouse, y
   durante la animacion de scroll: los tres estados componen, no se pisan. */
.escena__mundo {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: translateX(-4%) rotateX(calc(13deg + var(--tx, 0deg)))
    rotateY(calc(-25deg + var(--ty, 0deg))) rotateZ(1deg) scale(1.2);
}

.plano {
  position: absolute;
  left: 50%;
  top: 50%;
  width: min(16.5rem, 55%);
  aspect-ratio: 8 / 5;
  margin: 0;
  transform-style: preserve-3d;
  transform: translate3d(calc(-50% + var(--x)), calc(-50% + var(--y)), var(--z));
}

/* El cuerpo del plano va en ::before, NO en ::after: un ::after se genera como
   ultimo hijo y pintaria su fondo semitransparente ENCIMA de la etiqueta,
   que es justo lo que hacia que las rutas se leyeran como fantasmas. */
.plano::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 1px solid rgba(110, 147, 168, 0.3);
  border-radius: var(--r-md);
  background: linear-gradient(155deg, rgba(23, 29, 49, 0.96), rgba(11, 15, 30, 0.8));
  box-shadow: 0 22px 50px -26px rgba(0, 0, 0, 0.95);
  animation: encastrar var(--lento) var(--ease) var(--d) backwards;
}

.plano--frente::before {
  border-color: rgba(10, 143, 208, 0.42);
  background: linear-gradient(155deg, rgba(23, 29, 49, 0.97), rgba(11, 15, 30, 0.82));
}

/* La etiqueta va en la franja de arriba a la derecha: es la unica parte de
   cada plano que no tapa ni el plano de adelante ni el logo.
   El translateZ la despega 2px del cuerpo: dentro de un contexto 3D el orden
   lo decide la profundidad, no el z-index, asi que nunca queda por detras. */
.plano__et {
  position: absolute;
  top: 0.85rem;
  right: 1.15rem;
  display: inline-flex;
  align-items: baseline;
  gap: 0.85rem;
  font-family: var(--f-mono);
  font-size: 0.875rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
  transform: translateZ(2px);
  animation: encastrar-et var(--lento) var(--ease) var(--d) backwards;
}
/* Las rutas son el motivo de que la escena exista: si no se leen, esto pasa a
   ser decoracion. Van casi al blanco, con sombra para despegarlas del plano. */
.plano__ruta {
  font-weight: 500;
  color: #dbe6ec;
  text-shadow: 0 1px 8px rgba(4, 7, 16, 0.85);
}
.plano__dato {
  font-weight: 500;
  color: #7cc8f2;
  text-shadow: 0 1px 8px rgba(4, 7, 16, 0.85);
}
.plano--frente .plano__ruta { color: #f4f7f9; }

/* Las piezas llegan de posiciones sueltas y encastran en el stack. */
@keyframes encastrar {
  from {
    opacity: 0;
    transform: translate3d(var(--dx), -34px, 190px) rotateZ(-5deg);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Igual que encastrar, pero aterriza en el plano +2px de la etiqueta. */
@keyframes encastrar-et {
  from {
    opacity: 0;
    transform: translate3d(var(--dx), -34px, 192px) rotateZ(-5deg);
  }
  to {
    opacity: 1;
    transform: translateZ(2px);
  }
}

/* Vida en reposo: cada plano flota apenas, con un periodo distinto derivado de
   su propio delay de entrada (--d), asi nunca respiran en fase. Anima la
   propiedad `translate`, que COMPONE con el transform de posicionamiento: no
   hay que repetir la formula del stack. Tambien en movil (pedido de Lio: la
   escena no responde al dedo, pero tiene que respirar); el costo es minimo
   porque translate anima en el compositor. Solo el tilt queda de puntero. */
@media (prefers-reduced-motion: no-preference) {
  .plano {
    animation: flotar calc(5.4s + var(--d) * 8) ease-in-out calc(var(--d) + 1s)
      infinite alternate;
  }
  @keyframes flotar {
    from { translate: 0 0 0; }
    to { translate: 0 -7px 12px; }
  }
  /* Doble clase: esta regla vive antes que la base de .escena__logo en el
     archivo y sin esto perderia por orden de aparicion. */
  .escena .escena__logo {
    animation: aterrizar 700ms var(--ease) 60ms backwards,
      flotar-logo 6.5s ease-in-out 1.4s infinite alternate;
  }
  @keyframes flotar-logo {
    from { transform: translateY(0); }
    to { transform: translateY(-6px); }
  }
}

.escena__foco {
  position: absolute;
  left: 26%;
  top: 64%;
  width: 34rem;
  height: 34rem;
  translate: -50% -50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(10, 143, 208, 0.21), transparent 64%);
  animation: respirar 9s ease-in-out infinite;
}

@keyframes respirar {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 0.9; }
}

/* El logo va plano y entero delante de la escena: no se rota ni se deforma. */
.escena__logo {
  position: absolute;
  left: 26%;
  top: 64%;
  translate: -50% -50%;
  width: clamp(8.5rem, 16vw, 15rem);
  height: auto;
  filter: drop-shadow(0 16px 40px rgba(10, 143, 208, 0.24));
  animation: aterrizar 700ms var(--ease) 60ms backwards;
}

@keyframes aterrizar {
  from { opacity: 0; scale: 0.9; }
  to { opacity: 1; scale: 1; }
}

/* Al salir del hero la escena rota un poco mas: confirma que hay profundidad
   de verdad y no una imagen. Sin listeners de scroll, timeline nativa. */
@supports (animation-timeline: view()) {
  /* Solo en escritorio: en movil la escena se queda quieta despues de armarse
     (no hay motivo para gastar frames ahi). */
  @media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
    .escena__mundo {
      animation: alejarse linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 100%;
    }
    /* Los keyframes repiten las vars del tilt: mientras la escena sale, el
       cursor sigue teniendo voz. */
    @keyframes alejarse {
      from {
        transform: translateX(-4%) rotateX(calc(13deg + var(--tx, 0deg)))
          rotateY(calc(-25deg + var(--ty, 0deg))) rotateZ(1deg) scale(1.2);
      }
      to {
        transform: translateX(-4%) rotateX(calc(20deg + var(--tx, 0deg)))
          rotateY(calc(-9deg + var(--ty, 0deg))) rotateZ(-2deg) translateZ(-70px)
          scale(1.2);
      }
    }
  }
}

/* ------------------------------------------------------------------ quien */
.quien {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: clamp(2.5rem, 4vw, 3.5rem) var(--margen) clamp(3.5rem, 7vw, 6rem);
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  gap: 0 clamp(1.5rem, 4vw, 4rem);
  align-items: start;
}

.quien__titulo {
  grid-column: 1;
  grid-row: 1;
  font-size: clamp(1.85rem, 3vw, 2.75rem);
  line-height: 1.05;
}

.quien__prosa {
  grid-column: 2;
  grid-row: 1 / span 2;
  display: grid;
  gap: 1.15rem;
  max-width: 58ch;
  border-left: 1px solid var(--linea);
  padding-left: clamp(1.25rem, 2.5vw, 2.25rem);
}
.quien__prosa p { color: #c9d3da; }

/* La acotacion ocupa el margen izquierdo, debajo del titulo. */
.quien__nota {
  grid-column: 1;
  grid-row: 2;
  margin-top: 1.75rem;
  max-width: 34ch;
  color: var(--apagado);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* ------------------------------------------------------------ tres piezas */
.piezas {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: clamp(2rem, 5vw, 3.5rem) var(--margen) clamp(3.5rem, 7vw, 6rem);
}

.piezas__lista {
  margin-top: clamp(1.75rem, 4vw, 3rem);
  border-top: 1px solid var(--linea);
}

.pieza {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 5.5fr) minmax(0, 2.5fr);
  gap: clamp(1rem, 3vw, 2.5rem);
  align-items: baseline;
  padding: clamp(1.6rem, 3vw, 2.3rem) 0;
  border-bottom: 1px solid var(--linea);
  transition: border-color var(--medio) var(--ease);
}
.pieza:hover { border-bottom-color: var(--linea-fuerte); }

.pieza__nombre {
  font-size: clamp(1.5rem, 2.2vw, 2rem);
  line-height: 1.1;
}
.pieza__nombre a {
  text-decoration: none;
  background-image: linear-gradient(var(--azul), var(--azul));
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--medio) var(--ease), color var(--rapido) var(--ease);
}
/* Toda la fila lleva al mismo sitio, pero el link real es el titulo. */
.pieza__nombre a::after {
  content: '';
  position: absolute;
  inset: 0;
}
.pieza:hover .pieza__nombre a { background-size: 100% 1px; color: var(--azul-claro); }

/* La flecha aparece porque toda la fila es un link: confirma el destino. */
@media (hover: hover) {
  .pieza::after {
    content: '→';
    position: absolute;
    right: 0.25rem;
    top: 50%;
    translate: -12px -50%;
    opacity: 0;
    color: var(--azul-claro);
    font-family: var(--f-display);
    font-size: 1.4rem;
    pointer-events: none;
    transition: opacity var(--medio) var(--ease), translate var(--medio) var(--ease);
  }
  .pieza:hover::after { opacity: 1; translate: 0 -50%; }
}

.pieza__para {
  margin-top: 0.45rem;
  font-family: var(--f-mono);
  font-size: 0.75rem;
  color: var(--apagado);
}

.pieza__desc { color: #c9d3da; font-size: 1.0625rem; }

.pieza__estado {
  font-family: var(--f-mono);
  font-size: 0.75rem;
  color: var(--apagado);
  border: 1px solid var(--linea);
  border-radius: var(--r-sm);
  padding: 0.4rem 0.7rem;
  justify-self: start;
}

/* ------------------------------------------------------------------ tunel */
/* Solo existe con JS y sin reduced motion: es una transicion, no contenido.
   El alto (300svh) es el recorrido de scroll que scrubbea la camara. */
.tunel { display: none; }
.js .tunel {
  display: block;
  position: relative;
  height: 300svh;
  background: var(--base);
}
.js .tunel--off { display: none; }
.tunel__pegado {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}
.tunel__lienzo {
  display: block;
  width: 100%;
  height: 100%;
}
.tunel__linea {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--f-display);
  font-weight: 600;
  letter-spacing: -0.025em;
  font-size: clamp(1.9rem, 3.6vw, 3.1rem);
  color: var(--texto);
  text-shadow: 0 2px 34px rgba(8, 11, 23, 0.85);
  white-space: nowrap;
  pointer-events: none;
}

/* ----------------------------------------------------------- instrumental */
.instrumental {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: clamp(3.5rem, 7vw, 6rem) var(--margen);
}

.instrumental__intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  max-width: 62ch;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
.instrumental__bajada { color: var(--apagado); max-width: 54ch; }

/* Dos filas con ancho alternado (7|5 y despues 5|7). Cuatro celdas para
   cuatro cosas: ninguna casilla vacia, ningun relleno. */
.bento {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(0.9rem, 1.6vw, 1.25rem);
  align-items: stretch;
}
.celda--repo { grid-column: span 7; }
.celda--agentes { grid-column: span 5; }
.celda--verif { grid-column: span 5; }
.celda--log { grid-column: span 7; }

.celda {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  background: var(--superficie);
  padding: clamp(1.4rem, 2.4vw, 2rem);
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
/* Lift al pasar: `translate` compone con el transform del reveal, asi que el
   hover funciona igual aunque la celda todavia este entrando. */
@media (hover: hover) {
  .celda {
    transition: translate var(--medio) var(--ease), border-color var(--medio) var(--ease),
      box-shadow var(--medio) var(--ease);
  }
  .celda:hover {
    translate: 0 -4px;
    border-color: var(--linea-fuerte);
    box-shadow: 0 20px 44px -26px rgba(0, 0, 0, 0.85);
  }
}

.celda__titulo {
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.015em;
}
.celda__texto { color: #c9d3da; font-size: 1rem; }
.celda__pie {
  color: var(--apagado);
  font-size: 0.9375rem;
  margin-top: auto;
}

/* Variacion real de fondo entre celdas: luz, trama y filo de acento. */
.celda--repo {
  background:
    radial-gradient(28rem 22rem at 88% 4%, rgba(10, 143, 208, 0.16), transparent 66%),
    var(--superficie-alta);
}
.celda--repo .codigo { font-size: 0.875rem; }

.celda--agentes { border-left: 2px solid var(--azul); }

.celda--verif::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.5;
  background-image: radial-gradient(rgba(110, 147, 168, 0.22) 1px, transparent 1px);
  background-size: 14px 14px;
  mask-image: linear-gradient(200deg, #000, transparent 62%);
}
.celda--verif > * { position: relative; }

.celda--log { background: var(--base-hondo); }

.lista-mono { display: grid; gap: 0.85rem; }
.lista-mono li {
  display: grid;
  gap: 0.15rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--linea);
}
.lista-mono li:last-child { border-bottom: 0; padding-bottom: 0; }
.lista-mono code {
  font-family: var(--f-mono);
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--texto);
}
.lista-mono span { color: var(--apagado); font-size: 0.9375rem; }

/* ----------------------------------------------------------------- seguir */
.seguir {
  border-top: 1px solid var(--linea);
  border-bottom: 1px solid var(--linea);
  background: linear-gradient(180deg, rgba(19, 24, 41, 0.75), rgba(11, 15, 30, 0));
}
/* Alineado al mismo margen que el resto de la pagina: la banda es full bleed,
   el contenido no se centra. */
.seguir__caja {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: clamp(3.5rem, 7vw, 6rem) var(--margen);
}
.seguir__titulo,
.seguir__bajada,
.form,
.form__ayuda,
.form__exito { max-width: 44rem; }
.seguir__titulo { font-size: clamp(1.85rem, 3vw, 2.6rem); line-height: 1.08; }
.seguir__bajada { margin-top: 0.9rem; color: var(--apagado); max-width: 44ch; }

/* El error vive en su propia fila para que el boton no baile cuando aparece. */
.form {
  margin-top: 2rem;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 0.75rem;
}
.form__campo { grid-column: 1; display: grid; gap: 0.5rem; }
.form__label {
  font-family: var(--f-mono);
  font-size: 0.75rem;
  color: var(--apagado);
}
.form__input {
  width: 100%;
  font-family: var(--f-texto);
  font-size: 1rem;
  color: var(--texto);
  background: var(--base-hondo);
  border: 1px solid var(--linea-fuerte);
  border-radius: var(--r-sm);
  padding: 0.9rem 1rem;
  transition: border-color var(--rapido) var(--ease), background-color var(--rapido) var(--ease);
}
/* #8FA6B4 sobre #080B17 da 6.3:1, muy por encima de AA. */
.form__input::placeholder { color: #8fa6b4; opacity: 1; }
.form__input:focus {
  outline: none;
  border-color: var(--azul);
  background: #0a0e1c;
  box-shadow: 0 0 0 3px rgba(10, 143, 208, 0.25);
}
.form__input[aria-invalid='true'] { border-color: var(--ambar); }
.form__submit {
  grid-column: 2;
  padding-block: 0.95rem;
  /* Ancho fijo: la etiqueta cambia a "Mandando..." y no tiene que saltar. */
  min-width: 11.75rem;
}

.form__error {
  grid-column: 1 / -1;
  color: var(--ambar);
  font-size: 0.9375rem;
  margin-top: -0.15rem;
}
.form__ayuda {
  margin-top: 1rem;
  color: var(--apagado);
  font-size: 0.9375rem;
}
.form__exito {
  margin-top: 1.5rem;
  padding: 1rem 1.15rem;
  border: 1px solid rgba(10, 143, 208, 0.45);
  border-radius: var(--r-md);
  background: rgba(10, 143, 208, 0.1);
  color: var(--texto);
}
[hidden] { display: none !important; }

/* ----------------------------------------------------------------- cierre */
.cierre {
  max-width: var(--ancho);
  margin: 0 auto;
  padding: clamp(3rem, 6vw, 5rem) var(--margen);
}
.cierre p {
  max-width: 58ch;
  color: var(--apagado);
  font-size: 1rem;
}
.cierre a {
  color: var(--azul-claro);
  text-decoration: none;
  border-bottom: 1px solid rgba(79, 180, 232, 0.4);
  transition: border-color var(--rapido) var(--ease);
}
.cierre a:hover { border-bottom-color: var(--azul-claro); }

/* -------------------------------------------------------------------- pie */
.pie {
  border-top: 1px solid var(--linea);
  max-width: var(--ancho);
  margin: 0 auto;
  padding: 2.25rem var(--margen) 3rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
}
.pie__marca {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-family: var(--f-display);
  font-weight: 600;
}
.pie__nav { display: flex; gap: 1.5rem; }
.pie__nav a {
  text-decoration: none;
  color: var(--apagado);
  font-size: 0.9375rem;
  transition: color var(--rapido) var(--ease);
}
.pie__nav a:hover { color: var(--texto); }
.pie__legal {
  font-family: var(--f-mono);
  font-size: 0.75rem;
  color: var(--apagado);
}

/* --------------------------------------------------------------- reveals */
.js .revelar {
  opacity: 0;
  transform: translateY(18px);
}
/* Variantes por direccion: las filas llegan del lado por el que se leen, la
   nota al margen llega del suyo, y las celdas del bento asientan con un pelo
   de escala. Mismo presupuesto de tiempo, solo cambia el origen. */
.js .revelar--izq { transform: translateX(-26px); }
.js .revelar--der { transform: translateX(26px); }
.js .revelar--zoom { transform: translateY(14px) scale(0.965); }
.js .revelar.visible {
  opacity: 1;
  transform: none;
  transition: opacity 700ms var(--ease), transform 700ms var(--ease);
  transition-delay: var(--retraso, 0ms);
}
/* Cuando GSAP toma el mando (entradas.js), el estado inicial pasa a inline
   styles y el sistema IO queda apagado: la clase deja todo visible para que
   ningun .revelar sin coreografia quede oculto para siempre. */
.gsap-activa .revelar {
  opacity: 1;
  transform: none;
  transition: none;
}

/* ---------------------------------------------- scroll-driven (nativo) */
/* Todo con timeline nativa: cero listeners de scroll. Solo escritorio y solo
   si el navegador lo trae; si no, la pagina queda exactamente como estaba. */
@supports (animation-timeline: view()) {
  @media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
    /* El hero se despide: al scrollear, el texto sube un poco mas rapido que
       la pagina y se apaga. Confirma que ya arranco otra cosa. */
    .hero__texto {
      animation: despedirse linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 90%;
    }
    @keyframes despedirse {
      from { opacity: 1; translate: 0 0; }
      to { opacity: 0.1; translate: 0 -30px; }
    }

    /* La regla de la lista se dibuja de izquierda a derecha al entrar. */
    .piezas__lista { border-top: 0; position: relative; }
    .piezas__lista::before {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 1px;
      background: var(--linea-fuerte);
      transform-origin: 0 50%;
      animation: dibujar-x linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 28%;
    }
    @keyframes dibujar-x {
      from { scale: 0 1; }
      to { scale: 1 1; }
    }

    /* Y la regla vertical de la prosa se dibuja de arriba a abajo. */
    .quien__prosa { border-left-color: transparent; position: relative; }
    .quien__prosa::before {
      content: '';
      position: absolute;
      top: 0;
      bottom: 0;
      left: -1px;
      width: 1px;
      background: var(--linea);
      transform-origin: 50% 0;
      animation: dibujar-y linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 45%;
    }
    @keyframes dibujar-y {
      from { scale: 1 0; }
      to { scale: 1 1; }
    }
  }
}

/* ---------------------------------------------------------------- mobile */
@media (max-width: 940px) {
  .hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    padding-top: 1.25rem;
    padding-bottom: clamp(2.5rem, 8vw, 4rem);
    /* En movil manda el apilado: los dos CTA por encima de la linea de
       flotacion. Nada de alturas minimas empujando desde abajo. */
    min-height: 0;
  }
  .hero__titulo { max-width: 18ch; }
  .hero__bajada { margin-top: 1.1rem; }
  .hero__acciones { margin-top: 1.6rem; }
  .escena {
    order: 2;
    aspect-ratio: 7 / 5;
    min-height: 260px;
    max-height: 340px;
    /* Aire suficiente para que los planos de atras no toquen los botones. */
    margin-top: 3.25rem;
    perspective-origin: 50% 48%;
  }
  .escena__mundo {
    transform: translateX(-4%) rotateX(11deg) rotateY(-20deg) scale(0.92);
  }
  .plano { width: min(13.5rem, 54%); }
  .escena__logo { left: 23%; top: 67%; width: 8.25rem; }
  .escena__foco { left: 23%; top: 67%; width: 20rem; height: 20rem; }

  .codigo { font-size: 0.75rem; line-height: 1.8; }
  .celda--repo .codigo { font-size: 0.75rem; }

  /* Una sola columna: la acotacion vuelve al flujo, detras de la prosa. */
  .quien { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
  .quien__titulo,
  .quien__prosa,
  .quien__nota { grid-column: auto; grid-row: auto; }
  .quien__nota { margin-top: 0; max-width: 46ch; }

  .pieza { grid-template-columns: minmax(0, 1fr); gap: 0.75rem; }
  .pieza__desc { max-width: 46ch; }

  .js .tunel { height: 240svh; }

  .bento { grid-template-columns: minmax(0, 1fr); }

  .form { grid-template-columns: minmax(0, 1fr); }
  .form__submit { grid-column: 1; width: 100%; }
}

@media (max-width: 520px) {
  .barra { height: 64px; }
  .barra__nav { gap: 0.9rem; }
  .barra__nav a { font-size: 0.875rem; }
  .marca__nombre { display: none; }
  /* Botones al ancho de su texto, no full bleed: esto publica, no vende. */
  .hero__acciones {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.65rem;
  }
  .pie { justify-content: flex-start; }
}

/* --------------------------------------------------------- reduced motion */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .js .revelar { opacity: 1; transform: none; }
  /* La escena queda armada y quieta: sigue siendo el mismo dibujo, sin viaje. */
  .escena__foco { opacity: 0.7; }
}
