/* landing.css — la hoja de la PORTADA, y solo de la portada. Uso: la carga `web/landing.html` después de
   `estilo.css`, y le pisa lo que haga falta con `body.landing`.
   Proceso: nommeros-web

   ═══ POR QUÉ ESTÁ REESCRITA DE CERO (18-ago-2026) ══════════════════════════════════════════════════

   Iñaki, literal: «súper fea», «súper bugueada y mal», «muy ochentera, muy fea, muy cutre todo». Y con el
   modelo que quiere puesto al lado (Memmaros, y Cerberus de referencia) el diagnóstico deja de ser una
   opinión. Miré las seis capturas y lo que separa una de otra es concreto:

     · FONDO. La vieja pintaba el canvas ambiental del JUEGO (`escenario-fondo.mjs`, contexto «arena»):
       verdes sucios y olas azul marino que cruzaban de una sección a otra. En una pantalla de juego eso
       ambienta; detrás de una columna de texto es ruido, y además cambia con la hora, así que la portada
       se veía distinta según cuándo entrases. Ahora: negro neutro y quieto. El color lo pone el producto.
     · TIPOGRAFÍA. `estilo.css` pone una CONDENSADA del sistema en todo el `body`, y una condensada en
       mayúsculas a 96 px es exactamente la firma «ochentera». Aquí manda una sans normal del sistema, en
       caja mixta, con el interletrado apretado. La Anton se queda para UNA cosa: el logotipo de la barra.
     · AMARILLO. Estaba en el titular entero. Un acento que ocupa un tercio de la pantalla deja de ser un
       acento. Ahora sale en cuatro sitios contados: el ojo de sección, UNA palabra por titular, el botón
       y el «sí» de la doctrina.
     · Y LA DIFERENCIA ESTRUCTURAL, que es la que más pesa: en Memmaros CADA sección enseña el producto
       renderizado. La vieja no enseñaba el juego en ninguna parte salvo el bicho del hero. Aquí toda
       sección lleva su pieza: el visor 3D, las dos fichas de modo, la tarjeta de nivel, los cuatro Nomms.

   ⚠️ NO HAY UNA SOLA ANIMACIÓN DE `steps()` EN ESTE FICHERO, y es a propósito. El hero era una tira de 24
   fotogramas animada con `steps(24, jump-none)`; Iñaki lo llamó «parpadeo» y «súper cutre» DESPUÉS de que
   se corrigiera la aritmética de `background-position`. Un mecanismo que hay que volver a defender es un
   mecanismo que sobra: el hero es ahora el motor 3D de verdad (ver `landing.mjs`), y el parpadeo no se
   arregla, desaparece porque ya no existe la pieza que parpadeaba.

   ✍️ Ni una raya larga en el texto que sale a pantalla (norma de la casa: es la firma de que lo escribió
   una IA). En estos comentarios sí, que no los lee nadie de fuera. */

body.landing {
  /* Paleta local. Hereda los tokens de marca de `estilo.css` y añade los grises de superficie que la
     portada necesita: la profundidad se hace ACLARANDO sobre el negro, nunca con sombras. */
  --fondo: #0a0a0b;
  --panel: #121214;
  --panel-alto: #17171a;
  --borde: #232327;
  --borde-vivo: #34343a;
  --texto: var(--hueso);
  --texto-2: #9a978e;
  --texto-3: #6f6d67;
  /* Los dos colores de la portada que no son ni el oro ni un gris, y cada uno significa UNA cosa.
     · VERDE: primero fue el dinero (Iñaki, 19-ago: «que se vea en verde, porque al final el verde es
       el del dinero»), y ese mismo día lo amplió al SÍ: «que el no se vea en rojo y el sí en verde,
       tiene mucho más sentido». O sea: verde = lo que TIENES (euros que entran, permiso concedido,
       ventaja que sí está). Fuera de eso no aparece.
     · ROJO: solo el NO. Nunca decora, nunca marca un aviso, nunca pinta un borde «porque queda bien».
       Él mismo puso el reparo y la salida: «entiendo que el verde igual no pega mucho por el resto de
       la estética, pero el rojo sé que se podría poner». Por eso el rojo va en el TRAZO del aspa y en
       la cruz de la tabla, y jamás en un fondo grande: en una página negra un plano rojo grita, un
       trazo rojo informa. */
  --verde: #3ecf8e;
  --rojo: #f2564d;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Inter, Roboto, system-ui, sans-serif;

  margin: 0;
  background: var(--fondo);
  color: var(--texto);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.62;
  letter-spacing: -0.003em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ⚠️ La Anton se sirve DESDE AQUÍ, no desde Google Fonts: cero peticiones a terceros y cero fuente que
   dependa de que un CDN esté vivo. Y es el subconjunto LATIN. Trampa ya pagada: la primera descarga fue
   el subconjunto VIETNAMITA, que carga sin un solo error y deja la Ñ y las tildes a otra familia, así que
   «NOMMEROS» se veía bien y cualquier palabra con tilde se rompía. */
@font-face {
  font-family: 'Anton';
  src: url('/web/fuentes/anton-latin.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

body.landing ::selection { background: var(--amarillo); color: #000; }
body.landing a { color: inherit; }

/* ── titulares ───────────────────────────────────────────────────────────────────────────────────── */
/* ⚠️ `estilo.css` pone `text-transform: uppercase` y `font-weight: 900` a TODO h1/h2. Aquí se deshace: la
   caja mixta es la mitad del salto de nivel visual, y las mayúsculas a este tamaño es lo que se lee como
   cartel de gimnasio de 1987. */
body.landing :is(h1, h2, h3) {
  text-transform: none;
  font-family: var(--sans);
  color: var(--texto);
  margin: 0;
}
/* ⚠️ `text-wrap: balance` NO es un adorno, y esto se vio MIRANDO la captura, no leyendo el CSS. El
   titular llevaba un `<br>` a mano para partirlo en dos frases; a 1440 px la primera frase no cabía en
   una línea, así que el navegador la volvía a partir y dejaba la palabra «nivel» sola en su renglón. Un
   salto escrito a mano solo funciona en el ancho exacto para el que se escribió, y la portada se ve en
   todos los demás. `balance` reparte las líneas él, en cada ancho, y el `<br>` sobra. Repartir mal el
   titular es de las cosas que más «cutre» leen y ninguna medida lo caza: no hay error, hay renglón feo. */
body.landing h1 {
  font-size: clamp(38px, 6.4vw, 62px);
  line-height: 1.04;
  letter-spacing: -0.033em;
  font-weight: 800;
  text-wrap: balance;
}
body.landing h2 {
  font-size: clamp(25px, 3.2vw, 36px);
  line-height: 1.14;
  letter-spacing: -0.028em;
  font-weight: 750;
  text-wrap: balance;
}
body.landing h3 {
  font-size: 18px;
  line-height: 1.3;
  letter-spacing: -0.015em;
  font-weight: 650;
}
body.landing p { margin: 0; }
.landing .acento { color: var(--amarillo); }
.landing .apagado { color: var(--texto-2); }

/* El OJO de sección: la etiqueta pequeña de arriba. Lleva un punto amarillo en vez de ir toda amarilla,
   que es lo que la convierte en señal en lugar de en mancha. */
.landing .ojo {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 0 0 14px;
  font-size: 12px; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--texto-3);
}
.landing .ojo::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--amarillo); flex: none;
}

/* ── botones ─────────────────────────────────────────────────────────────────────────────────────── */
.landing .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font: 650 16px/1 var(--sans);
  letter-spacing: -0.01em;
  text-transform: none;
  text-decoration: none;
  padding: 15px 26px;
  border-radius: 999px;
  background: var(--amarillo); color: #000;
  transition: transform .14s ease, box-shadow .14s ease, filter .14s ease;
}
.landing .btn:hover { filter: none; transform: translateY(-1px); box-shadow: 0 10px 30px rgba(255, 212, 0, .18); }
.landing .btn-grande { font-size: 17px; padding: 17px 32px; }
.landing .btn-mini { font-size: 14px; padding: 10px 18px; }
.landing .btn-linea {
  background: transparent; color: var(--texto);
  border: 1px solid var(--borde-vivo);
}
.landing .btn-linea:hover { background: var(--panel-alto); box-shadow: none; }

/* ── barra ───────────────────────────────────────────────────────────────────────────────────────── */
.landing .barra {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px max(18px, calc((100vw - 1120px) / 2));
  background: rgba(10, 10, 11, .72);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease;
}
.landing .barra.pegada { border-bottom-color: var(--borde); }
.landing .marca {
  font-family: 'Anton', var(--sans);
  font-size: 21px; letter-spacing: 0.045em;
  text-decoration: none; color: var(--texto);
}
.landing .barra nav { display: flex; align-items: center; gap: 10px; }
.landing .enlace-barra {
  color: var(--texto-2); text-decoration: none; font-size: 15px; padding: 10px 8px;
}
.landing .enlace-barra:hover { color: var(--texto); }

/* ── rejilla general ─────────────────────────────────────────────────────────────────────────────── */
.landing .ancho { max-width: 1120px; margin: 0 auto; padding: 0 18px 40px; }
.landing .bloque { padding: 76px 0 0; }
.landing .estrecho { max-width: 660px; }

/* ── hero ────────────────────────────────────────────────────────────────────────────────────────── */
.landing .hero {
  display: grid; gap: 40px;
  grid-template-columns: 1fr;
  align-items: center;
  padding: 52px 0 12px;
}
.landing .hero-sub {
  margin: 20px 0 0;
  color: var(--texto-2);
  font-size: clamp(17px, 1.9vw, 19px);
  max-width: 30em;
}
.landing .hero-sub strong { color: var(--texto); font-weight: 600; }
.landing .acciones { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 30px; }
.landing .letra-chica { color: var(--texto-3); font-size: 14px; margin: 0; }

/* EL VISOR. Es el sitio del Nomms de verdad: `landing.mjs` monta aquí el mismo motor WebGL2 que pinta el
   juego. Mientras no está montado se ve el póster, que es un fotograma REAL del mismo motor horneado, no
   un dibujo: la portada nunca enseña algo distinto de lo que hay dentro. */
.landing .visor {
  position: relative;
  width: 100%;
  max-width: 460px;
  margin-inline: auto;
  aspect-ratio: 1;
  border-radius: 22px;
  border: 1px solid var(--borde);
  overflow: hidden;
  background:
    radial-gradient(72% 62% at 50% 34%, rgba(255, 212, 0, .07) 0%, rgba(255, 212, 0, 0) 62%),
    radial-gradient(100% 100% at 50% 0%, #191920 0%, #101013 55%, #0b0b0d 100%);
  /* el gesto de girar necesita quedarse el arrastre horizontal; el vertical sigue siendo de la página, y
     por eso el motor pone `touch-action: pan-y` al agarrarlo */
  touch-action: pan-y;
  cursor: grab;
}
.landing .visor.girando { cursor: grabbing; }
.landing .visor-lienzo { position: absolute; inset: 0; }
.landing .visor-lienzo canvas { width: 100%; height: 100%; display: block; }
.landing .visor-poster {
  position: absolute; inset: 0; margin: auto;
  width: 100%; height: 100%; object-fit: contain;
  transition: opacity .35s ease;
}
.landing .visor.con-3d .visor-poster { opacity: 0; pointer-events: none; }
/* EL SUELO. Era una elipse NEGRA (`rgba(0,0,0,.55)`) sobre un fondo que ya es casi negro (#0b0b0d), y
   eso no puede anclar nada: sobre oscuro, una mancha oscura no se lee como sombra, se lee como suciedad.
   Iñaki lo señaló dos veces («la sombra debajo del Nomms no la has arreglado, todavía se sigue viendo»).
   Se invierte el gesto: en vez de OSCURECER debajo del bicho, se ILUMINA el trozo de suelo que pisa. Un
   charco de luz cálida hace el mismo trabajo (dice dónde está el plano) y en oscuro sí se ve, porque la
   señal va en la dirección en la que queda contraste. Mismo idioma en las tres escenas de `#que-es` y en
   las dos tarjetas de modo, con la variable de abajo.
   ⚠️ SEGUNDA PASADA (19-ago-2026): invertir el gesto era lo correcto y aun así seguía «quedando fatal esa
   línea». El fallo no era el color, era la INTENSIDAD y el BORDE. A `.17` sobre un panel de `#0e0e11` la
   mezcla sale (57, 50, 38): un caqui sucio, no luz — o sea el mismo problema de antes con otro tono. Y con
   dos paradas (`.17` → `0`) el `closest-side` deja una meseta plana en el centro con una caída corta al
   final, y esa caída es justo lo que el ojo lee como CANTO de una elipse. Se baja a `.075` y se añade una
   parada intermedia para que la caída sea larga y sin canto. Medido a 3x en `docs/capturas/beta-2026-08-19-suelo`: con
   `.17` la mancha se lee de un vistazo, con `.075` no hay elipse, solo un halo en los pies.
   🚫 No se puede juzgar esto midiendo la luminancia media de la tarjeta: la dominan las chapas amarillas
   y los chips, y ni se entera de la mancha. Se mira el recorte del SUELO, a 3x y con las capas apagadas
   de una en una (`docs/capturas/beta-2026-08-19-suelo/70-compara-suelo.png`). */
.landing { --suelo: radial-gradient(closest-side, rgba(255, 226, 140, .075) 0%, rgba(255, 226, 140, .03) 50%, rgba(255, 226, 140, 0) 100%); }
.landing .visor::before {
  content: ''; position: absolute; left: 50%; bottom: 11.5%;
  width: 42%; height: 9%; transform: translateX(-50%);
  background: var(--suelo);
  pointer-events: none;
}
.landing .visor-pista {
  position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; border-radius: 999px;
  background: rgba(12, 12, 14, .82); border: 1px solid var(--borde);
  color: var(--texto-2); font-size: 13px; white-space: nowrap;
  transition: opacity .3s ease;
}
.landing .visor-pista[hidden] { display: none; }
.landing .visor-pista.se-va { opacity: 0; }
/* La frase que Iñaki pidió LITERAL («este es el Nomms de serie, el tuyo lo haces tú») manda, y la pista de
   uso va DEBAJO y más apagada. Iban en la misma línea y la captura lo delató: leído del tirón, «el tuyo lo
   haces tú: toca uno» hace que «lo haces tú» signifique «tocando una miniatura», que es justo lo contrario
   de lo que promete (lo haces TÚ, en el creador). Separarlas devuelve cada frase a su trabajo. */
.landing .pie-visor { margin: 14px 0 0; text-align: center; color: var(--texto-3); font-size: 14px; }
.landing .pie-visor b { display: block; font-weight: 600; color: var(--texto-2); }
.landing .pie-visor span { display: block; margin-top: 2px; font-size: 13px; }

/* EL SELECTOR de apariencias. Era una sección entera a media página con cuatro PNG grandes y mudos, y de
   ahí salió el veredicto de Iñaki (18-ago-2026): «lo único guay es el Nomms que aparece al principio y que
   puedes mover. El resto, una puta mierda». Así que los cuatro dejan de ser un cartel y se convierten en el
   mando del que sí le gustaba: tocas uno y el Nomms grande se pone como él, en vivo.
   Las miniaturas son BOTONES, no imágenes con un `onclick`: se llega con el tabulador, se disparan con
   Enter y el lector de pantalla anuncia cuál está puesto (`aria-pressed`). */
.landing .selector {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
  max-width: 460px; margin: 18px auto 0;
}
.landing .mini {
  appearance: none; -webkit-appearance: none;
  padding: 0; border: 1px solid var(--borde); border-radius: 14px;
  background: linear-gradient(180deg, var(--panel-alto), var(--panel));
  cursor: pointer; overflow: hidden; position: relative;
  transition: border-color 160ms ease, transform 160ms ease, box-shadow 160ms ease;
}
.landing .mini img { display: block; width: 100%; height: auto; }
.landing .mini:hover { border-color: var(--borde-vivo); transform: translateY(-3px); }
.landing .mini:active { transform: translateY(-1px) scale(.97); }
.landing .mini:focus-visible { outline: 2px solid var(--amarillo); outline-offset: 3px; }
/* El puesto se marca con el amarillo de la casa Y con un punto: el color solo dejaría fuera a quien no
   lo distinga, y esto es el estado de un control, no un adorno. */
.landing .mini[aria-pressed='true'] {
  border-color: var(--amarillo);
  box-shadow: 0 0 0 1px var(--amarillo) inset, 0 10px 28px rgba(255, 212, 0, .14);
}
.landing .mini[aria-pressed='true']::after {
  content: ''; position: absolute; left: 50%; bottom: 6px; transform: translateX(-50%);
  width: 6px; height: 6px; border-radius: 50%; background: var(--amarillo);
}

/* ── «Qué es Nommeros»: el bloque de la verificación ─────────────────────────────────────────────── */
.landing .que-es {
  margin-top: 56px;
  padding: 30px;
  border: 1px solid var(--borde);
  border-radius: 18px;
  background: var(--panel);
}
.landing .que-es h2 { font-size: 22px; margin-bottom: 12px; }
.landing .que-es p { color: var(--texto-2); max-width: 78ch; }
.landing .que-es p + p { margin-top: 14px; }
.landing .que-es strong { color: var(--texto); font-weight: 600; }
.landing .que-es a { color: var(--amarillo); text-underline-offset: 3px; }

/* ── LA TIRA DE TRES VIÑETAS: qué es esto, contado sin leer ──────────────────────────────────────── */
/* Iñaki, 19-ago-2026: «¿qué es Nómeros? me gustaría que se viera más interactivo… que haya animaciones…
   que se entienda directamente sin tener que leer nada». Va ENCIMA del texto de la verificación, que no
   se toca (el candado vive en `landing.html`): la viñeta es para quien pasa de largo, el párrafo es para
   quien tiene que leerlo.
   ⚠️ EL REPOSO ES EL ESTADO BUENO, igual que en las tarjetas de modo, y aquí importa el doble: son tres
   escenas seguidas, así que `prefers-reduced-motion` (que apaga TODA animación al final del fichero) tiene
   que dejar tres cuadros que ya cuenten la historia — el Nomms creado con su chapa, los dos cables ya
   enganchados, y la máquina con el «+1 XP» y el nivel puestos. La animación solo sale de ahí y vuelve.
   ⚠️ Y NI UNA SOLA `steps()`, por lo mismo que dice la cabecera de este fichero: el hero de 24 fotogramas
   que iba a saltos se llamó «parpadeo» y «súper cutre», y esto es la misma página. */
.landing .pasos {
  list-style: none; padding: 0;
  display: grid; gap: 16px; grid-template-columns: 1fr;
  margin: 18px 0 30px;
}
.landing .paso {
  border: 1px solid var(--borde); border-radius: 14px;
  background: linear-gradient(180deg, var(--panel-alto) 0%, var(--panel) 100%);
  padding: 13px 13px 16px;
  display: grid; gap: 13px; grid-template-columns: 1fr; align-items: center;
}
.landing .paso-texto { min-width: 0; }
.landing .paso h3 {
  font-size: 16.5px; margin: 0 0 5px;
  display: flex; align-items: center; gap: 9px;
}
.landing .paso-num {
  flex: 0 0 auto;
  width: 23px; height: 23px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12.5px; font-weight: 700; letter-spacing: 0;
  color: #0a0a0b; background: var(--amarillo);
}
.landing .paso p { font-size: 15px; color: var(--texto-2); max-width: none; }

/* La escena de cada viñeta habla el mismo idioma que `.modo-escena` (mismo fondo, misma raya de suelo,
   mismo radio): son la misma página contando lo mismo en dos sitios, y si el fondo cambiara parecerían
   dos componentes de dos webs distintas. */
.landing .paso-escena {
  position: relative;
  height: 190px;
  border: 1px solid var(--borde); border-radius: 11px;
  background: linear-gradient(180deg, #0b0b0d, #0e0e11);
  overflow: hidden;
}
/* La raya de 1 px de antes cruzaba la escena de lado a lado a `bottom: 14px`, o sea EXACTAMENTE a la
   altura de la chapa (que empieza en `bottom: 11px`), y como ninguno de los dos llevaba `z-index` y el
   pseudo-elemento se genera el último, la raya se pintaba ENCIMA del botón. Iñaki: «queda fatal esa línea
   que hace de sombra, cuando aparece el botón de creado y conectado lo tapa». Se cambia por el mismo
   charco de luz del hero, que no cruza nada. Y va en `::before`, no en `::after`: el pseudo-elemento de
   CIERRE se genera el último y por eso se pintaba ENCIMA de la chapa; el de APERTURA se genera el
   primero y queda debajo de todo sin repartir `z-index` por media hoja. Ese solo cambio ya es el mínimo
   que pidió («como poco, que el botón esté por encima de esa línea»), y de paso arregla el hero: un
   suelo tiene que estar DETRÁS del bicho que lo pisa, no delante de sus pies. */
.landing .paso-escena::before {
  content: ''; position: absolute; left: 50%; bottom: 9px;
  width: 46%; height: 15%; transform: translateX(-50%);
  background: var(--suelo);
  pointer-events: none;
}

/* La chapa de «hecho»: el remate de las viñetas 1 y 2, y su estado de reposo es PUESTA. Lo que anima es
   el momento en que aparece, no su presencia. */
.landing .chapa-hecho {
  position: absolute; z-index: 2;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 11px 5px 8px; border-radius: 999px;
  font-size: 12.5px; font-weight: 700; letter-spacing: -0.01em;
}
.landing .chapa-hecho svg { width: 12px; height: 12px; }

/* Iñaki, 19-ago: «lo de creado, en vez de aparecer abajo a la derecha como lo de conectado, que
   aparezca arriba a la derecha, y que sea distinto el botón», y «el botón de conectado no quiero que
   aparezca a la vez que el de creado». Eran la MISMA chapa (mismo sitio, mismo relleno, mismo
   instante) en dos tarjetas contiguas, así que las dos viñetas remataban con el mismo destello y se
   leían como una sola cosa parpadeando dos veces. Ahora se separan en los TRES ejes a la vez:
     · SITIO   arriba-derecha contra abajo-derecha.
     · FORMA   «Creado» es de contorno (el Nomms acaba de nacer, todavía no ha hecho nada) y
               «Conectado» es macizo (ya hay un cable enganchado, eso sí es un logro).
     · MOMENTO 30-38% del ciclo contra 62-70%, que con 5.400 ms son 1,7 s de separación. */
.landing .chapa-creado {
  top: 11px; right: 11px;
  padding: 4px 10px 4px 7px;
  background: rgba(255, 212, 0, .1); color: var(--amarillo);
  border: 1px solid rgba(255, 212, 0, .45);
}
.landing .chapa-conectado {
  bottom: 11px; right: 11px;
  background: var(--amarillo); color: #0a0a0b;
  box-shadow: 0 4px 12px -6px rgba(255, 212, 0, .6);
}
.landing .paso.dentro .chapa-creado    { animation: chapa-entra 5400ms ease-out infinite; }
.landing .paso.dentro .chapa-conectado { animation: chapa-entra-tarde 5400ms ease-out infinite; }
@keyframes chapa-entra {
  0%, 30%   { opacity: 0; transform: translateY(7px) scale(.86); }
  38%       { opacity: 1; transform: none; }
  100%      { opacity: 1; transform: none; }
}
@keyframes chapa-entra-tarde {
  0%, 62%   { opacity: 0; transform: translateY(7px) scale(.86); }
  70%       { opacity: 1; transform: none; }
  100%      { opacity: 1; transform: none; }
}

/* ── viñeta 1: se crea un Nomms a cámara rápida ──────────────────────────────────────────────────── */
/* ⚠️ Los `bottom` salen de la caja alfa del horneado, no de probar números: el PNG es un cuadrado de 340
   y a `nomms-a`/`nomms-d` les sobran 39 px por debajo mientras que a `nomms-b`/`nomms-c` solo 10. A esta
   altura (172 px) eso son 19,7 px contra 5,1, así que con un solo `bottom` dos de los cuatro se quedarían
   flotando por encima de la raya del suelo justo mientras pasan. Es la misma cuenta que las tarjetas de
   modo, y si se rehornea con otros morfos se vuelve a medir con `Image.getbbox()`. */
.landing .cria {
  position: absolute; left: 50%; bottom: -6px;
  height: 172px; width: auto; transform: translateX(-50%);
  opacity: 0;
  filter: drop-shadow(0 9px 11px rgba(0, 0, 0, .34));
}
.landing .cria-alta { bottom: 9px; }
.landing .cria-final { opacity: 1; }          /* el reposo: el Nomms ya creado */
/* Cada cuerpo tapa al de abajo un cachito y se apaga. Sin `fill-mode`, a propósito: fuera de su tramo la
   regla base (`opacity: 0`) es la que manda, y por eso el retardo esconde en vez de congelar el primer
   fotograma. Los tres van al MISMO ciclo de 5.400 ms que el resto de la tira. */
.landing .paso.dentro .cria-1,
.landing .paso.dentro .cria-2,
.landing .paso.dentro .cria-3 { animation: cria-pasa 5400ms linear infinite; }
.landing .paso.dentro .cria-2 { animation-delay: 550ms; }
.landing .paso.dentro .cria-3 { animation-delay: 1100ms; }
@keyframes cria-pasa {
  0%, 10.1%  { opacity: 1; }
  10.2%, 100% { opacity: 0; }
}
/* 🔴 Y LA BASE SE APAGA MIENTRAS PASAN LOS OTROS. Es lo que se vio en la captura de las 900 ms: como el
   Nomms de reposo estaba encendido DEBAJO todo el rato, en cada relevo se veían dos cuerpos a la vez
   (los brazos y las antenas verdes asomando por detrás del azul), y eso no es «a cámara rápida», es una
   doble exposición. El relevo termina a los 1.650 ms, o sea el 30,5% del ciclo. */
.landing .paso.dentro .cria-final { animation: cria-base 5400ms linear infinite; }
@keyframes cria-base {
  0%, 30.4%   { opacity: 0; }
  30.5%, 100% { opacity: 1; }
}

/* Los mandos que se están moviendo mientras se crea. Reposo: la posición final.
   🔴 EL TIRADOR NO ES ADORNO. Sin él son tres barras horizontales apiladas, y eso ya significa otra cosa
   en una pantalla: el icono de menú hamburguesa. En la primera captura se leía como un menú, no como
   alguien moviendo controles. El circulito al final del relleno es lo único que convierte una barra en un
   mando, así que `.mando` NO puede llevar `overflow: hidden` (recortaría justo el tirador) y el redondeo
   lo pone cada trozo por su cuenta. */
.landing .mandos { position: absolute; left: 13px; top: 15px; display: grid; gap: 11px; width: 62px; }
.landing .mando { display: block; height: 4px; border-radius: 3px; background: #1e1e23; }
.landing .mando b {
  display: block; position: relative; height: 100%; border-radius: 3px; background: rgba(255, 212, 0, .8);
}
.landing .mando b::after {
  content: ''; position: absolute; right: -5px; top: 50%; margin-top: -5.5px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--amarillo); border: 2px solid #0d0d0f; box-sizing: border-box;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}
.landing .mando:nth-child(1) b { width: 74%; }
.landing .mando:nth-child(2) b { width: 45%; }
.landing .mando:nth-child(3) b { width: 88%; }
.landing .paso.dentro .mando:nth-child(1) b { animation: mando-1 5400ms ease-in-out infinite; }
.landing .paso.dentro .mando:nth-child(2) b { animation: mando-2 5400ms ease-in-out infinite; }
.landing .paso.dentro .mando:nth-child(3) b { animation: mando-3 5400ms ease-in-out infinite; }
@keyframes mando-1 { 0% { width: 16%; } 9% { width: 63%; } 18% { width: 34%; } 28% { width: 74%; } 100% { width: 74%; } }
@keyframes mando-2 { 0% { width: 80%; } 9% { width: 22%; } 18% { width: 61%; } 28% { width: 45%; } 100% { width: 45%; } }
@keyframes mando-3 { 0% { width: 35%; } 9% { width: 71%; } 18% { width: 18%; } 28% { width: 88%; } 100% { width: 88%; } }

/* ── viñeta 2: los canales se enganchan al Nomms ─────────────────────────────────────────────────── */
.landing .conecta-nomms {
  position: absolute; left: 50%; bottom: -4px;
  height: 158px; width: auto; transform: translateX(-50%);
  filter: drop-shadow(0 9px 11px rgba(0, 0, 0, .34));
}
.landing .cables { position: absolute; inset: 0; width: 100%; height: 100%; }
.landing .cable, .landing .punta {
  stroke: var(--borde-vivo); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; fill: none;
}
.landing .punta { stroke-width: 2.2; }
/* `stroke-dasharray: 240` es MAYOR que el trazo (unos 75 unidades de `viewBox`) a propósito: así el
   `dashoffset` de arranque lo esconde entero y el de reposo (0) lo enseña entero, sin tener que medir la
   curva a mano cada vez que se mueve un punto de control. */
.landing .paso.dentro .cable { stroke-dasharray: 240; animation: cable-dibuja 5400ms ease-out infinite; }
.landing .paso.dentro .punta { animation: punta-llega 5400ms ease-out infinite; }
.landing .paso.dentro .cable-2 { animation-delay: 420ms; }
.landing .paso.dentro .punta-2 { animation-delay: 420ms; }
@keyframes cable-dibuja {
  0%, 8%  { stroke-dashoffset: 240; stroke: var(--borde-vivo); }
  34%     { stroke-dashoffset: 0; stroke: var(--amarillo); }
  50%     { stroke: var(--borde-vivo); }
  100%    { stroke-dashoffset: 0; stroke: var(--borde-vivo); }
}
@keyframes punta-llega {
  0%, 30% { opacity: 0; }
  36%     { opacity: 1; stroke: var(--amarillo); }
  52%     { opacity: 1; stroke: var(--borde-vivo); }
  100%    { opacity: 1; stroke: var(--borde-vivo); }
}
/* Las chapas van en % para que sigan a los extremos del `viewBox` cuando la tarjeta cambia de ancho: el
   cable ARRANCA en x=62 y x=238 de 300, o sea al filo interior de cada chapa, y PARA en x=108 y x=192,
   antes del cuerpo. Las puntas señalan al Nomms; no se le clavan encima.
   🔴 Y se llaman `canal`, NO `red`, porque `estilo.css` ya define `.red` para las filas de la pantalla de
   cuenta (una rejilla de 34px 1fr auto con panel, borde y relleno). Esa hoja también la carga la landing,
   así que la clase repetida no daba error: heredaba en silencio la rejilla y el panel, y las dos chapas
   salían como pastillas anchas encima de la cabeza del Nomms. Se vio en la captura, no en el código. */
.landing .canal {
  position: absolute; top: 30px;
  display: grid;
  color: var(--texto-2);
}
.landing .canal-izq { left: 6%; }
.landing .canal-dcha { right: 6%; }
/* Iñaki, 19-ago: «pone YouTube y TikTok, tendrían que aparecer más: Instagram, LinkedIn, las que
   usamos y que vinculamos, que vayan cambiándose». No caben seis chapas en una escena de 190 px sin
   convertirla en una parrilla de iconos, así que lo que rota es el CONTENIDO de dos sitios fijos: los
   extremos de los dos cables no se mueven (el cable sigue acabando donde acababa) y dentro de cada uno
   se relevan tres marcas. Las tres se apilan en la MISMA celda de rejilla, como el 6 y el 7 de la
   chapa de nivel, para que el relevo no cambie el ancho del hueco: si cambiara, se leería como un
   salto del cuadro y no como un cambio de red.
   El ciclo es 16.200 ms = 3 x 5.400, o sea EXACTAMENTE tres vueltas de la escena: cada vuelta enseña
   una red distinta y en 16,2 s han pasado las seis. Y el `both` del `animation-fill-mode` es
   estructural, no adorno: sin él `.logo-red-1` volvería a su `opacity: 1` de base durante su turno de
   descanso y las otras dos destellarían antes de que corriera su retardo.
   🔴 19-ago-2026: esto se llamaba `.marca`, y `.marca` ya era el logotipo de la barra Y el trazo de las
   chapas de permisos. Como aquí hay un `opacity: 0` de base, la palabra NOMMEROS de la barra y los
   cuatro iconos de permisos salían INVISIBLES en la beta SERVIDA, en la landing y en `entrar.html`.
   Ninguna de las tres reglas estaba mal: se llamaban igual tres cosas distintas, y eso no da error.
   Tercera vez en este fichero (la anterior fue `.sube`), y por eso ahora lo vigila
   `tests/landing-clases.test.mjs`. */
.landing .logo-red {
  grid-area: 1 / 1;
  display: grid; justify-items: center; gap: 5px;
  opacity: 0;
}
.landing .logo-red-1 { opacity: 1; }   /* el REPOSO: lo que se ve sin JS, sin scroll y con reduced-motion */
.landing .canal svg {
  width: 38px; height: 38px; padding: 7px; box-sizing: border-box;
  border: 1px solid var(--borde-vivo); border-radius: 11px; background: #131316;
}
.landing .canal em { font-style: normal; font-size: 11px; color: var(--texto-3); letter-spacing: .01em; }
.landing .paso.dentro .canal { animation: canal-asoma 5400ms ease-out infinite; }
.landing .paso.dentro .canal-dcha { animation-delay: 420ms; }
@keyframes canal-asoma {
  0%     { opacity: 0; transform: translateY(-8px); }
  14%    { opacity: 1; transform: none; }
  100%   { opacity: 1; transform: none; }
}
.landing .paso.dentro .logo-red { animation: logo-red-releva 16200ms ease-in-out infinite both; }
.landing .paso.dentro .logo-red-2 { animation-delay: 5400ms; }
.landing .paso.dentro .logo-red-3 { animation-delay: 10800ms; }
@keyframes logo-red-releva {
  0%        { opacity: 0; transform: translateY(6px); }
  4%, 29%   { opacity: 1; transform: none; }
  33%, 100% { opacity: 0; transform: translateY(-6px); }
}

/* ── viñeta 3: la máquina cuenta, se lo manda, y sube de nivel ───────────────────────────────────── */
.landing .maquina {
  position: absolute; left: 13px; top: 50%; transform: translateY(-50%);
  width: 100px; padding: 10px 8px 8px; box-sizing: border-box;
  border: 1px solid var(--borde-vivo); border-radius: 12px; background: #131316;
  text-align: center;
}
.landing .maquina-luz {
  position: absolute; top: 8px; right: 8px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--amarillo);
}
.landing .paso.dentro .maquina-luz { animation: luz-parpadea 5400ms ease-in-out infinite; }
@keyframes luz-parpadea { 0%, 44%, 100% { opacity: 1; } 20% { opacity: .25; } }
.landing .maquina-barras {
  display: flex; align-items: flex-end; justify-content: center; gap: 3px;
  height: 24px; margin-bottom: 6px;
}
.landing .maquina-barras i { width: 7px; border-radius: 2px 2px 0 0; background: #2c2c33; }
.landing .maquina-barras i:nth-child(1) { height: 46%; }
.landing .maquina-barras i:nth-child(2) { height: 78%; }
.landing .maquina-barras i:nth-child(3) { height: 34%; }
.landing .maquina-barras i:nth-child(4) { height: 92%; }
.landing .paso.dentro .maquina-barras i { animation: barra-cuenta 5400ms ease-in-out infinite; }
.landing .paso.dentro .maquina-barras i:nth-child(2) { animation-delay: 110ms; }
.landing .paso.dentro .maquina-barras i:nth-child(3) { animation-delay: 220ms; }
.landing .paso.dentro .maquina-barras i:nth-child(4) { animation-delay: 330ms; }
@keyframes barra-cuenta {
  0%   { transform: scaleY(.35); }
  12%  { transform: scaleY(1); }
  22%  { transform: scaleY(.55); }
  32%  { transform: scaleY(1); }
  100% { transform: scaleY(1); }
}
.landing .maquina-barras i { transform-origin: 50% 100%; }
.landing .maquina-cifra {
  display: block; font-size: 21px; font-weight: 700; letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
}
/* Con importe hay dos glifos más («1.240 €» contra «291») dentro de la misma caja de 84 px útiles, así
   que baja el cuerpo. Va por el atributo que ya escribe el bucle para contar en euros, no por una
   clase aparte: una segunda marca del mismo hecho se desincroniza en cuanto alguien toque una sola. */
.landing .maquina-cifra[data-sufijo] { font-size: 17.5px; }
.landing .maquina-pie {
  display: block; margin-top: 1px;
  font-size: 10px; color: var(--texto-3);
  text-transform: uppercase; letter-spacing: .07em;
}

/* El paquete: lo que la máquina le manda. Sale de su borde derecho y muere en el Nomms, que está anclado
   a la derecha — por eso el viaje es un `translateX` FIJO y no un %: lo que varía con el ancho de la
   tarjeta es el hueco de en medio, no dónde empieza ni dónde acaba. */
.landing .paquete { position: absolute; left: 121px; top: 50%; margin-top: -4px; }
/* Iñaki, 19-ago: «que le aparezcan bolas en base al dinero» y «que la cantidad de comida y la
   experiencia que se gana cambie si ganas más o menos piezas». Un solo cuadrito no puede decir
   «más» ni «menos»: no hay con qué comparar. Ahora hay SEIS en el DOM y quien decide cuántas se ven
   es un selector de atributo, no el JavaScript — así que con el JS caído la escena sigue enseñando
   un caso coherente (las 4 bolas de `data-bolas="4"`, con sus 128 piezas y sus +12 XP) en vez de un
   hueco. El JS solo cambia el número del atributo. */
.landing .paquete i {
  position: absolute; display: none;
  width: 9px; height: 9px; border-radius: 3px; background: var(--amarillo);
  opacity: 0;
}
.landing .paquete[data-bolas="1"] i:nth-child(-n + 1),
.landing .paquete[data-bolas="2"] i:nth-child(-n + 2),
.landing .paquete[data-bolas="3"] i:nth-child(-n + 3),
.landing .paquete[data-bolas="4"] i:nth-child(-n + 4),
.landing .paquete[data-bolas="5"] i:nth-child(-n + 5),
.landing .paquete[data-bolas="6"] i:nth-child(-n + 6) { display: block; }
.landing .paquete i:nth-child(1) { top:   0px; left:  0px; }
.landing .paquete i:nth-child(2) { top: -13px; left:  1px; }
.landing .paquete i:nth-child(3) { top:  13px; left:  1px; }
.landing .paquete i:nth-child(4) { top:  -7px; left: 13px; }
.landing .paquete i:nth-child(5) { top:   7px; left: 13px; }
.landing .paquete i:nth-child(6) { top:   0px; left: 25px; }
.landing .paso.dentro .paquete i { animation: paquete-viaja 5400ms ease-in-out infinite; }
.landing .paso.dentro .paquete i:nth-child(2) { animation-delay:  90ms; }
.landing .paso.dentro .paquete i:nth-child(3) { animation-delay: 180ms; }
.landing .paso.dentro .paquete i:nth-child(4) { animation-delay: 270ms; }
.landing .paso.dentro .paquete i:nth-child(5) { animation-delay: 360ms; }
.landing .paso.dentro .paquete i:nth-child(6) { animation-delay: 450ms; }
@keyframes paquete-viaja {
  0%, 30% { opacity: 0; transform: translateX(0) scale(.5); }
  36%     { opacity: 1; transform: translateX(0) scale(1); }
  58%     { opacity: 1; transform: translateX(46px) scale(1); }
  64%     { opacity: 0; transform: translateX(56px) scale(.4); }
  100%    { opacity: 0; transform: translateX(0) scale(.5); }
}
.landing .cuenta-nomms {
  position: absolute; right: 2px; bottom: -4px;
  height: 158px; width: auto;
  filter: drop-shadow(0 9px 11px rgba(0, 0, 0, .34));
}
/* `.premio` es la MISMA chapa que sueltan las dos tarjetas de modo, y se reusa a propósito: es el mismo
   premio contado dos veces en la misma página. Aquí solo cambia dónde cae, porque esta escena tiene al
   Nomms a la derecha y no en el centro. */
.landing #paso-cuenta .premio { right: 15px; top: 44px; }
.landing .paso.dentro .premio { animation: premio-brota 5400ms ease-out infinite; }
@keyframes premio-brota {
  0%, 58% { opacity: 0; transform: translateY(12px) scale(.6); }
  66%     { opacity: 1; transform: translateY(0) scale(1.12); }
  72%     { opacity: 1; transform: none; }
  100%    { opacity: 1; transform: none; }
}
.landing .sube {
  position: absolute; left: 13px; bottom: 11px;
  padding: 4px 10px; border-radius: 999px;
  border: 1px solid rgba(255, 212, 0, .34); background: rgba(255, 212, 0, .12);
  font-size: 12.5px; font-weight: 650; color: var(--texto-2);
}
.landing .sube b { color: var(--amarillo); font-weight: 700; }

/* 🔴 Y EL NÚMERO TIENE QUE CAMBIAR. La chapa ya daba su pulso, pero pulsar enseñando el mismo «7» no es
   subir de nivel: es una chapa nerviosa. El guion de esta viñeta acaba en «y sube de nivel», así que si
   el número no se mueve, la última palabra de la frase no llega a pasar en pantalla.
   El 6 y el 7 se apilan en la MISMA celda de rejilla porque en una fuente proporcional no miden lo
   mismo: si la chapa cambiara de ancho al relevarse se leería como un parpadeo del recuadro y no como
   un ascenso. Y el reposo es el 7, el estado final, para que con `prefers-reduced-motion` (que apaga
   las animaciones) se siga viendo el fotograma bueno y no el de antes de subir. */
.landing .sube .nivel { display: inline-grid; }
.landing .sube .nivel i { grid-area: 1 / 1; font-style: normal; }
.landing .sube .nivel-antes { opacity: 0; }
.landing .paso.dentro .nivel-antes { animation: nivel-se-va 5400ms ease-out infinite; }
.landing .paso.dentro .nivel-luego { animation: nivel-llega 5400ms ease-out infinite; }
@keyframes nivel-se-va {
  0%, 70%   { opacity: 1; transform: none; }
  76%, 100% { opacity: 0; transform: translateY(-7px); }
}
@keyframes nivel-llega {
  0%, 70%   { opacity: 0; transform: translateY(8px); }
  76%, 100% { opacity: 1; transform: none; }
}
.landing .paso.dentro .sube { animation: sube-el-nivel 5400ms ease-out infinite; }
@keyframes sube-el-nivel {
  0%, 70% { transform: none; border-color: rgba(255, 212, 0, .34); }
  76%     { transform: scale(1.1); border-color: var(--amarillo); }
  86%     { transform: none; border-color: var(--amarillo); }
  100%    { transform: none; border-color: rgba(255, 212, 0, .34); }
}

/* Los dos botones de U0025. Sin JavaScript ni se pintan raros ni estorban: son dos botones que no hacen
   nada y la máquina se queda contando piezas, que es el caso por defecto. */
.landing .paso-mandos { display: flex; gap: 8px; margin-top: 12px; }
.landing .paso-chip {
  flex: 0 1 auto; min-width: 106px;
  padding: 7px 10px; border-radius: 9px;
  border: 1px solid var(--borde); background: #121215;
  color: var(--texto-2); font: inherit; font-size: 13.5px; font-weight: 600;
  cursor: pointer;
  transition: border-color .16s ease, color .16s ease, background-color .16s ease;
}
.landing .paso-chip:hover { border-color: var(--borde-vivo); color: var(--texto); }
.landing .paso-chip[aria-pressed='true'] {
  border-color: rgba(255, 212, 0, .38); background: rgba(255, 212, 0, .10); color: var(--texto);
}

/* ── los tres puntos de dolor, dibujados (R13) ───────────────────────────────────────────────────── */
/* Cada escena enseña el problema en vez de contarlo, y el reposo de las tres es el fotograma que MÁS
   duele: el pico que no depende de ti, las cuatro semanas que no suman, y el hueco del día flojo. Lo que
   anima es cómo se llega ahí, nunca el mensaje, así que apagar las animaciones no apaga el argumento. */
.landing .dolores { list-style: none; display: grid; gap: 16px; grid-template-columns: 1fr; margin: 18px 0 0; }
.landing .dolor {
  border: 1px solid var(--borde); border-radius: 14px;
  background: linear-gradient(180deg, var(--panel-alto) 0%, var(--panel) 100%);
  padding: 13px 13px 16px;
}
.landing .dolor h3 { font-size: 16.5px; margin: 14px 0 5px; }
.landing .dolor p { color: var(--texto-2); font-size: 15px; line-height: 1.5; margin: 0; }
.landing .dolor-escena {
  position: relative; height: 152px;
  border: 1px solid var(--borde); border-radius: 11px;
  background: linear-gradient(180deg, #0b0b0d, #0e0e11);
  overflow: hidden;
}

/* 1 · el pico. Las barras son lo que mide el algoritmo y saltan sin ton ni son; la raya amarilla es tu
   curro y NO se mueve ni un píxel. Que la raya esté quieta es el argumento entero, así que se dibuja
   plana y encima de todo. Las barras se mueven con `scaleY` desde abajo y no con `height` porque así
   basta UNA regla de animación para las siete: lo que las hace erráticas es el desfase de cada una. */
.landing .picos {
  position: absolute; left: 14px; right: 14px; bottom: 22px; height: 96px;
  display: flex; align-items: flex-end; gap: 6px;
}
.landing .picos i {
  flex: 1 1 0; border-radius: 3px 3px 0 0; transform-origin: 50% 100%;
  background: linear-gradient(180deg, #2e2e36, #1b1b20);
}
.landing .picos i:nth-child(1) { height: 20%; }
.landing .picos i:nth-child(2) { height: 72%; }
.landing .picos i:nth-child(3) { height: 26%; }
.landing .picos i:nth-child(4) { height: 12%; }
.landing .picos i:nth-child(5) { height: 58%; }
.landing .picos i:nth-child(6) { height: 16%; }
.landing .picos i:nth-child(7) { height: 66%; }
.landing .raya-curro {
  position: absolute; left: 14px; right: 14px; bottom: 62px; height: 0;
  border-top: 2px dashed rgba(255, 212, 0, .8);
}
.landing .raya-curro em {
  position: absolute; right: 0; top: -18px;
  font-style: normal; font-size: 10.5px; font-weight: 650; color: var(--amarillo);
}
.landing .problema.dentro .picos i { animation: pico-salta 3600ms ease-in-out infinite; }
.landing .problema.dentro .picos i:nth-child(2) { animation-delay: 700ms; }
.landing .problema.dentro .picos i:nth-child(3) { animation-delay: 1400ms; }
.landing .problema.dentro .picos i:nth-child(4) { animation-delay: 300ms; }
.landing .problema.dentro .picos i:nth-child(5) { animation-delay: 1900ms; }
.landing .problema.dentro .picos i:nth-child(6) { animation-delay: 1100ms; }
.landing .problema.dentro .picos i:nth-child(7) { animation-delay: 2300ms; }
@keyframes pico-salta {
  0%, 100% { transform: scaleY(1); }
  25%      { transform: scaleY(.35); }
  50%      { transform: scaleY(1.25); }
  75%      { transform: scaleY(.6); }
}

/* 2 · lo que no se acumula. Detrás, a trazos, la escalera que TENDRÍA que haber (lo que llevas hecho);
   delante, macizas, las cuatro semanas que se cuentan de verdad: todas igual de bajas, ninguna se apoya
   en la anterior. La escalera se queda quieta a propósito — es el listón, no el suceso. */
.landing .escalera, .landing .columnas {
  position: absolute; left: 14px; right: 14px; bottom: 22px; height: 96px;
  display: flex; align-items: flex-end; gap: 9px;
}
.landing .escalera i {
  flex: 1 1 0; border-radius: 4px 4px 0 0;
  border: 1px dashed rgba(255, 212, 0, .34); border-bottom: 0;
}
.landing .escalera i:nth-child(1) { height: 30%; }
.landing .escalera i:nth-child(2) { height: 52%; }
.landing .escalera i:nth-child(3) { height: 74%; }
.landing .escalera i:nth-child(4) { height: 96%; }
/* La etiqueta va arriba a la IZQUIERDA, que es el unico rincon vacio de la escena: a la derecha
   caia justo encima del cuarto peldano y su trazo vertical la TACHABA. */
.landing .escalera em {
  position: absolute; left: 0; top: -4px;
  font-style: normal; font-size: 10.5px; font-weight: 650; color: rgba(255, 212, 0, .78);
}
.landing .columnas i {
  flex: 1 1 0; border-radius: 4px 4px 0 0; height: 20%; transform-origin: 50% 100%;
  background: linear-gradient(180deg, #33333c, #1e1e24);
}
.landing .problema.dentro .columnas i { animation: semana-no-suma 4400ms ease-out infinite; }
.landing .problema.dentro .columnas i:nth-child(2) { animation-delay: 260ms; }
.landing .problema.dentro .columnas i:nth-child(3) { animation-delay: 520ms; }
.landing .problema.dentro .columnas i:nth-child(4) { animation-delay: 780ms; }
@keyframes semana-no-suma {
  0%       { transform: scaleY(.06); }
  16%      { transform: scaleY(1); }
  62%      { transform: scaleY(1); }
  70%, 100%{ transform: scaleY(.06); }
}

/* 3 · la racha rota. Seis días marcados y el séptimo vacío: el hueco es lo único que lleva amarillo, y
   lleva el trazo A TRAZOS para que no se lea como «un día más», sino como el que falta. */
.landing .racha {
  position: absolute; left: 14px; right: 14px; top: 50%; margin-top: -31px;
  display: flex; gap: 6px;
}
.landing .dia {
  flex: 1 1 0; height: 46px; border-radius: 9px;
  border: 1px solid rgba(255, 212, 0, .38); background: rgba(255, 212, 0, .13);
  position: relative;
}
.landing .dia::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px;
  border-radius: 50%; background: var(--amarillo);
}
.landing .dia-hueco { border: 1px dashed var(--borde-vivo); background: #0f0f12; }
.landing .dia-hueco::after { display: none; }
.landing .nadie-espera {
  position: absolute; right: 14px; top: 50%; margin-top: 25px;
  font-size: 10.5px; font-weight: 650; color: var(--texto-3);
}
.landing .problema.dentro .dia { animation: dia-se-marca 4600ms ease-out infinite; }
.landing .problema.dentro .dia:nth-child(2) { animation-delay: 180ms; }
.landing .problema.dentro .dia:nth-child(3) { animation-delay: 360ms; }
.landing .problema.dentro .dia:nth-child(4) { animation-delay: 540ms; }
.landing .problema.dentro .dia:nth-child(5) { animation-delay: 720ms; }
.landing .problema.dentro .dia:nth-child(6) { animation-delay: 900ms; }
/* El hueco NO entra en el relevo: no se marca nunca, que es justo lo que hay que ver. */
.landing .problema.dentro .dia-hueco { animation: none; }
@keyframes dia-se-marca {
  0%, 4%  { opacity: .18; transform: scale(.86); }
  12%     { opacity: 1; transform: scale(1); }
  86%     { opacity: 1; transform: scale(1); }
  96%, 100% { opacity: .18; transform: scale(.86); }
}

/* ── los permisos, dibujados ─────────────────────────────────────────────────────────────────────── */
/* R09: «los permisos de solo lectura se explican animados». Lo que hay que ver de un golpe es la
   PROPORCIÓN: una cosa que sí y tres que no. Por eso el que sí va entero y los tres que no van apagados y
   tachados, en vez de cuatro chapas iguales con distinto icono.
   ⚠️ El amarillo NO entra, y es a propósito: en esta página el amarillo es el premio, y pintar de premio
   «leer tu recuento» convierte un permiso que concedes en algo que ganas.
   🔴 Lo que sí entra, desde el 19-ago-2026, es el verde/rojo del §vars, y lo pidió Iñaki mirando esta
   misma chapa: «leer tu recuento debería tener un check, como que sí, en verde, y publicar, editar y
   borrar una cruz en rojo, rollo como que no puede, porque si no así no se refleja bien, no queda claro,
   yo no lo entendería». Aquí estaba justo el fallo de la versión anterior: encendido-vs-apagado se lee
   como «esto está activo / esto está gris», no como «esto sí puedo / esto NO puedo», que es lo único que
   hay que entender de una lista de permisos. El color va SOLO en el icono: si tiñera el texto, cuatro
   chapas de colores taparían la proporción (una que sí, tres que no), que es la otra mitad del mensaje. */
.landing .permisos {
  list-style: none;
  display: flex; flex-wrap: wrap; gap: 8px;
  margin: 16px 0 0;
}
.landing .permiso {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px 7px 9px; border-radius: 999px;
  border: 1px solid var(--borde); background: #101013;
  font-size: 13.5px; font-weight: 600; letter-spacing: -0.005em;
}
.landing .permiso svg { width: 15px; height: 15px; flex: 0 0 auto; }
.landing .permiso-si { color: var(--texto); border-color: rgba(62, 207, 142, .32); background: var(--panel-alto); }
.landing .permiso-no { color: var(--texto-3); }
.landing .permiso-si svg { color: var(--verde); }
.landing .permiso-no svg { color: var(--rojo); }
/* El tachón se DIBUJA. `stroke-dasharray: 40` es mayor que cada aspa (17 unidades por trazo) para no
   tener que medir: escondida entera con el `dashoffset` de arranque, entera con el de reposo.
   ⚠️ Y el reposo es CON la marca puesta: sin JavaScript, o con `prefers-reduced-motion`, se ven las
   cuatro chapas ya marcadas, que es la información. Lo que se pierde es el gesto de marcarlas. */
.landing .permiso-trazo { stroke-dasharray: 40; stroke-dashoffset: 0; }
.landing .que-es.dentro .permiso-trazo { animation: permiso-se-dibuja 700ms ease-out both; }
.landing .que-es.dentro .permiso:nth-child(1) .permiso-trazo { animation-delay: 120ms; }
.landing .que-es.dentro .permiso:nth-child(2) .permiso-trazo { animation-delay: 400ms; }
.landing .que-es.dentro .permiso:nth-child(3) .permiso-trazo { animation-delay: 560ms; }
.landing .que-es.dentro .permiso:nth-child(4) .permiso-trazo { animation-delay: 720ms; }
@keyframes permiso-se-dibuja {
  from { stroke-dashoffset: 40; }
  to   { stroke-dashoffset: 0; }
}

/* ── los DOS MODOS ───────────────────────────────────────────────────────────────────────────────── */
/* Aquí vivía un conmutador de pestañas (`.conmutador` / `.pestana`) que enseñaba un modo cada vez. Se ha
   retirado entero: lo que hay que poder hacer en esta sección es decidir cuál es el tuyo DE UN VISTAZO, y
   con pestañas la comparación la tenía que hacer la memoria. Las dos tarjetas, al lado, y ya. */
.landing .modos { display: grid; gap: 18px; grid-template-columns: 1fr; margin-top: 32px; }
.landing .modo {
  position: relative;
  display: flex; flex-direction: column;
  padding: 26px;
  border: 1px solid var(--borde);
  border-radius: 18px;
  background: linear-gradient(180deg, var(--panel-alto) 0%, var(--panel) 100%);
  transition: border-color .18s ease, transform .18s ease;
}
.landing .modo:hover { border-color: var(--borde-vivo); }
/* 🔴 El hover se re-declara CON `.dentro` porque si no lo pisa el revelado: `.landing.con-revelado
   .revela.dentro { transform: none }` tiene 4 clases y `.landing .modo:hover` solo 2, así que la tarjeta
   se quedaba sin el empujoncito al pasar por encima. */
.landing .modo.dentro:hover { transform: translateY(-2px); }

/* LA ESCENA. El Nomms de ese modo, su emblema y la animación de qué le hace SUBIR. En el creador entra
   una pieza publicada, en el de MRR entra una moneda, y de los dos sale el mismo «+1 XP»: la entrada es
   distinta, el premio es el mismo, y eso es exactamente lo que hace el sistema por dentro.
   ⚠️ EL REPOSO ES EL ESTADO BUENO. Sin JavaScript (no llega `.dentro`) o con `prefers-reduced-motion`
   (que apaga toda animación más abajo), la escena se queda en una composición quieta y completa: el
   Nomms, el emblema, la ficha de entrada abajo y el «+1 XP» arriba. La animación solo sale de ahí y
   vuelve. Nada de lo que hay que entender depende de que algo se mueva. */
.landing .modo-escena {
  position: relative;
  height: 210px; margin-bottom: 20px;
  border: 1px solid var(--borde); border-radius: 14px;
  /* ⚠️ Aquí había un `radial-gradient(120% 90% at 50% 108%, rgba(255,212,0,.10), transparent 62%)`, y era
     la MITAD de la mancha que Iñaki señaló: 120% de ancho centrado por DEBAJO de la caja, o sea un velo
     oliva de lado a lado justo donde se posa el charco del suelo. Los dos juntos sumaban al caqui sucio.
     El velo no aportaba nada que no aporte ya el degradado vertical, y quitarlo es lo que deja el fondo
     negro limpio del que la elipse tenue puede destacar sin parecer suciedad. */
  background: linear-gradient(180deg, #0b0b0d, #0e0e11);
  overflow: hidden;
}
/* La raya del suelo: es lo que hace que el alto/bajo de cada Nomms se LEA, en vez de que parezcan dos
   recortes flotando a distinta altura. */
.landing .modo-escena::before {
  content: ''; position: absolute; left: 50%; bottom: 10px;
  width: 44%; height: 14%; transform: translateX(-50%);
  background: var(--suelo);
  pointer-events: none;
}
.landing .modo-nomms {
  position: absolute; left: 50%; bottom: 10px;
  height: 200px; width: auto; transform: translateX(-50%);
  filter: drop-shadow(0 10px 12px rgba(0, 0, 0, .34));
}
/* ⚠️ Número atado al horneado: el PNG es un cuadrado de 340 y cada Nomms ocupa un trozo distinto. El de
   MRR es BAJO, así que su recorte deja 23 px de aire por debajo y el de creador solo 6: con el mismo
   `bottom` uno se quedaba flotando sobre la raya del suelo. Los dos valores están cuadrados con el
   `bottom: 16px` de esa raya para que las plantas la PISEN: medido en una captura a 4x, con los números
   de antes la raya cruzaba los tobillos de los dos. Si se rehornea con otros morfos, se vuelve a medir la
   caja alfa (`Image.getbbox()`) y se ajusta esto. */
.landing #modo-mrr .modo-nomms { bottom: -6px; }
.landing .modo-ico {
  position: absolute; top: 14px; right: 14px;
  width: 42px; height: 42px; border-radius: 12px;
  display: grid; place-items: center;
  background: rgba(255, 212, 0, .1); color: var(--amarillo);
  border: 1px solid rgba(255, 212, 0, .18);
}
.landing .modo-ico svg { width: 24px; height: 24px; }

/* Lo que ENTRA (la red que ha publicado / la plataforma que ha cobrado) y lo que SALE (el XP y su cifra).
   La entrada ya no es un icono: es una PILA de sellos en la misma celda de rejilla, y solo se ve el que
   diga `data-marca`. Lo pone `web/landing.mjs` en el instante en que la pieza está invisible. */
.landing .entrada { position: absolute; left: 20px; bottom: 24px; display: grid; }
.landing .sello { grid-area: 1 / 1; display: grid; justify-items: center; gap: 5px; }
.landing .sello i {
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--borde-vivo); background: #131316; color: var(--texto);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
}
.landing .sello svg { width: 21px; height: 21px; }
.landing .sello em {
  font-style: normal; font-size: 10.5px; font-weight: 600; letter-spacing: -0.01em;
  color: var(--texto-2); white-space: nowrap;
}
/* ⚠️ EL REPOSO. Sin `data-marca` (o sea: sin JavaScript) se ve el PRIMERO y ninguno más. Solo cuando el
   relevo está vivo pasa a mandar el atributo, y entonces la regla de abajo enciende el que toque. */
.landing .sello { opacity: 0; }
.landing .sello:first-child { opacity: 1; }
.landing .entrada[data-marca] .sello { opacity: 0; }
.landing .entrada[data-marca="1"] .sello:nth-child(1),
.landing .entrada[data-marca="2"] .sello:nth-child(2),
.landing .entrada[data-marca="3"] .sello:nth-child(3),
.landing .entrada[data-marca="4"] .sello:nth-child(4),
.landing .entrada[data-marca="5"] .sello:nth-child(5) { opacity: 1; }
/* Las DOS entradas pesan igual a propósito. La moneda llevaba el amarillo y la pieza no, y en el móvil
   a 2x la pieza se leía como un botón apagado mientras la moneda brillaba: parecía que al Nomms Creador
   le faltaba algo. Aquí el amarillo es el PREMIO y el verde es el DINERO, así que la entrada va neutra en
   las dos y cada color se queda donde significa algo. */

/* La chapa del XP y la cifra que la explica viajan JUNTAS: son una sola frase («+9 XP» «9 vídeos, 12.400
   visitas»), y dos animaciones gemelas se desfasarían medio fotograma el día que alguien toque una.
   `z-index` porque el Nomms va DESPUÉS en el HTML, y sin esto la imagen le pasaría por encima al dato,
   que es más ancho que la chapa y llega hasta el centro de la escena. */
.landing .recompensa {
  position: absolute; right: 22px; top: 86px; z-index: 2;
  display: grid; justify-items: end; gap: 6px;
}
.landing .recompensa .premio { position: static; }
.landing .dato {
  padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--borde-vivo); background: rgba(10, 10, 12, .86);
  color: var(--texto-2); font-size: 11.5px; font-weight: 600; letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.landing .dato-euros {
  color: var(--verde);
  border-color: rgba(62, 207, 142, .38);
  background: rgba(11, 32, 24, .88);
}
/* ⚠️ El `top` y el recorrido de `sale-el-xp` están CUADRADOS con el emblema: el emblema ocupa de 14 a
   56 px, y la chapa sube 22 px desde 86, o sea acaba en 64. Con los números de antes (top 62, subida 26)
   la chapa se metía DEBAJO del emblema justo en el fotograma más visible, y no se veía en la captura
   quieta de la tarjeta de la izquierda porque la de la derecha va a contratiempo. Si se mueve uno, se
   mueve el otro. */
.landing .premio {
  position: absolute; right: 22px; top: 86px;
  padding: 5px 11px; border-radius: 999px;
  background: var(--amarillo); color: #000;
  font-size: 13px; font-weight: 700; letter-spacing: -0.01em;
  box-shadow: 0 4px 12px -6px rgba(255, 212, 0, .6);
}
.landing .modo.dentro .entrada { animation: entra-al-nomms 3600ms cubic-bezier(.3, .8, .4, 1) infinite; }
.landing .modo.dentro .recompensa { animation: sale-el-xp 3600ms ease-out infinite; }
/* el segundo modo va a contratiempo: dos escenas latiendo a la vez se leen como un parpadeo de la página */
.landing #modo-mrr.dentro .entrada,
.landing #modo-mrr.dentro .recompensa { animation-delay: 1100ms; }
/* 🔴 LAS DOS COREOGRAFÍAS ESTÁN GIRADAS 46% RESPECTO A LO QUE PARECE. El orden de lo que se ve no ha
   cambiado ni un milisegundo (la pieza espera, entra al Nomms, y justo ahí sale la chapa); lo que se ha
   movido es DÓNDE cae el corte entre vuelta y vuelta, que antes caía con las dos cosas a la vista.
   Y eso importa porque `landing.mjs` cambia la marca y las cifras en el evento `animationiteration`, o
   sea EXACTAMENTE en el 0%: si en ese instante algo se ve, el cambio se ve como un salto.
   Por eso el 0% de las dos es `opacity: 0`, y con margen a los dos lados (0-3% y 99-1%), que son ~2
   fotogramas a 60 Hz. Si alguien vuelve a tocar estos porcentajes: el 0% se queda invisible o se rompe. */
@keyframes entra-al-nomms {
  0%, 3%   { transform: translate(74px, -96px) scale(.5); opacity: 0; }
  4%, 54%  { transform: none; opacity: 1; }
  62%      { transform: translate(0, 14px) scale(.85); opacity: 0; }
  80%      { transform: translate(36px, -46px) scale(1); opacity: 1; }
  100%     { transform: translate(74px, -96px) scale(.5); opacity: 0; }
}
@keyframes sale-el-xp {
  0%, 1%    { transform: translateY(16px) scale(.6); opacity: 0; }
  10%       { transform: translateY(0) scale(1.14); opacity: 1; }
  16%       { transform: none; opacity: 1; }
  40%       { transform: translateY(-22px); opacity: 0; }
  41%, 98%  { transform: none; opacity: 1; }
  99%, 100% { transform: translateY(16px) scale(.6); opacity: 0; }
}

.landing .modo h3 { margin-bottom: 6px; }
.landing .modo-reclamo { color: var(--amarillo); font-size: 14px; font-weight: 600; margin-bottom: 12px; }
.landing .modo p { color: var(--texto-2); font-size: 16px; }
.landing .modo-unidad {
  display: inline-block; align-self: flex-start; margin: 16px 0 22px;
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--borde-vivo); background: #0d0d0f;
  color: var(--texto-2); font-size: 13px;
}
/* `auto` para que las dos fichas de nivel queden a la misma altura aunque un párrafo mida una línea más */
.landing .nota-modos {
  margin-top: 22px; color: var(--texto-2); font-size: 17px; line-height: 1.5;
}

/* LA TARJETA DE NIVEL. La misma que se ve dentro del juego, y está aquí por lo que enseñan las capturas
   de Memmaros: cada sección suya lleva su maqueta del producto. Sin esto la sección «cómo funciona» es
   texto sobre negro, que es justo lo que se veía «cutre».
   Y el tratamiento es de HUD de juego a propósito: medalla de nivel en vez de la palabra «Nivel 7» en
   texto plano, la fase como chapa, y la barra por segmentos con brillo. Puesto en texto corriente, lo que
   dentro del juego es un logro aquí parecía una fila de una hoja de cálculo. */
.landing .ficha-nivel {
  margin-top: auto; padding: 20px;
  border: 1px solid var(--borde); border-radius: 14px;
  background: linear-gradient(180deg, #0d0d10, #0a0a0c);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .035);
}
.landing .ficha-cab { display: flex; align-items: center; gap: 14px; }
.landing .medalla {
  flex: none; width: 58px; height: 58px; border-radius: 50%;
  display: grid; place-content: center; text-align: center; line-height: 1;
  background: radial-gradient(80% 80% at 50% 22%, #201a05, #0b0b0d 78%);
  border: 2px solid rgba(255, 212, 0, .55);
  box-shadow: 0 0 0 4px rgba(255, 212, 0, .07), inset 0 1px 0 rgba(255, 255, 255, .09);
}
.landing .medalla b { display: block; font-size: 23px; font-weight: 800; color: var(--amarillo); letter-spacing: -0.03em; }
.landing .medalla small { display: block; margin-top: 3px; font-size: 9px; letter-spacing: .16em; text-transform: uppercase; color: var(--texto-3); }
/* SUBIR DE NIVEL, que es el único momento en que la ficha cambia de estado de verdad. Iñaki, 19-ago:
   «que se vea cómo va sumando su experiencia». Sin un gesto propio, la barra se vacía y el número de la
   chapa cambia solo: se lee como un parpadeo, o peor, como haber PERDIDO la XP que acababa de entrar.
   ⚠️ El 100% devuelve la sombra EXACTA de `.medalla` de arriba, no `none`: la clase se queda puesta y
   con `both` el último fotograma es lo que se ve para siempre. Si alguien cambia esa sombra, cambia las
   dos. Lo pone y lo quita `landing.mjs`; sin JavaScript esta regla no llega a aplicarse nunca. */
/* 🔴 Esta clase se llama `ficha-sube` y NO `sube`, y no es cosmético: `.landing .sube` (la chapa de
   nivel del paso 3, ~420 líneas más arriba) es `position: absolute`, y con `.ficha-nivel.sube` la
   ficha entera SALÍA DEL FLUJO. La tarjeta se desinflaba de 641 a 476 px (exactamente los 165 px de
   la ficha) y la ficha se plantaba encima del párrafo. Medido en la beta el 19-ago-2026, y es lo que
   Iñaki fotografió. Al añadir una clase de estado, compruébala contra TODO el fichero: no hay error,
   no hay aviso, y solo se ve cuando el estado se dispara. */
.landing .ficha-nivel.ficha-sube .medalla { animation: sube-de-nivel 760ms cubic-bezier(.2, .9, .3, 1) both; }
@keyframes sube-de-nivel {
  0% {
    transform: none;
    box-shadow: 0 0 0 4px rgba(255, 212, 0, .07), inset 0 1px 0 rgba(255, 255, 255, .09);
  }
  30% {
    transform: translateY(-5px) scale(1.12);
    box-shadow: 0 0 0 13px rgba(255, 212, 0, .17), inset 0 1px 0 rgba(255, 255, 255, .09);
  }
  100% {
    transform: none;
    box-shadow: 0 0 0 4px rgba(255, 212, 0, .07), inset 0 1px 0 rgba(255, 255, 255, .09);
  }
}
.landing .ficha-fase {
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--borde-vivo); background: #0d0d0f;
  color: var(--texto-2); font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
}
.landing .barra-xp {
  position: relative;
  margin: 16px 0 10px; height: 13px; border-radius: 999px;
  background: #08080a; border: 1px solid var(--borde); overflow: hidden;
}
/* los tramos: la barra deja de ser un tubo y se lee como una barra de juego */
.landing .barra-xp::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: repeating-linear-gradient(90deg, transparent 0 calc(10% - 2px), rgba(0, 0, 0, .8) calc(10% - 2px) 10%);
}
/* La barra se llena al asomar, no está llena de entrada: el gesto que cuenta es el de SUBIR. El ancho
   final lo escribe el HTML (`style="width: 68%"`), lo guarda `landing.mjs` y lo devuelve; por eso sin JS
   la barra sale ya en su sitio en vez de vacía. */
.landing .barra-xp i {
  position: relative; overflow: hidden;
  display: block; height: 100%; width: 68%;
  background: linear-gradient(90deg, #FFA800, var(--amarillo) 70%, #FFF0A8);
  border-radius: 999px;
  box-shadow: 0 0 14px -2px rgba(255, 212, 0, .55);
  transition: width 1100ms cubic-bezier(.22, 1, .36, 1);
}
/* el destello que recorre lo ya ganado. Decoración pura: en reposo no está, y no se pierde nada */
.landing .modo.dentro .barra-xp i::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 42px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .55), transparent);
  animation: destello-xp 2600ms ease-in-out 1200ms infinite;
}
@keyframes destello-xp {
  0%        { transform: translateX(-60px); }
  55%, 100% { transform: translateX(560px); }
}
.landing .ficha-pie { color: var(--texto-2); font-size: 14px; }
.landing .ficha-pie b { color: var(--texto); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ── doctrina ────────────────────────────────────────────────────────────────────────────────────── */
/* ── la comparativa (R15, rehecha el 19-ago) ──────────────────────────────────────────────────────── */
/* La anterior era una tabla de dos columnas con la cabecera en versalitas espaciadas y filetes de un
   píxel, y su veredicto fue «bastante, no sé, ochentero, no me convence» (T07) + «se queda en tres
   filas y no mola» (T05). Lo que la arregla no es maquillarla: es que sea una MATRIZ de verdad, que es
   lo que él mandó mirar («fíjate en la de Memmaros, es mil veces mejor», T08). O sea criterio a la
   izquierda, un servicio por columna, iconos centrados, y la columna nuestra encendida de arriba abajo
   con las esquinas redondeadas, que es lo que hace que la conclusión se vea antes de leer una celda.
   🎨 Y el reparto de color, que fue una orden literal (T09) con su propio reparo dentro: «que el no se
   vea en rojo y el sí en verde. Entiendo que el verde aquí igual no pega mucho por el resto de la
   estética, pero el rojo sé que se podría poner». Se cumple entera respetando el reparo: rojo y verde
   viven SOLO en el trazo del icono, y el realce de columna sigue siendo el oro. En una página negra un
   plano de color grita; un trazo informa. */
.landing .comparativa-caja {
  max-width: 880px; margin: 28px 0 0;
  padding: 4px 10px 10px;
  border: 1px solid var(--borde); border-radius: 16px;
  background: var(--panel);
  /* En móvil seis columnas no caben ni encogiendo la letra: antes se apretaba el texto hasta que la
     frase se partía en dos, y la frase ES el argumento. Mejor que se arrastre de lado. */
  overflow-x: auto; -webkit-overflow-scrolling: touch;
}
.landing .comparativa {
  width: 100%; min-width: 620px;
  border-collapse: separate; border-spacing: 0;
  font-size: 14px;
}
/* Los iconos van centrados en su columna y el criterio a la izquierda: eso solo es una regla y su
   excepción, y es lo que permite leer la tabla en vertical (¿cuántos síes tiene esta columna?) además
   de en horizontal. */
.landing .comparativa th, .landing .comparativa td { text-align: center; vertical-align: middle; }
.landing .comparativa .esquina, .landing .comparativa tbody th { text-align: left; }
.landing .comparativa .esquina {
  width: 31%; padding: 15px 14px 12px 12px;
  font-size: 12px; font-weight: 600; color: var(--texto-3);
}
.landing .comparativa thead th {
  padding: 15px 8px 12px; font-size: 13px; font-weight: 650;
  color: var(--texto-2); line-height: 1.25;
}
/* La columna de Nommeros: fondo, marco y esquinas. El fondo lo llevan las CELDAS y no un `<col>`
   porque `<col>` no acepta `border-radius` en ningún navegador. */
.landing .comparativa .cab-nom {
  color: var(--amarillo); font-weight: 750;
  background: rgba(255, 212, 0, .06);
  border-radius: 12px 12px 0 0;
  box-shadow: inset 1px 0 0 rgba(255, 212, 0, .22), inset -1px 0 0 rgba(255, 212, 0, .22),
              inset 0 1px 0 rgba(255, 212, 0, .22);
}
.landing .comparativa .cab-pie {
  display: block; margin-top: 3px;
  font-size: 10.5px; font-weight: 600; color: var(--texto-3);
}
.landing .comparativa tbody th {
  padding: 14px 14px 14px 12px; font-weight: 600; color: var(--texto);
  border-top: 1px solid var(--borde);
}
.landing .comparativa tbody td { padding: 14px 8px; border-top: 1px solid var(--borde); }
.landing .comparativa td.col-nom {
  background: rgba(255, 212, 0, .06);
  border-top-color: rgba(255, 212, 0, .16);
  box-shadow: inset 1px 0 0 rgba(255, 212, 0, .22), inset -1px 0 0 rgba(255, 212, 0, .22);
}
.landing .comparativa tbody tr:last-child td.col-nom {
  border-radius: 0 0 12px 12px;
  box-shadow: inset 1px 0 0 rgba(255, 212, 0, .22), inset -1px 0 0 rgba(255, 212, 0, .22),
              inset 0 -1px 0 rgba(255, 212, 0, .22);
}
.landing .comparativa svg {
  width: 17px; height: 17px; vertical-align: -3px;
  fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
}
.landing .comparativa .aspa { color: var(--rojo); }
.landing .comparativa .visto { color: var(--verde); }
/* El visto se DIBUJA, igual que el tachón de los permisos y por el mismo motivo: `stroke-dasharray`
   holgado (24 > los ~16 del trazo) para no tener que medir el path. Escalonado por FILA, no por celda:
   con 30 iconos, animarlos uno a uno sería parpadeo, y en cambio fila a fila se lee como que la tabla
   se está rellenando sola.
   ⚠️ Y el reposo es CON el visto puesto: sin JavaScript, o con `prefers-reduced-motion`, la tabla se ve
   entera y marcada. Lo que se pierde es el gesto, nunca el dato. */
.landing .comparativa .visto path { stroke-dasharray: 24; stroke-dashoffset: 0; }
.landing .comparativa-caja.dentro .visto path { animation: visto-se-dibuja 520ms ease-out both; }
.landing .comparativa-caja.dentro tbody tr:nth-child(1) .visto path { animation-delay: 160ms; }
.landing .comparativa-caja.dentro tbody tr:nth-child(2) .visto path { animation-delay: 250ms; }
.landing .comparativa-caja.dentro tbody tr:nth-child(3) .visto path { animation-delay: 340ms; }
.landing .comparativa-caja.dentro tbody tr:nth-child(4) .visto path { animation-delay: 430ms; }
.landing .comparativa-caja.dentro tbody tr:nth-child(5) .visto path { animation-delay: 520ms; }
.landing .comparativa-caja.dentro tbody tr:nth-child(6) .visto path { animation-delay: 610ms; }
@keyframes visto-se-dibuja {
  from { stroke-dashoffset: 24; }
  to   { stroke-dashoffset: 0; }
}
@media (max-width: 560px) {
  .landing .comparativa-caja { padding: 2px 6px 6px; }
  .landing .comparativa { font-size: 13px; min-width: 540px; }
  .landing .comparativa .esquina { width: 34%; padding: 12px 8px 10px 8px; font-size: 11px; }
  .landing .comparativa thead th { padding: 12px 6px 10px; font-size: 12px; }
  .landing .comparativa tbody th { padding: 12px 10px; font-size: 12.5px; }
  .landing .comparativa tbody td { padding: 12px 6px; }
  .landing .comparativa svg { width: 15px; height: 15px; }
  /* En un movil de 390 px la matriz se arrastra de lado, y arrastrandose desaparecia JUSTO la columna
     que hay que ver: al abrir la seccion el visitante se quedaba mirando a Duolingo y a Habitica sin
     vernos a nosotros, que es lo contrario de para lo que existe la tabla. Se clavan las DOS que
     sostienen la lectura (el criterio a la izquierda y Nommeros a la derecha) y lo que corre por
     debajo son los rivales, que es lo secundario. De regalo, el hueco entre las dos columnas clavadas
     ya ES el aviso de que ahi dentro hay mas: no hace falta pintar una flechita.
     ⚠️ `position: sticky` en celdas de tabla exige `border-collapse: separate` (lo esta arriba) y un
     fondo OPACO: con el amarillo al 6% las celdas de los rivales se ven pasar POR DEBAJO. Por eso el
     `#201e13`, que es ese mismo 6% ya resuelto contra `--panel`. */
  .landing .comparativa .esquina,
  .landing .comparativa tbody th {
    position: sticky; left: 0; z-index: 2;
    background: var(--panel);
  }
  .landing .comparativa .cab-nom,
  .landing .comparativa td.col-nom {
    position: sticky; right: 0; z-index: 2;
    background: #201e13;
  }
}
/* Lo que él cazó (D01): decir «no compras nada» era mentira, porque con dinero real SÍ se compra. Va
   debajo de la tabla y en llano, no en una celda: es el matiz que sostiene la fila «pagando no
   adelantas», y esconderlo es justo lo que hacía que la tabla se leyera como un truco. */
.landing .pie-tabla { margin-top: 14px; max-width: 62ch; font-size: 13px; color: var(--texto-3); }
/* Con la matriz, el dato de una celda es el ICONO. Sin esto un lector de pantalla anuncia la fila
   entera vacía: seis criterios y ni un sí ni un no. */
.landing .solo-lector {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.landing .remate { margin-top: 22px; color: var(--texto-2); max-width: 62ch; }

/* ── qué hay dentro (R18/R16/R17) ────────────────────────────────────────────────────────────────── */
/* La tarjeta pierde su `padding` y lo hereda SOLO el pie: así la imagen llega hasta el borde redondeado
   en vez de flotar en un marco, que es lo que la hace mandar sobre el texto. El `overflow: hidden` es lo
   que recorta la imagen contra el radio de la tarjeta; sin él las esquinas de la foto salen cuadradas por
   encima del borde y se ve como un fallo. */
.landing .rejilla-cosas { display: grid; gap: 16px; grid-template-columns: 1fr; margin-top: 16px; }
.landing .cosa {
  padding: 0; overflow: hidden;
  border: 1px solid var(--borde); border-radius: 16px; background: var(--panel);
}
.landing .cosa-ancha { margin-top: 30px; }
.landing .cosa-pie { padding: 18px 22px 20px; }
.landing .cosa h3 { margin-bottom: 4px; }
.landing .cosa p { color: var(--texto-2); font-size: 15.5px; line-height: 1.5; }
/* 🔴 Las dos tarjetas de la rejilla tienen que ocupar la MISMA caja o no alinean: la tira de la liga es
   mucho más baja que la sala, así que sin esto la rejilla estiraba «La liga» hasta el alto de «Tu casa» y le
   dejaba un socavón negro debajo del texto.
   ⚠️ Y LA PROPORCIÓN LA MANDA EL MOTOR, no la imagen (19-ago-2026). Aquí ponía `856 / 574`, que es lo que
   mide `sala.png` DESPUÉS del recorte al contenido que hace `hornea-landing.mjs`. Desde que «Tu casa» monta
   la habitación de verdad, esa caja es la de un lienzo cuyo mundo mide 300x242 fijos (`encuadre(6, 4)`), y
   ahí no hay margen para elegir: `habitacion.mjs` calcula el buffer él solo y `celdaDe()` traduce el clic
   con `canvas.width / rect.width`, o sea DANDO POR HECHO que el lienzo llena su caja estirado por igual.
   Con una caja de otra proporción solo hay dos finales, y los dos son malos: `width/height: 100%` deforma
   la sala, y un `object-fit` la centra o la recorta y entonces **cada clic cae en una casilla que no es la
   que tocaste** — sin un solo error, solo el bicho andando a donde no le has dicho. Cambiar la caja es lo
   barato; tocar la geometría del motor por una tarjeta de la landing, no.
   El póster sigue con `contain` y no `cover`: recortar la sala le cortaría muebles, que son exactamente lo
   que esa imagen tiene que enseñar. Al ser más ancho que la caja nueva, le quedan dos franjas finas arriba
   y abajo — justo el aire que el horneado le había quitado. */
.landing .cosa-img {
  margin: 0; display: grid; place-items: center; aspect-ratio: 300 / 242; overflow: hidden;
  background: #0d0d0f; border-bottom: 1px solid var(--borde);
}
.landing .cosa-img > img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* ── TU CASA, JUGABLE: el póster se aparta y debajo está el motor ──────────────────────────────────── */
/* Mismo reparto que el visor del hero: una imagen horneada encima, el lienzo vivo debajo, y una clase que
   pone el JS (`casa-viva`) cruza de una a otro. Si el motor no arranca, la clase no se pone y la tarjeta se
   queda como estaba: la información NUNCA depende de que el 3D llegue a montar. */
.landing .casa-visor { position: relative; }
.landing .casa-lienzo {
  position: absolute; inset: 0; display: block; width: 100%; height: 100%;
  opacity: 0; transition: opacity .35s ease;
}
.landing .casa-poster { transition: opacity .35s ease; }
.landing .casa-visor.casa-viva { cursor: pointer; }
.landing .casa-visor.casa-viva .casa-lienzo { opacity: 1; }
/* `visibility` además de `opacity`: el póster es un `<img>` a pantalla completa por encima del lienzo, y
   con solo `opacity: 0` seguiría comiéndose los clics de las casillas de arriba. */
.landing .casa-visor.casa-viva .casa-poster { opacity: 0; visibility: hidden; }
.landing .casa-pista {
  position: absolute; left: 50%; bottom: 12px; z-index: 2; transform: translateX(-50%);
  margin: 0; padding: 7px 13px; border-radius: 999px; white-space: nowrap; pointer-events: none;
  background: rgba(12, 12, 14, .82); border: 1px solid var(--borde);
  color: var(--texto-2); font-size: 13px;
  transition: opacity .3s ease;
}
.landing .casa-pista[hidden] { display: none; }
.landing .casa-pista.se-apaga { opacity: 0; }

/* EL DUELO. Los dos Nomms se apoyan en la MISMA línea de suelo (`align-items: flex-end` y el mismo alto
   de imagen), porque en cuanto uno flota el ojo deja de leer «pelea» y lee «dos recortes pegados». El
   `padding-bottom: 0` es a propósito: los pies tocan el borde inferior del recuadro y ése hace de suelo. */
.landing .duelo {
  position: relative; display: flex; align-items: flex-end; justify-content: center;
  padding: 22px 6px 0; overflow: hidden;
  background:
    radial-gradient(80% 70% at 50% 100%, rgba(255, 212, 0, .05), transparent 62%),
    #0d0d0f;
}
/* Se solapan un pelín (`margin-inline` negativo) porque con el hueco que dejaba `justify-content: center`
   el chispazo caía en tierra de nadie: se leía como una estrella decorativa ENTRE dos muñecos, no como un
   golpe. Y el defensor va más pequeño que el atacante: la morfología ya lo dice (horneado con `altura: 0,1`
   contra `altura: 1`), pero a 250 px la silueta sola no basta, y lo que tiene que entenderse de un vistazo
   es quién le está pegando a quién. */
.landing .duelo img { display: block; height: auto; margin-inline: -2.5%; }
.landing .duelo-a { width: min(46%, 260px); }
.landing .duelo-b { width: min(38%, 214px); }

/* El chispazo va ENCIMA de los dos, centrado en el punto donde se juntan. Se dibuja con el mismo idioma
   que el resto de la página (`stroke-dasharray` holgado y `stroke-dashoffset` a 0), y su estado de REPOSO
   es la estrella ya dibujada: con `prefers-reduced-motion` el impacto sigue ahí. */
.landing .chispazo {
  position: absolute; left: 50%; bottom: 40%; width: clamp(72px, 17%, 132px);
  transform: translate(-50%, 45%); pointer-events: none;
}
.landing .chispazo .estrella {
  fill: rgba(255, 212, 0, .12); stroke: var(--amarillo); stroke-width: 3.5;
  stroke-linejoin: round; stroke-dasharray: 640; stroke-dashoffset: 0;
}

/* ── LA LIGA: EL RANGO SE VE, Y SE VE A QUIÉN TE TOCA (rehecho el 19-ago-2026) ──────────────────── */
/* ⚠️ AQUÍ HABÍA CUATRO NOMMS EN ONDA, y el comentario que los defendía decía que el escalonado NO era
   una escalera «porque una escalera diría clasificación, y el pie de esta misma tarjeta dice justo lo
   contrario: nunca contra el número de nadie». Lo tumbó él mirándolo: «lo de la liga me gustaría que se
   viera mejor representado, o sea que se les vea como diferentes rangos encima de cada Nomms... y que se
   vea cómo van a luchar en base a ello» (19-ago-2026).
   Y el reparo viejo se disuelve leyendo bien su propia frase: «el número de nadie» son las VISTAS, los
   seguidores, el MRR (es lo que argumenta la comparativa dos secciones más arriba), no el nivel de tu
   propio Nomms. La liga sí tiene orden, y ocultarlo no la hacía más amable: la hacía muda.

   Lo que se pinta es NIVEL, y sale del código, no de la nada: `core/ligas.mjs` ordena la cohorte de la
   semana por `(nivel desc, actividad desc, nombre asc)`, y `core/arena.mjs` reparte rival con
   `nivelesAlrededor(n) → [n-1, n, n, n+1]`, o sea «algún rival por debajo, a tu talla, y algo por
   encima». Por eso la tira es 7 · 8 | 8 · 9 y por eso los pares son 7-8 y 8-9: es el emparejamiento
   real del juego, no una composición bonita. Inventar Bronce/Plata/Oro habría sido mentir: no existen.

   🚫 Y NADA DE NOMBRES `.par`, `.uno`, `.chip`: todo va con prefijo `liga-`. Tres bugs invisibles se han
   pagado ya en esta hoja por dos cosas distintas llamadas igual (`.sube`, `.marca`), y los caza
   `tests/landing-clases.test.mjs`. */

/* 🔴 MEDIDO EN LA BETA SERVIDA, no deducido: la tira ocupaba el 36% de su caja y el 64% restante era un
   agujero negro encima de los muñecos, con los pies del Nv 7 pegados al borde de abajo (1 px en
   escritorio y -1,5 px en movil, o sea CORTADOS). La causa es de aqui al lado: `.cosa-img` paso de
   856/574 a 300/242 para que el lienzo de la casa case EXACTO con el mundo (de eso depende que el clic
   caiga en la casilla que tocas), y esta tira comparte esa clase, asi que heredo una caja un 20% mas
   alta sin que nadie recompusiera lo de dentro. En una hoja de estilos eso no da ningun error.

   🚫 Y la salida NO es devolverle a la tira su propia `aspect-ratio`: las dos tarjetas son las dos
   columnas de la MISMA fila de `.rejilla-cosas`, asi que cajas de alto distinto dejan la fila coja. Se
   arregla lo que estaba mal de verdad, que es que la composicion no llenaba su caja. Es el mismo
   diagnostico que ya esta escrito para la Arena a dos columnas: «dos munecos pequenos perdidos en medio
   de un rectangulo negro enorme, que es justo lo contrario de darle bombo».

   Los numeros salen de medir el PNG, no de tantear: dentro de sus 340x340 el bicho solo pinta el 41-45%
   del ancho, o sea que hay ~28% de transparencia por lado y las figuras pueden solaparse MUCHO antes de
   tocarse. Con base 96% y -24% de margen a cada lado, el hueco que se llevan dos munecos en la fila es
   96-48 = 48% del par (caben los dos), pintan al 96% y entre bicho y bicho queda un 5% de aire. La
   imagen pasa de 127 a ~235 px de alto, o sea el 55% de la caja en vez del 30%.
   Y el grupo va CENTRADO (`align-items: center`), no pegado abajo: asi el aire que sobra se reparte
   arriba y abajo en vez de amontonarse entero encima, y los pies dejan de rozar el borde.
   El escalon de rango sigue siendo `margin-bottom` en `.liga-n7/8/9` y no se toca. */
.landing .tira-liga {
  display: flex; align-items: center; justify-content: center; gap: 4%;
  padding: 0 4px; overflow: hidden;
  background: radial-gradient(80% 62% at 50% 92%, rgba(255, 212, 0, .07), transparent 62%), #0d0d0f;
}
.landing .liga-par { position: relative; flex: 0 1 46%; display: flex; align-items: flex-end; justify-content: center; }
/* La altura de cada Nomms va por `margin-bottom` y NO por `transform`: el `transform` se lo queda entero
   la animación de embestida, y mezclar los dos obliga a repetir el desnivel dentro de cada fotograma
   (que es justo el bug que ya se pagó con el chispazo del duelo). */
.landing .liga-uno { position: relative; margin: 0 -24%; flex: 0 0 96%; }
.landing .liga-cara { display: block; width: 100%; height: auto; }
.landing .liga-n7 { margin-bottom: 0; }
.landing .liga-n8 { margin-bottom: 6%; }
.landing .liga-n9 { margin-bottom: 12%; }
.landing .liga-n7 .liga-cara { filter: brightness(.76); }
.landing .liga-n8 .liga-cara { filter: brightness(.9); }

/* La chapa de rango, ENCIMA de cada uno, que es literalmente lo que pidió. En reposo se ve entera y
   legible: nada de lo que dice depende de que la animación llegue a correr. */
.landing .liga-chip {
  position: absolute; top: 0; left: 50%; z-index: 2; transform: translateX(-50%);
  padding: 3px 7px; border-radius: 999px; white-space: nowrap;
  border: 1px solid var(--borde-vivo); background: rgba(10, 10, 11, .9);
  font: 700 clamp(9px, 1.5vw, 12px)/1.25 var(--sans); letter-spacing: .04em;
  color: var(--texto-2);
}
/* El de arriba de la escalera va en oro: el rango se lee de un vistazo aunque no llegues a leer la cifra. */
.landing .liga-n9 .liga-chip { color: var(--hueso); border-color: rgba(255, 212, 0, .5); }

/* 🔴 La altura NO se elige a ojo: a `bottom: 30%` el `vs` caia a la altura de las MANOS, que es lo mas
   ancho del muneco, y con el borde opaco medido a SU altura se metia -2,6 px dentro de las dos manos en
   reposo y -32 px en el pico de la embestida. La caja envolvente no lo delata (dice que hay 47 px de
   hueco): hay que medir el borde alfa EN LA FRANJA del `vs`. Perfil del hueco por altura, en reposo:
   20-25% da 75/54 px · 30% da 48/34 · 35% da 11,6/8,5 (el minimo, las manos) · 55-60% da 82/62.
   A 22% (entre las piernas) quedan 75 px de aire en escritorio y 55 en movil, y aun con la embestida
   encima no llega a tocar. */
/* El `vs` es lo que convierte cuatro muñecos en dos peleas. Va sobre el hueco entre los dos del par y
   aparece en el momento del choque, no antes: si estuviera fijo, sería una etiqueta; apareciendo, es el
   emparejamiento pasando. */
.landing .liga-vs {
  position: absolute; left: 50%; bottom: 22%; z-index: 3; transform: translate(-50%, 0);
  font: 800 clamp(9px, 1.4vw, 12px)/1 var(--sans); letter-spacing: .1em; text-transform: uppercase;
  color: var(--amarillo); text-shadow: 0 0 10px rgba(10, 10, 11, .95); pointer-events: none;
  opacity: .5;
}

/* Y ahora el movimiento, colgando de `.cosa.dentro` como el duelo de la Arena: arranca cuando la tarjeta
   entra en pantalla. Los dos pares NO van a la vez (el segundo entra 1,2 s tarde): a la vez se leen como
   un temblor de la tira entera, y escalonados se lee que son DOS combates distintos. */
/* ⚠️ Quien acomete se elige por POSICIÓN en el par (`:first-of-type` / `:last-of-type`), no por su clase
   de nivel: `.liga-par-b` TAMBIÉN lleva la clase `.liga-par`, así que un `.liga-par .liga-n8` cazaría los
   dos ochos a la vez (el de la derecha del primer par y el de la izquierda del segundo) y uno de ellos
   embestiría hacia fuera. Silencioso, válido y al revés. */
.landing .cosa.dentro .liga-par .liga-uno:first-of-type { animation: liga-acomete-dcha 3.6s cubic-bezier(.65, 0, .3, 1) .3s infinite both; }
.landing .cosa.dentro .liga-par .liga-uno:last-of-type { animation: liga-acomete-izq 3.6s cubic-bezier(.65, 0, .3, 1) .3s infinite both; }
.landing .cosa.dentro .liga-par .liga-vs { animation: liga-choque 3.6s ease-out .3s infinite both; }
/* Y el segundo par entra tarde. Las tres reglas repiten el `:first-of-type`/`:last-of-type` a propósito:
   con `.liga-par-b .liga-uno` a secas la especificidad quedaba POR DEBAJO del atajo de arriba y el
   `animation-delay` no llegaba a aplicarse nunca. */
.landing .cosa.dentro .liga-par-b .liga-uno:first-of-type,
.landing .cosa.dentro .liga-par-b .liga-uno:last-of-type,
.landing .cosa.dentro .liga-par-b .liga-vs { animation-delay: 1.5s; }

@keyframes liga-acomete-dcha {
  0%, 16%   { transform: translateX(0) rotate(0); }
  30%       { transform: translateX(10%) rotate(4deg); }
  46%, 100% { transform: translateX(0) rotate(0); }
}
@keyframes liga-acomete-izq {
  0%, 16%   { transform: translateX(0) rotate(0); }
  30%       { transform: translateX(-10%) rotate(-4deg); }
  46%, 100% { transform: translateX(0) rotate(0); }
}
@keyframes liga-choque {
  0%, 18%   { opacity: .5; transform: translate(-50%, 0) scale(.9); }
  30%       { opacity: 1; transform: translate(-50%, 0) scale(1.15); }
  46%, 100% { opacity: .5; transform: translate(-50%, 0) scale(.9); }
}

/* ── FAQ ─────────────────────────────────────────────────────────────────────────────────────────── */
.landing .faq { margin-top: 28px; border-top: 1px solid var(--borde); }
.landing .faq details { border-bottom: 1px solid var(--borde); }
.landing .faq summary {
  list-style: none; cursor: pointer;
  padding: 20px 30px 20px 0; position: relative;
  font-size: 17px; font-weight: 600; letter-spacing: -0.012em;
}
.landing .faq summary::-webkit-details-marker { display: none; }
.landing .faq summary::after {
  content: '+'; position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  color: var(--texto-3); font-size: 20px; font-weight: 400;
}
.landing .faq details[open] summary::after { content: '\2212'; }
.landing .faq details p { padding: 0 0 22px; color: var(--texto-2); max-width: 72ch; }

/* ── cierre ──────────────────────────────────────────────────────────────────────────────────────── */
.landing .cierre {
  margin-top: 84px; padding: 60px 26px;
  border: 1px solid var(--borde); border-radius: 24px;
  background:
    radial-gradient(90% 130% at 50% 0%, rgba(255, 212, 0, .09) 0%, rgba(255, 212, 0, 0) 60%),
    linear-gradient(180deg, var(--panel-alto), var(--panel));
  text-align: center;
}
.landing .cierre h2 { max-width: 16ch; margin-inline: auto; }
.landing .cierre .btn { margin-top: 28px; }
.landing .cierre .letra-chica { margin-top: 16px; }

/* ── pie ─────────────────────────────────────────────────────────────────────────────────────────── */
/* Tres columnas `1fr auto 1fr` y no un flex con `space-between`, porque el copyright tiene que quedar
   CENTRADO respecto a la página, no a lo que le dejen libre los vecinos: con `space-between` su posición
   la dictaría el ancho de la firma y el de los legales, así que se movería sola cada vez que se toque una
   palabra de cualquiera de los dos. Con `1fr auto 1fr` las dos columnas de los lados valen lo mismo por
   construcción y el centro es el centro de verdad. */
.landing .pie {
  max-width: 1120px; margin: 60px auto 0; padding: 26px 18px 46px;
  border-top: 1px solid var(--borde);
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px 22px;
  color: var(--texto-3); font-size: 14px;
}
.landing .pie-copy { text-align: center; }
.landing .pie-legal { text-align: right; }
/* Por debajo del ancho de una fila cabe la firma y poco más, así que se apilan y se centran los tres:
   una firma pegada a la izquierda con un copyright centrado debajo lee como un desajuste, no como orden. */
@media (max-width: 720px) {
  .landing .pie { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .landing .pie-legal { text-align: center; }
}
.landing .pie p { margin: 0; }
.landing .pie a { color: var(--texto-2); text-decoration: none; }
.landing .pie a:hover { color: var(--texto); text-decoration: underline; text-underline-offset: 3px; }
.landing .pie-firma { color: var(--texto-2); }
/* El corazón late al pasar por encima, y solo entonces: un latido perpetuo en el pie es un tic nervioso
   en el rabillo del ojo durante toda la lectura. `hover: hover` lo deja fuera del móvil, donde no hay
   puntero y quedaría congelado a medio latido. Lo apaga `prefers-reduced-motion` al final del fichero. */
/* el `inline-block` le da al emoji su caja completa, que es lo que necesita para escalar al latir.
   ⚠️ Llevaba un `margin-right: -0.28em` para apretarlo contra los dos puntos que había antes; al pasar a
   «Con ❤ por Iñaki» ese tirón se come el espacio de la palabra y queda «❤por». Se retira con ellos. */
.landing .corazon { display: inline-block; }
@media (hover: hover) {
  .landing .pie-firma:hover .corazon { animation: latido 900ms ease-in-out infinite; }
}
@keyframes latido {
  0%, 100% { transform: scale(1); }
  18% { transform: scale(1.3); }
  36% { transform: scale(1); }
  54% { transform: scale(1.15); }
  72% { transform: scale(1); }
}

/* ── el asomo ────────────────────────────────────────────────────────────────────────────────────── */
/* Cada bloque entra desde abajo la primera vez que se ve, y se queda. Iñaki, 18-ago-2026: «faltan
   animaciones, faltan cosas chulas, que hagan que sea divertido ver la página».
   ⚠️ EL CANDADO ESTÁ EN `body.con-revelado`, y no es una precaución de manual: si `.revela` escondiera
   por sí sola, un `landing.mjs` que no cargue (error de red, navegador viejo, un `import` roto) dejaría la
   portada ENTERA en blanco, sin un error visible y sin nada que mirar. La clase la pone el JS en cuanto
   arranca, así que esconder solo es posible si alguien puede volver a enseñarlo. */
.landing.con-revelado .revela {
  opacity: 0; transform: translateY(16px);
  transition: opacity 620ms ease, transform 620ms cubic-bezier(.22, 1, .36, 1);
}
.landing.con-revelado .revela.dentro { opacity: 1; transform: none; }
/* Escalonado dentro de una rejilla: las tarjetas no entran las tres a la vez, entran en cascada. Es la
   diferencia entre «aparece un bloque» y «se está montando algo». */
.landing.con-revelado .revela:nth-child(2) { transition-delay: 90ms; }
.landing.con-revelado .revela:nth-child(3) { transition-delay: 180ms; }
.landing.con-revelado .revela:nth-child(4) { transition-delay: 270ms; }

/* ── de tablet para arriba ───────────────────────────────────────────────────────────────────────── */
@media (min-width: 720px) {
  .landing .modos { grid-template-columns: 1fr 1fr; }
  /* 🔴 Aquí estaban las tres viñetas EN FILA, cada una con su texto debajo. Iñaki, 19-ago: «las
     animaciones me gustan mucho; lo que no me gusta es cómo está distribuido el texto y las
     animaciones. Tendría que ser una lista de 1, 2, 3 pero que la explicación esté al lado de cada
     animación». Ofreció «o en vez de eso, que la explicación esté debajo» como alternativa, y ésa
     es DESCARTABLE por evidencia y no a cara o cruz: debajo es exactamente lo que ya había, y de eso
     dijo «no me acaba de convencer, sinceramente, como está hecho ahora mismo». Así que gana al lado.
     La escena se queda en su ancho de diseño con un `clamp`, no con un %: a 1.180 px un 38% suelto la
     estiraría a 428 px y el Nomms de la viñeta 3 (anclado a la derecha, 158 px) se quedaría solo en
     medio del rectángulo. El paquete de la tercera sigue viajando en px fijos por lo mismo de antes:
     lo que cambia con el ancho es el hueco de en medio, no dónde empieza ni dónde acaba. */
  .landing .paso {
    grid-template-columns: minmax(0, clamp(240px, 38%, 360px)) minmax(0, 1fr);
    gap: 22px; padding: 14px;
  }
  .landing .paso h3 { font-size: 19px; }
  .landing .paso p { max-width: 34em; }
  .landing .dolores { grid-template-columns: repeat(3, 1fr); }
  /* Tantas columnas como tarjetas: con una de más, la última columna queda VACÍA y en escritorio se ve
     un rectángulo negro a la derecha (pasó con `repeat(4, 1fr)` y tres tarjetas, y está fotografiado en
     `docs/capturas/landing-v7/05-dentro.png`). Hoy son DOS, porque la Arena se salió de la rejilla para
     ocupar su propia fila. Si vuelve a haber otra cosa aquí, este número sube con ella. */
  .landing .rejilla-cosas { grid-template-columns: repeat(2, 1fr); }
  /* La Arena, a dos columnas. A ancho completo la escena eran dos muñecos pequeños perdidos en medio de un
     rectángulo negro enorme, que es justo lo contrario de darle bombo. Aquí la pelea ocupa dos tercios y el
     texto se sienta a su lado con más cuerpo que el de las otras dos tarjetas, y eso es lo que la pone por
     encima de ellas sin escribir ni una palabra más. */
  .landing .cosa-ancha { display: grid; grid-template-columns: 1.3fr .7fr; align-items: center; }
  .landing .cosa-ancha .duelo { height: 100%; border-right: 1px solid var(--borde); }
  .landing .cosa-ancha .cosa-pie { padding: 28px 34px; }
  .landing .cosa-ancha h3 { font-size: 27px; }
  .landing .cosa-ancha p { font-size: 17px; }
  .landing .bloque { padding-top: 96px; }
}
@media (min-width: 980px) {
  .landing .hero { grid-template-columns: 1.05fr .95fr; gap: 56px; padding: 76px 0 24px; }
  .landing .visor { max-width: 500px; }
}

/* ── el duelo en movimiento: EN BUCLE Y PEGANDO LOS DOS (R16 · rehecho el 19-ago-2026) ──────────── */
/* Cuelga de `.cosa.dentro`, la clase que pone el IntersectionObserver: la pelea arranca cuando la tarjeta
   entra en pantalla, no al cargar.

   ⚠️ AQUÍ PONÍA `2` PASADAS, defendido con un «un bucle infinito en una landing es un tic nervioso». Lo
   tumbó él mirándolo: «la animación del golpe de la arena está muy chula, pero me gustaría que se fuera
   repitiendo, no que se vea una vez y ya luego se quede estática como en una imagen... porque mola mucho»
   (19-ago-2026). Y tenía razón de fondo, no solo de gusto: la tarjeta se llama La Arena y lo que promete
   es que ahí dentro se pelea. Dos muñecos congelados a medio metro prometen justo lo contrario.

   ⚠️ Y AHORA PEGAN LOS DOS. El `encaja` de antes solo movía al azul HACIA ATRÁS, o sea que el azul era un
   saco y no un rival: «y que el azul también pegue, que no solo pegue el rojo, que se vayan pegando
   mutuamente». Así que el ciclo son DOS golpes con sus dos retrocesos.

   El ciclo dura 3,6 s y buena parte es AIRE (0-8% y 74-100% quietos, más el hueco de 36-46% entre los dos
   golpes). Sin esas pausas un bucle de puñetazos no se lee como un intercambio, se lee como un temblor: lo
   que hace que se entienda quién pega y quién encaja es el silencio de en medio, no la velocidad.

   ⚠️ `both` se queda por el `delay`: sin él, entre el retardo y el primer fotograma el chispazo se vería a
   tamaño final antes de que empiece el golpe, o sea el impacto ANTES del puñetazo. */
.landing .cosa.dentro .duelo-a { animation: duelo-coral 3.6s cubic-bezier(.65, 0, .3, 1) .25s infinite both; }
.landing .cosa.dentro .duelo-b { animation: duelo-azul 3.6s cubic-bezier(.65, 0, .3, 1) .25s infinite both; }
.landing .cosa.dentro .chispazo { animation: chispea 3.6s ease-out .25s infinite both; }

/* El coral pega primero (pico en 16%) y encaja la devolución en 60%; el azul es el espejo, desfasado medio
   ciclo. Los picos NUNCA coinciden a propósito: dos muñecos avanzando a la vez se leen como un choque de
   trenes, no como una pelea. */
@keyframes duelo-coral {
  0%, 8%    { transform: translateX(0) rotate(0); }
  16%       { transform: translateX(13%) rotate(3deg); }    /* pega */
  28%, 52%  { transform: translateX(0) rotate(0); }
  60%       { transform: translateX(-9%) rotate(-6deg); }   /* la encaja */
  74%, 100% { transform: translateX(0) rotate(0); }
}
@keyframes duelo-azul {
  0%, 14%   { transform: translateX(0) rotate(0); }
  22%       { transform: translateX(11%) rotate(8deg); }    /* la encaja */
  36%, 46%  { transform: translateX(0) rotate(0); }
  56%       { transform: translateX(-15%) rotate(-4deg); }  /* pega */
  70%, 100% { transform: translateX(0) rotate(0); }
}
/* El `translate(…, 45%)` se repite en CADA fotograma a propósito: es lo que coloca el chispazo, y una sola
   `transform` sin él lo mandaría a la esquina en cuanto arrancara la animación.
   Y la X ya no es siempre `-50%`: el destello se corre HACIA EL QUE RECIBE (`-34%` cae sobre el azul,
   `-66%` sobre el coral). Centrado siempre, los dos golpes se veían idénticos y no se sabía quién había
   pegado a quién; corriéndolo, el impacto señala al que lo encaja sin una sola palabra. */
@keyframes chispea {
  0%, 12%  { opacity: 0; transform: translate(-50%, 45%) scale(.25); }
  18%      { opacity: 1; transform: translate(-34%, 45%) scale(1.18); }
  30%      { opacity: 0; transform: translate(-34%, 45%) scale(.85); }
  50%      { opacity: 0; transform: translate(-66%, 45%) scale(.25); }
  58%      { opacity: 1; transform: translate(-66%, 45%) scale(1.18); }
  70%      { opacity: 0; transform: translate(-66%, 45%) scale(.85); }
  100%     { opacity: 0; transform: translate(-50%, 45%) scale(.25); }
}

/* ── el cierre (R21) ─────────────────────────────────────────────────────────────────────────────── */
.landing .cierre-arte {
  position: relative; width: min(220px, 58vw); margin: 0 auto 6px; aspect-ratio: 1;
  display: grid; place-items: center;
}
.landing .cierre-arte img { display: block; width: 78%; height: auto; }
.landing .cierre-aro { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.landing .cierre-aro circle { fill: none; stroke-width: 7; stroke-linecap: round; transform-origin: 50% 50%; }
.landing .cierre-aro .pista { stroke: rgba(255, 255, 255, .07); }
/* 578 es el perímetro largo (2πr con r=92 son 578,05): el `dasharray` se pone al perímetro ENTERO y el
   offset dice cuánto falta. En reposo queda a ~3/4, que es lo que dice «esto va por aquí», no «esto está
   terminado»: un aro lleno del todo en la última pantalla contaría lo contrario de lo que vende la página. */
.landing .cierre-aro .lleno {
  stroke: var(--amarillo); stroke-dasharray: 578; stroke-dashoffset: 144; rotate: -90deg;
}
.landing .cierre.dentro .cierre-aro .lleno { animation: llena-aro 1.5s cubic-bezier(.3, 0, .2, 1) .3s both; }
/* Iñaki, 19-ago-2026: «abajo del todo me gustaría que el Nomms tuviera una animación, el Nomms que hay
   dentro de esa especie de barra que entiendo que es como la experiencia; que se vea, no sé, saltando y
   saludando o algo así, rollo para que se vea gracioso ahí dentro, para que tengas ganas de darle a
   crear mi Nomms». Es el último bicho antes del botón: si ahí está quieto, el botón pide algo que la
   página acaba de enseñar inmóvil.
   ⚠️ SON DOS ANIMACIONES EN CADENA SOBRE LA MISMA PROPIEDAD, y el orden es lo que las hace convivir:
   cuando dos animaciones tocan `transform` a la vez, manda **la última de la lista**. `asoma-nomms`
   lleva `both`, así que sigue «activa» rellenando para siempre después de acabar (a 1,25 s) — si el
   salto fuese antes en la lista, no se vería moverse ni un píxel. Y al revés no molesta: hasta que no
   pasa su retardo (1,3 s) el salto no aplica nada, porque no tiene `fill`, así que el asomo entra
   limpio. El hueco de 50 ms entre las dos es a propósito, y las dos valen `transform: none` ahí.
   ⚠️ El origen baja a los pies (`50% 92%`): un aplastado con el origen en el centro hunde al bicho en
   vez de posarlo, y el ladeo del saludo pivota desde la barriga en vez de desde el suelo. */
.landing .cierre.dentro .cierre-arte img {
  transform-origin: 50% 92%;
  animation: asoma-nomms 1.1s cubic-bezier(.2, .8, .3, 1) .15s both,
             salta-y-saluda 2800ms ease-in-out 1.3s infinite;
}
/* 🔴 EL REPOSO ES EL ESTADO BUENO: el 0% y el 100% son `transform: none`, o sea el Nomms de pie y
   quieto. Dos tercios de la vuelta no pasa nada — el gesto tiene que leerse como un saludo puntual,
   no como un bicho nervioso. Y ni una `steps()`, como en toda esta hoja. */
@keyframes salta-y-saluda {
  0%, 30%   { transform: none; }
  36%       { transform: translateY(2px) scaleX(1.07) scaleY(.94); }   /* flexiona antes de saltar */
  44%       { transform: translateY(-15px) scaleX(.96) scaleY(1.05); }
  52%       { transform: translateY(-18px) rotate(-8deg); }            /* arriba, se ladea */
  60%       { transform: translateY(-18px) rotate(8deg); }             /* el saludo */
  67%       { transform: translateY(-12px) rotate(-4deg); }
  75%       { transform: translateY(0) scaleX(1.08) scaleY(.92); }     /* aterriza y se aplasta */
  83%       { transform: translateY(-5px) scaleX(.99) scaleY(1.02); }  /* el rebote */
  91%, 100% { transform: none; }
}
@keyframes llena-aro {
  from { stroke-dashoffset: 578; }
  to   { stroke-dashoffset: 144; }
}
@keyframes asoma-nomms {
  from { opacity: 0; transform: translateY(14px) scale(.94); }
  to   { opacity: 1; transform: none; }
}

/* Quien pide menos movimiento no recibe ninguno: el motor 3D no se monta solo (ver `landing.mjs`), y aquí
   además se apagan las transiciones. La portada sigue COMPLETA, porque nada de lo que cuenta depende de
   que algo se mueva. */
@media (prefers-reduced-motion: reduce) {
  body.landing *, body.landing *::before, body.landing *::after {
    animation: none !important;
    transition: none !important;
  }
  /* 🔴 Y ESTO NO ES OPCIONAL: apagar la transición sin devolver el estado final deja `.revela` en
     `opacity: 0` PARA SIEMPRE. O sea, la portada en blanco para quien pidió menos movimiento, que es
     justo a quien más caro le sale. Aquí se ve todo, de golpe y quieto, que es lo que pidió. */
  .landing.con-revelado .revela { opacity: 1 !important; transform: none !important; }
}
