/* ══════════════════════════════════════════════════════════════════════
   LYQUIA — lyquia.com
   Un solo CSS para todo el sitio. Tema oscuro único: la paleta viva de
   lyquia.com (navy profundo + cian), intocable — está fichada en
   _fuente/vivo/inventario.md.

   Dos reglas de disciplina, heredadas de la casa (DEVIA):

   1 · LOS COLORES NO SE ESCRIBEN EN LOS COMPONENTES. Cada superficie
       redefine --texto, --texto-suave, --acento, --acento-vivo y
       --filete; todo lo de dentro hereda. Añadir un componente no
       obliga a pensar sobre qué fondo va a caer.

   2 · EL RITMO VERTICAL VIVE EN UN ÚNICO SITIO: .seccion. Ningún
       componente lleva margen exterior propio.

   La elevación en oscuro no son sombras negras (sobre #080f1f no se
   ven): es superficie un paso más clara + brillo superior de 1px
   (--alza) y, solo en los momentos de marca, el halo cian (--glow).

   TESIS DE MOVIMIENTO — escrita antes de animar nada:
   Lyquia vende liquidez; el movimiento de la casa es EL FLUIR. Todo
   entra como agua que se asienta: fundidos y desplazamientos cortos
   hacia arriba, ninguna salida, ningún rebote. El único dibujo animado
   del sitio es la propia curva de caja, que se traza en el héroe y se
   rompe — y reaparece plana y sobre cero en el cierre. El scroll trae
   contenido, nunca lo quita. Movimiento reducido no es apagado nuclear
   sino «menos y más suave»: muere el desplazamiento, sobreviven el
   color y la opacidad que confirman acciones.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Tokens ──────────────────────────────────────────────────────────── */

:root {
  /* Paleta viva de lyquia.com — NO tocar */
  --bg: #080f1f;
  --navy: #0c1e3a;
  --card: #0e1c33;
  --cyan: #28cabe;
  --cyan-l: #8bf1e6;
  --txt: #e8eef7;
  --mut: #8fa3bd;
  --linea: rgba(255, 255, 255, 0.08);

  /* Derivados (contraste medido sobre lo pintado, ver auditar.js)
     --txt/--bg 16,4:1 · --mut/--bg 7,4:1 · --mut/--card 6,6:1 ·
     --mut/--card-alta 6,1:1 · --cyan/--bg 9,4:1 · tinta sobre cian 9,4:1.
     No inventar más grises: si algo pide menos presencia que --mut,
     se baja el tamaño o se sube el aire, no el contraste. */
  --card-alta: #13233f;
  --linea-fuerte: rgba(255, 255, 255, 0.14);
  --linea-cyan: rgba(40, 202, 190, 0.35);
  --tinta-boton: #080f1f;
  --rojo-cursor: #f27e6b; /* el coral del producto: lo que reclama atención */
  --glow: 0 0 60px rgba(40, 202, 190, 0.14);
  --alza: inset 0 1px 0 rgba(255, 255, 255, 0.05);

  /* Tipografías (autoalojadas en assets/tipos/) */
  --letra-cuerpo: 'Montserrat', 'Montserrat de reserva', -apple-system, 'Segoe UI', sans-serif;
  --letra-titular: 'Libre Baskerville', 'Libre Baskerville de reserva', Georgia, 'Times New Roman', serif;
  --letra-cifra: 'Geist Mono', ui-monospace, 'Cascadia Mono', monospace;

  /* Movimiento — tokens de la marca (lyquia-app/globals.css) más los
     dos propios de esta web. --ease-revelar es la curva de la
     referencia (oakandgrid.com), calcada de su .reveal. */
  --ease-asentar: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-suave: cubic-bezier(0.33, 0.1, 0.25, 1);
  --ease-revelar: cubic-bezier(0.22, 1, 0.36, 1);
  --dur-toque: 120ms;
  --dur-cerca: 220ms;
  --dur-panel: 340ms;
  --dur-vista: 420ms;
  --dur-focal: 650ms;
  --dur-trazo: 1400ms;

  /* Maqueta */
  --wrap: 1200px;
  --radio-s: 8px;
  --radio: 14px;
  --radio-l: 20px;

  color-scheme: dark;
}

/* ── Reset corto y base ─────────────────────────────────────────────── */

*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* La barra fija no debe tapar el destino de las anclas. */
  scroll-padding-top: 92px;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--letra-cuerpo);
  font-weight: 300;
  font-size: 1.0625rem;
  line-height: 1.7;
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;

  /* Superficie raíz: la mesa. Los componentes solo usan estas cinco. */
  --texto: var(--txt);
  --texto-suave: var(--mut);
  --acento: var(--cyan);
  --acento-vivo: var(--cyan-l);
  --filete: var(--linea);
  color: var(--texto);
}

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

a {
  color: inherit;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

ul,
ol {
  list-style: none;
}

/* Superficies del navegador, tematizadas: la casa llega hasta el caret. */
::selection {
  background: var(--cyan);
  color: var(--tinta-boton);
}

html {
  caret-color: var(--cyan);
  scrollbar-color: #22375c var(--bg);
}

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

/* ── El cursor: punto exacto y anillo que llega tarde ──────────────────
   El punto va clavado donde está el ratón; el anillo lo persigue con
   inercia y se cierra sobre él al pasar sobre algo pulsable. Existe
   solo si lo enciende lyquia.js (html.con-cursor), que a su vez solo lo
   hace con ratón fino y sin movimiento reducido: nadie pierde su cursor
   del sistema por culpa de una decoración. Sobre campos de texto vuelve
   el cursor de siempre, porque ahí la forma del puntero es información
   (dónde se va a escribir), no adorno. */

html.con-cursor,
html.con-cursor a,
html.con-cursor button,
html.con-cursor summary,
html.con-cursor [data-plegable],
html.con-cursor .plan[data-sitio]:not([data-sitio='centro']) {
  cursor: none;
}

html.con-cursor input,
html.con-cursor textarea,
html.con-cursor [contenteditable] {
  cursor: auto;
}

.cursor-punto,
.cursor-anillo {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  pointer-events: none;
  border-radius: 50%;
  opacity: 0;
  /* La POSICIÓN la escribe lyquia.js en `translate`, no en `transform`:
     así `transform` queda libre para la vibración, y las dos cosas se
     componen en vez de pisarse (translate se aplica antes). */
  will-change: translate;
  transition: opacity var(--dur-cerca) var(--ease-suave);
}

html.cursor-dentro .cursor-punto,
html.cursor-dentro .cursor-anillo {
  opacity: 1;
}

/* Sobre un campo de texto manda el cursor del sistema: el nuestro se
   aparta en vez de estorbar. */
html.cursor-escribiendo .cursor-punto,
html.cursor-escribiendo .cursor-anillo {
  opacity: 0;
}

.cursor-punto {
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  background: var(--cyan-l);
}

.cursor-anillo {
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 1px solid var(--cyan);
  transition:
    opacity var(--dur-cerca) var(--ease-suave),
    width var(--dur-cerca) var(--ease-asentar),
    height var(--dur-cerca) var(--ease-asentar),
    margin var(--dur-cerca) var(--ease-asentar),
    background-color var(--dur-cerca) var(--ease-suave),
    border-color var(--dur-cerca) var(--ease-suave);
}

/* Sobre lo pulsable el anillo se cierra sobre el punto, los dos se
   tiñen de rojo y el anillo vibra: el puntero avisa de que ahí hay algo
   que responde antes incluso de leer el elemento. El rojo es el mismo
   coral que el producto usa para lo que reclama atención, no un color
   nuevo. */
html.cursor-sobre-accion .cursor-punto {
  background: var(--rojo-cursor);
}

html.cursor-sobre-accion .cursor-anillo {
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  background: rgba(242, 126, 107, 0.16);
  border-color: var(--rojo-cursor);
  animation: vibrar 150ms steps(4, end) infinite;
}

/* Un pelo de temblor, no un terremoto: ±1px basta para que se note en
   un anillo de 16. */
@keyframes vibrar {
  0% { transform: translate(0.6px, -0.6px); }
  25% { transform: translate(-0.6px, 0.6px); }
  50% { transform: translate(-0.6px, -0.6px); }
  75% { transform: translate(0.6px, 0.6px); }
  100% { transform: translate(0.6px, -0.6px); }
}

/* ── Atmósfera ──────────────────────────────────────────────────────────
   Grano feTurbulence en velo fijo sin eventos: convierte el navy digital
   en un material y mata el banding de los degradados. Data-URI: cero
   peticiones. Receta de la casa. */

body::after {
  content: '';
  position: fixed;
  inset: 0;
  /* Por encima de todo, portada (120) y barra (100) incluidas: el
     grano es el material de la casa, no un adorno del fondo. */
  z-index: 130;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* El velo del héroe: un amanecer cian muy tenue tras la composición. */
.heroe {
  background:
    radial-gradient(60% 50% at 50% -10%, rgba(40, 202, 190, 0.08), transparent 70%),
    radial-gradient(90% 60% at 50% -20%, rgba(22, 41, 77, 0.9), transparent 65%);
}

/* ── Tipografías ────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Montserrat';
  font-weight: 300;
  font-style: normal;
  font-display: swap;
  src: url('../tipos/montserrat-300.woff2') format('woff2');
}

@font-face {
  font-family: 'Montserrat';
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url('../tipos/montserrat-400.woff2') format('woff2');
}

@font-face {
  font-family: 'Montserrat';
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  src: url('../tipos/montserrat-500.woff2') format('woff2');
}

@font-face {
  font-family: 'Libre Baskerville';
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url('../tipos/baskerville-400.woff2') format('woff2');
}

@font-face {
  font-family: 'Libre Baskerville';
  font-weight: 400;
  font-style: italic;
  font-display: swap;
  src: url('../tipos/baskerville-400i.woff2') format('woff2');
}

@font-face {
  font-family: 'Geist Mono';
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url('../tipos/geistmono-400.woff2') format('woff2');
}

/* ── Tipografías de reserva ───────────────────────────────────────────
   Mientras llegan las de la casa, el navegador pinta con Georgia y con
   Arial y vuelve a pintar al llegar las buenas. Si no miden lo mismo, la
   página salta: 0,109 de CLS medido en una primera visita de escritorio,
   que antes no contaba porque el héroe estaba a opacidad 0 y ahora está
   pintado bajo la cubierta desde el primer pintado. Estas dos caras
   apuntan a la fuente local y la estiran (size-adjust y los tres
   override) hasta que ocupa exactamente lo mismo que la de la casa, así
   que el cambio de letra no mueve nada. Los números los calcula
   _fuente/tipos-de-reserva.mjs desde los .woff2 que sirve la web; no
   se retocan a mano. */
@font-face {
  font-family: 'Libre Baskerville de reserva';
  src: local('Georgia');
  size-adjust: 115.31%;
  ascent-override: 84.12%;
  descent-override: 23.41%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Montserrat de reserva';
  src: local('Arial');
  size-adjust: 108.83%;
  ascent-override: 88.95%;
  descent-override: 23.06%;
  line-gap-override: 0%;
}

/* ── Escala tipográfica ─────────────────────────────────────────────── */

h1,
h2 {
  font-family: var(--letra-titular);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.01em;
  text-wrap: balance;
  color: var(--texto);
}

h1 {
  font-size: clamp(2.5rem, 1.2rem + 4.8vw, 4.5rem);
  line-height: 1.08;
}

h1 em,
.acento-serif {
  font-style: italic;
  color: var(--acento-vivo);
}

h2 {
  font-size: clamp(1.9rem, 1.2rem + 2.6vw, 3rem);
}

h3 {
  font-family: var(--letra-cuerpo);
  font-weight: 500;
  font-size: 1.125rem;
  line-height: 1.35;
  letter-spacing: -0.005em;
  color: var(--texto);
  text-wrap: balance;
}

p {
  color: var(--texto-suave);
}

p strong,
li strong {
  font-weight: 500;
  color: var(--texto);
}

/* El único antetítulo del sitio vive en el héroe de portada. */
.kicker {
  display: block;
  font-weight: 500;
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--acento);
}

/* Cifras y numeración editorial: siempre en mono, siempre tabulares. */
.cifra,
.numero {
  font-family: var(--letra-cifra);
  font-variant-numeric: tabular-nums;
}

.numero {
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  color: var(--texto-suave);
}

.micro {
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--texto-suave);
}

/* ── Maqueta ────────────────────────────────────────────────────────── */

.wrap {
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 2.5rem);
}

/* Único dueño del ritmo vertical. El silencio es parte del diseño. */
.seccion {
  padding-block: clamp(4.75rem, 3.2rem + 5.2vw, 8.75rem);
}

.seccion + .seccion {
  border-top: 1px solid var(--filete);
}

/* Cabecera de sección: editorial, a la izquierda, titular que carga solo. */
.cabecera-seccion {
  max-width: 46rem;
  margin-bottom: clamp(2.75rem, 2rem + 3vw, 4.5rem);
}

.cabecera-seccion .entradilla {
  margin-top: 1.25rem;
  max-width: 38rem;
}

/* Salto accesible: invisible hasta que el teclado lo pide. */
.saltar {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--card-alta);
  color: var(--texto);
  border-radius: var(--radio-s);
  text-decoration: none;
}

.saltar:focus-visible {
  left: 1rem;
  top: 1rem;
}

/* ── Botones ────────────────────────────────────────────────────────── */

.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.8rem 1.65rem;
  border-radius: var(--radio-s);
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: 0.01em;
  text-decoration: none;
  transition:
    background-color var(--dur-cerca) var(--ease-suave),
    border-color var(--dur-cerca) var(--ease-suave),
    color var(--dur-cerca) var(--ease-suave);
}

.boton-primario {
  background: var(--acento);
  color: var(--tinta-boton);
}

.boton-primario:hover {
  background: var(--acento-vivo);
}

.boton-fantasma {
  border: 1px solid var(--linea-fuerte);
  color: var(--texto);
}

.boton-fantasma:hover {
  border-color: var(--linea-cyan);
  color: var(--acento-vivo);
}

/* Enlaces de texto: se tiñen, sin moverse. */
.enlace {
  color: var(--acento-vivo);
  text-decoration: underline;
  text-decoration-color: var(--linea-cyan);
  text-underline-offset: 0.2em;
  transition:
    color var(--dur-cerca) var(--ease-suave),
    text-decoration-color var(--dur-cerca) var(--ease-suave);
}

.enlace:hover {
  text-decoration-color: currentColor;
}

/* ── La barra ───────────────────────────────────────────────────────────
   Fija y transparente al nacer; a unos píxeles de scroll (sentinel de
   IntersectionObserver, cero listeners) se asienta: fondo, velo y
   hairline. */

/* El sentinel del que depende .con-fondo: 1px en lo alto del documento. */
#sentinel-barra {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
}

.barra {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  transition:
    background-color var(--dur-panel) var(--ease-suave),
    border-color var(--dur-panel) var(--ease-suave),
    backdrop-filter var(--dur-panel) var(--ease-suave);
}

.barra.con-fondo {
  background: rgba(8, 15, 31, 0.72);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom-color: var(--filete);
}

.barra-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 68px;
}

.marca {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  text-decoration: none;
}

.marca img {
  width: 28px;
  height: 28px;
}

/* El logotipo es el del producto, trazado del brandbook: la misma
   geometria que pinta la aplicacion (`lib/brand/palabra.ts`). Va en
   linea y con `currentColor` para heredar el color del texto que lo
   rodea, que es lo que la web pedia y un fichero externo no da.

   El alto que se le pone es el de la CAJA, no el de la mayuscula: la L
   ocupa 607,2 de los 757,3 que mide la caja, y por debajo solo bajan la
   y y la q. La proporcion con la baldosa es la del producto —mayuscula
   de 0,43 de su lado—, asi que a baldosa de 28 px le toca mayuscula de
   12, o sea 15 px de caja. */
.marca .logotipo {
  height: 15px;
  width: auto;
  color: var(--texto);
}

.barra nav {
  display: flex;
  align-items: center;
  gap: 1.9rem;
}

.barra nav a:not(.boton) {
  font-weight: 400;
  font-size: 0.9rem;
  text-decoration: none;
  color: var(--texto-suave);
  transition: color var(--dur-cerca) var(--ease-suave);
}

.barra nav a:not(.boton):hover,
.barra nav a:not(.boton):focus-visible {
  color: var(--acento-vivo);
}

.barra .boton {
  padding: 0.55rem 1.15rem;
  font-size: 0.875rem;
}

/* El menú en móvil: la barra entera despliega su lista. */
.menu-boton {
  display: none;
  width: 44px;
  height: 44px;
  border-radius: var(--radio-s);
  place-items: center;
}

.menu-boton svg {
  width: 22px;
  height: 22px;
  stroke: var(--texto);
  stroke-width: 1.6;
  fill: none;
}

.menu-boton .cerrar {
  display: none;
}

@media (max-width: 880px) {
  .menu-boton {
    display: grid;
  }

  .barra nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.5rem clamp(1.25rem, 4vw, 2.5rem) 1.5rem;
    background: rgba(8, 15, 31, 0.96);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--filete);
  }

  .barra[data-abierto='si'] nav {
    display: flex;
  }

  .barra[data-abierto='si'] {
    background: rgba(8, 15, 31, 0.96);
    border-bottom-color: var(--filete);
  }

  .barra[data-abierto='si'] .menu-boton .abrir {
    display: none;
  }

  .barra[data-abierto='si'] .menu-boton .cerrar {
    display: block;
  }

  .barra nav a:not(.boton) {
    padding: 0.9rem 0;
    font-size: 1rem;
    border-bottom: 1px solid var(--filete);
  }

  .barra nav .boton {
    margin-top: 1.1rem;
    justify-content: center;
  }
}

/* ── El héroe ───────────────────────────────────────────────────────── */

.heroe {
  padding-top: clamp(9rem, 7rem + 6vw, 12.5rem);
  padding-bottom: clamp(4rem, 3rem + 3vw, 6rem);
  text-align: center;
}

.heroe h1 {
  max-width: 24ch;
  margin: 1.4rem auto 0;
}

.heroe .entradilla {
  max-width: 36rem;
  margin: 1.6rem auto 0;
  font-size: 1.125rem;
}

.heroe .cta {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin-top: 2.4rem;
}

.heroe .fiabilidad {
  margin-top: 1.4rem;
}

/* La curva que se rompe: el momento firma. Decorativa (aria-hidden),
   sin cifras inventadas; solo la forma del problema que Lyquia detecta.
   Nace completa y quieta; el bloque MOVIMIENTO la traza si puede. */
.curva-caja {
  position: relative;
  margin-top: clamp(2.5rem, 2rem + 2vw, 4rem);
}

.curva-caja svg {
  display: block;
  width: 100%;
  height: clamp(90px, 12vw, 150px);
}

.curva-caja .linea {
  stroke: var(--acento);
  stroke-width: 2;
  fill: none;
  opacity: 0.55;
}

.curva-caja .cero {
  stroke: var(--texto-suave);
  stroke-width: 1;
  stroke-dasharray: 3 6;
  opacity: 0.3;
}

/* El marcador de la rotura es HTML sobre el SVG: el dibujo se estira
   con la ventana (preserveAspectRatio none) y un texto o un círculo
   dentro se deformarían. El punto cae donde la curva cruza el cero
   (838/1200 · 100/160). */
.curva-caja .marcador {
  position: absolute;
  left: 69.8%;
  top: 62.5%;
  display: flex;
  align-items: center;
  gap: 0.55rem;
  transform: translateY(-50%);
}

.curva-caja .punto {
  flex: none;
  width: 8px;
  height: 8px;
  margin-left: -4px;
  border-radius: 50%;
  background: var(--acento-vivo);
  box-shadow: 0 0 14px rgba(40, 202, 190, 0.7);
}

.curva-caja .etiqueta {
  font-family: var(--letra-cifra);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: var(--texto-suave);
  white-space: nowrap;
}

/* ── Las pantallas del producto, incrustadas ──────────────────
   No son capturas ni imitaciones: son el HTML que pinta Lyquia, dentro
   de ESTE documento. Estuvieron en <iframe>, que regalaba el
   aislamiento, pero una ventana dentro de otra se lee como una lámina
   pegada encima: su fondo no es el de la página, su canto es una recta
   y su contenido no puede desbordar hacia el texto.

   Ahora el aislamiento se fabrica: `lyquia-producto.css` es el CSS del
   producto con todos sus selectores colgados de `.lyq`. Así `.lyq h1`
   (0,1,1) gana a `h1` (0,0,1) y las dos hojas dejan de verse. A cambio,
   la pantalla comparte lienzo, tipografías y grano con la página, se
   recorta a la altura que interesa y se disuelve por los bordes.

   El HTML no se toca a mano: lo incrusta `_fuente/demos/incrustar.py`
   entre las marcas <!-- pantalla:… -->. */

.escenario {
  width: min(1560px, 94vw);
  margin: clamp(2.5rem, 2rem + 2vw, 4rem) auto 0;
}

/* La isla. Tres puentes con el producto, y nada más.

   `.vista .lyq` y no `.lyq` a secas: el `:root`, el `html` y el
   `body` del producto aterrizan todos sobre `.lyq`, así que con una
   sola clase el puente empataba y perdía por orden. */
.vista .lyq {
  /* Las familias que el producto pide por variable son las que la web
     ya sirve: ni una descarga más. */
  --font-montserrat: 'Montserrat', system-ui, sans-serif;
  --font-baskerville: 'Libre Baskerville', Georgia, serif;
  --font-geist-mono: 'Geist Mono', ui-monospace, monospace;
  /* El lienzo de la aplicación pasa a ser el de la página. Es el único
     color del producto que se toca, y era el que delataba el recorte:
     un rectángulo #020617 sobre un fondo #080f1f se ve. Los paneles,
     las tarjetas, los gráficos y los semánticos siguen siendo suyos. */
  --lab-lienzo: var(--bg);
  background: transparent;
  /* La web escribe 17 px con interlínea 1,7; la aplicación se dibuja
     sobre 16 px con 1,5. Sin devolver la base, todo lo que dentro no
     lleva medida propia crece y descuadra. */
  font-size: 1rem;
  line-height: 1.5;
  /* La aplicación se dibuja para una ventana: las pantallas que son
     documento se desbordan hacia abajo y las recorta el hueco; las que
     son marco (el Lab, los diálogos) se ajustan a él. */
  height: 100%;
}

/* El envoltorio del producto pide una pantalla entera de alto. Aquí el
   alto lo pone el hueco. */
.vista .lyq .min-h-screen {
  /* Tres clases: el producto trae esta misma clase con dos, y su
     hoja cierra la cascada. */
  min-height: 0;
}

/* La web viste `p` por elemento (color apagado); dentro de la isla ese
   color lo ponen las clases del producto, y donde no las hay, la
   herencia. Con `:where` para no pesar más que ellas. */
.vista .lyq :where(p) {
  color: inherit;
}

/* La ventana por la que asoma: sin borde, sin fondo, sin radio. Lo que
   se ve es la interfaz del producto, no un recuadro que la contiene. */
.vista {
  position: relative;
}

.vista-isla {
  height: var(--vista-alto, 26rem);
  overflow: clip;
  /* Esto no es un detalle: media aplicación se cuelga de `fixed` o de
     `absolute` (el raíl del Lab, el diálogo de financiación, el plan de
     la IA). Sin un bloque contenedor propio, esos trozos se colocan
     contra el viewport y salen flotando sobre la página; con
     contención de pintado, la ventana ES su viewport. */
  contain: paint;
  /* Los bordes se disuelven en la página. Esto es lo que hace que la
     pantalla nazca del documento en lugar de estar pegada encima: por
     abajo se desvanece (y así se lee que sigue más allá), y por los
     lados se apaga el filo recto. */
  -webkit-mask-image:
    linear-gradient(to bottom, #000 calc(100% - var(--vista-humo, 6.5rem)), transparent),
    linear-gradient(to right, transparent, #000 2.4%, #000 97.6%, transparent);
  mask-image:
    linear-gradient(to bottom, #000 calc(100% - var(--vista-humo, 6.5rem)), transparent),
    linear-gradient(to right, transparent, #000 2.4%, #000 97.6%, transparent);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* Cada pantalla enseña el tramo del que habla su texto. */
.vista .vista-isla > .lyq {
  margin-top: calc(-1 * var(--vista-desde, 0px));
}

.vista-heroe {
  --vista-alto: min(72vh, 44rem);
  --vista-humo: 9rem;
}

/* Los diálogos del producto se centran en su ventana. Recortado por la
   mitad, un panel centrado se lee como un error; apoyado en la cima y
   disuelto por abajo, se lee como lo que es. */
.vista-cima .lyq .place-items-center {
  place-items: start center;
}

/* En pantallas estrechas manda el diseño adaptable del propio producto,
   que para eso lo tiene. Solo se recorta con más alto: en vertical su
   contenido se apila y hace falta más sitio para que se entienda. */
@media (max-width: 880px) {
  .vista {
    --vista-alto: 30rem;
    --vista-humo: 5rem;
  }

  .vista-heroe {
    --vista-alto: 32rem;
  }
}

/* ── La carga en móvil: primero el titular, luego el producto ─────────
   En un móvil de gama media (CPU ×4, 4G lento) la portada tardaba 2,8 s
   en pintar su primer fotograma, y no por la red: todo lo crítico había
   llegado a los 0,8 s. Era CPU. El primer pintado esperaba a maquetar
   el documento entero, y el documento lleva dentro las seis pantallas
   del producto, miles de nodos: 939 ms de maquetación y 460 de estilos
   antes de enseñar una sola letra (traza de Chrome).

   Tres cosas, de más a menos peso, y las tres solo en móvil (en
   escritorio las pantallas viven en escenas fijadas, se mueven con el
   scroll, y ahí saltarse su pintado se vería):

   1 · La pantalla del héroe se pinta un fotograma DESPUÉS del titular.
       Queda justo bajo el pliegue, dentro del margen en que el navegador
       ya la da por visible, así que `auto` no la salta: va `hidden`
       hasta que lyquia.js pone html.heroe-pintado tras el primer
       pintado. Su hueco tiene alto fijo: no hay salto. Y si lyquia.js no
       llega, la cabecera retira con-js a los 4 s y la regla se cae sola.
   2 · Las demás pantallas, `auto`: se maquetan cuando se acercan.
   3 · Las secciones de debajo, `auto` también, con el alto que tuvieron
       la última vez (el `auto` de contain-intrinsic-size) o una
       estimación mientras no se han pintado nunca.

   Medido con vitales.mjs, primera visita en móvil: de 2,8 s a 1,3 s de
   LCP (el paso a paso, en el README, «Web Vitals»). */
@media (max-width: 879.98px) {
  .vista-isla {
    content-visibility: auto;
  }

  html.con-js:not(.heroe-pintado) .vista-heroe .vista-isla {
    content-visibility: hidden;
  }

  main > .seccion {
    content-visibility: auto;
    contain-intrinsic-size: auto 1400px;
  }
}

/* ── El cartel: la pantalla espera velada hasta que te acercas ─────
   Dos capas y un fundido cruzado, la receta de la referencia. La
   pantalla no se tapa: se desenfoca y se apaga, así se ve que debajo
   hay un producto de verdad y no una promesa. Al acercar el cursor (o
   al llegar con el teclado, o siempre en táctil, donde no hay
   «acercar») el desenfoque se disuelve. */

.velo-demo {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  gap: 0.6rem;
  align-content: center;
  text-align: center;
  pointer-events: none;
  background:
    radial-gradient(60% 60% at 50% 50%, rgba(8, 15, 31, 0.72), rgba(8, 15, 31, 0.94));
  transition: opacity var(--dur-panel) var(--ease-suave);
}

.velo-demo .titulo {
  font-family: var(--letra-titular);
  font-size: clamp(1.4rem, 1.1rem + 1.4vw, 2.1rem);
  letter-spacing: 0.01em;
  color: var(--txt);
}

.velo-demo .titulo span {
  color: var(--cyan-l);
}

.velo-demo .pista {
  font-family: var(--letra-cifra);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mut);
}

.vista-heroe .vista-isla .lyq {
  filter: blur(7px) saturate(0.7);
  opacity: 0.5;
  transition:
    filter var(--dur-lejos) var(--ease-asentar),
    opacity var(--dur-lejos) var(--ease-asentar);
}

.vista-heroe:hover .vista-isla .lyq,
.vista-heroe:focus-within .vista-isla .lyq,
.vista-heroe.revelada .vista-isla .lyq {
  filter: none;
  opacity: 1;
}

.vista-heroe:hover .velo-demo,
.vista-heroe:focus-within .velo-demo,
.vista-heroe.revelada .velo-demo {
  opacity: 0;
}

/* Sin «acercar el cursor» no puede haber revelado por acercarlo: en
   táctil y con movimiento reducido, la pantalla se ve desde el
   principio. */
@media (hover: none), (prefers-reduced-motion: reduce) {
  .velo-demo {
    display: none;
  }

  .vista-heroe .vista-isla .lyq {
    filter: none;
    opacity: 1;
  }
}

/* ── El estudio: el portátil del héroe ────────────────────────────────
   Una mesa redonda de nogal bajo un softbox cenital, y sobre ella el
   portátil: una secuencia de fotogramas fotorrealistas (Blender, Cycles;
   la escena en _fuente/estudio/) que assets/js/estudio.js pinta en un
   canvas según el scroll. Encima del panel, en todos los fotogramas, va
   la figura de siempre, el HTML de verdad, deformada en perspectiva
   hasta sus cuatro esquinas: el texto que se lee nunca es el del render.

   La pantalla mide lo que la ventana (o lo que pide el 16:10 para
   cubrirla de alto): al final del viaje, a escala 1, la pantalla ES la
   ventana y se ve a 1:1, sin interpolar un píxel.

   Todo cuelga de html.con-estudio, que pone la cabecera en pantallas
   anchas y que lyquia.js retira si el estudio no llega a arrancar. Sin
   ella (o por debajo de 880 px) los envoltorios no pintan caja y la
   pantalla vuelve a ser la de siempre, recortada y disuelta. */

.portatil-lienzo {
  display: contents;
}

.estudio,
.portatil-muesca,
.portatil-reflejo {
  display: none;
}

@media (min-width: 880px) {
  /* El amanecer del héroe se pinta sobre la altura que tenía: con la
     escena el héroe mide cinco pantallas y el degradado se estiraba. */
  html.con-estudio .heroe {
    background-size: 100% 1700px;
    background-repeat: no-repeat;
  }

  html.con-estudio .escenario {
    --pw: max(100vw, 160vh);
    --ph: calc(var(--pw) / 1.6);
    width: 100%;
  }

  html.con-estudio .portatil-lienzo {
    display: block;
    position: relative;
    height: min(86vh, 62vw);
    overflow: clip;
  }

  /* El plató es la página: el fondo del lienzo es el --bg, y además se
     disuelve por los cantos, así que no hay rectángulo que se lea. */
  html.con-estudio .estudio {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    transition: opacity 900ms var(--ease-suave);
    /* Quieto en la página, el fotograma acaba por abajo en la mesa: se
       funde. Arriba no hace falta, el fondo del render es el de la web. */
    -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent);
    mask-image: linear-gradient(to bottom, #000 72%, transparent);
  }

  /* La pantalla, a su tamaño lógico, en la esquina del lienzo: de ahí
     la lleva el estudio a su sitio con la homografía. Hasta que el
     estudio no ha pintado, no se ve (flotaría suelta). */
  html.con-estudio .portatil-lienzo .vista-heroe {
    --vista-alto: var(--ph);
    position: absolute;
    top: 0;
    left: 0;
    width: var(--pw);
    height: var(--ph);
    transform-origin: 0 0;
    border-radius: calc(var(--pw) * 0.0075) calc(var(--pw) * 0.0075) 0 0;
    opacity: 0;
    transition: opacity 900ms var(--ease-suave);
  }

  html.estudio-listo .estudio,
  html.estudio-listo .portatil-lienzo .vista-heroe {
    opacity: 1;
  }

  /* Opaca: el producto no siempre llena la pantalla de alto (a 1920 px
     la pantalla lógica mide 1920×1200 y su contenido acaba antes), y lo
     que queda debajo es el panel del render, con su captura. Sin fondo,
     esa captura asomaba bajo la pantalla de verdad. */
  html.con-estudio .portatil-lienzo .vista-isla {
    border-radius: inherit;
    background-color: var(--bg);
    -webkit-mask-image: none;
    mask-image: none;
  }

  /* «Acerca el cursor» no es la invitación aquí: la pantalla se
     enciende sola cuando el portátil se pone de frente. */
  html.con-estudio .portatil-lienzo .velo-demo .pista {
    display: none;
  }

  html.con-estudio .portatil-lienzo .velo-demo {
    border-radius: inherit;
  }

  /* La muesca de la cámara, colgando del bisel sobre la pantalla. */
  html.con-estudio .portatil-muesca {
    display: block;
    position: absolute;
    z-index: 7;
    top: -1px;
    left: 50%;
    width: calc(var(--pw) * 0.062);
    height: calc(var(--ph) * 0.034);
    translate: -50% 0;
    border-radius: 0 0 calc(var(--pw) * 0.006) calc(var(--pw) * 0.006);
    background:
      radial-gradient(circle at 50% 45%, #1a2336 0 calc(var(--ph) * 0.0045), transparent calc(var(--ph) * 0.006)),
      #030304;
  }

  /* El brillo del cristal, que se nota con la pantalla aún apagada. */
  html.con-estudio .portatil-reflejo {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 6;
    border-radius: inherit;
    pointer-events: none;
    background: linear-gradient(118deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.02) 36%, transparent 36.2%);
  }

  html.con-estudio .portatil-lienzo .vista-heroe.revelada .portatil-reflejo {
    opacity: 0;
    transition: opacity 1200ms var(--ease-suave);
  }
}

/* ── El bento de funciones ──────────────────────────────────────────── */

.bento {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 0.9rem;
}

.celda {
  grid-column: span 12;
  border: 1px solid var(--filete);
  border-radius: var(--radio);
  background: var(--card);
  box-shadow: var(--alza);
  padding: clamp(1.5rem, 1.2rem + 1vw, 2.25rem);
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  transition:
    background-color var(--dur-cerca) var(--ease-asentar),
    border-color var(--dur-cerca) var(--ease-asentar);
}

.celda p {
  font-size: 0.9375rem;
  line-height: 1.65;
}

.celda .motivo {
  margin-top: auto;
  padding-top: 1.25rem;
}

@media (min-width: 880px) {
  .celda-7 { grid-column: span 7; }
  .celda-5 { grid-column: span 5; }
  .celda-4 { grid-column: span 4; }
  .celda-12 { grid-column: span 12; }

  /* La banda baja es distinta a propósito: horizontal, sin motivo. */
  .celda-12 {
    flex-direction: row;
    align-items: baseline;
    gap: 2.5rem;
  }

  .celda-12 h3 {
    flex: 0 0 14rem;
  }

  .celda-12 p {
    max-width: 52rem;
  }
}

/* Motivo de la celda grande: la mini-curva con su rotura, estática. */
.motivo-curva svg {
  display: block;
  width: 100%;
  height: 56px;
}

.motivo-curva .linea {
  stroke: var(--acento);
  stroke-width: 1.5;
  fill: none;
  opacity: 0.45;
}

.motivo-curva .cero {
  stroke: var(--texto-suave);
  stroke-width: 1;
  stroke-dasharray: 2 5;
  opacity: 0.3;
}

.motivo-curva .punto {
  fill: var(--acento-vivo);
}

/* Motivo de la celda de simulación: dos fichas de movimiento, quietas. */
.motivo-fichas {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.motivo-fichas span {
  font-family: var(--letra-cifra);
  font-variant-numeric: tabular-nums;
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  color: var(--texto-suave);
  border: 1px solid var(--filete);
  border-radius: 999px;
  padding: 0.3rem 0.85rem;
}

.motivo-fichas .ficha-viva {
  color: var(--acento-vivo);
  border-color: var(--linea-cyan);
}

/* ── Los capítulos (Lyquia en acción) ───────────────────────────────── */

.capitulo {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.75rem, 1.5rem + 2vw, 3.5rem);
  align-items: center;
  padding-block: clamp(2.75rem, 2rem + 3vw, 4.75rem);
}

.capitulo + .capitulo {
  border-top: 1px solid var(--filete);
}

/* Las celdas de la rejilla pueden encoger por debajo de su contenido:
   sin esto, la demo del Lab (ancho máximo interno) ensancharía la
   página en móvil en vez de desplazarse por dentro. */
.capitulo-texto,
.capitulo-media {
  min-width: 0;
}

@media (min-width: 880px) {
  .capitulo {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
  }

  .capitulo .capitulo-texto {
    max-width: 62ch;
  }
}

.capitulo .numero {
  display: block;
  font-size: 1rem;
  margin-bottom: 1.1rem;
  color: var(--acento);
  opacity: 0.75;
}

.capitulo h3 {
  font-family: var(--letra-titular);
  font-weight: 400;
  font-size: clamp(1.4rem, 1.1rem + 1.4vw, 1.9rem);
  line-height: 1.22;
  letter-spacing: -0.005em;
}

.capitulo p {
  margin-top: 1.1rem;
  font-size: 0.9875rem;
}

/* El capítulo ancho (pool bancario): la media a todo el ancho. */
.capitulo-ancho {
  display: block;
}

.capitulo-ancho .capitulo-texto {
  max-width: 46rem;
  margin-bottom: 2.25rem;
}

/* ── Integraciones: dos sendas hermanas, no gemelas ─────────────────── */

.sendas {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem;
}

@media (min-width: 880px) {
  .sendas {
    grid-template-columns: 1fr 1fr;
  }
}

.senda {
  border: 1px solid var(--filete);
  border-radius: var(--radio);
  background: var(--card);
  box-shadow: var(--alza);
  padding: clamp(1.75rem, 1.4rem + 1.2vw, 2.5rem);
  display: flex;
  flex-direction: column;
}

.senda-erp {
  border-color: var(--linea-cyan);
}

.senda h3 {
  font-size: 1.25rem;
}

.senda p {
  margin-top: 0.9rem;
  font-size: 0.9375rem;
}

/* ── Las guías: cartas hermanas de las sendas, en rejilla de tres ─────
   Reutilizan .senda (borde, fondo, aire y el alzarse al pasar) y la
   cadencia de reveals de la casa; lo único propio es la rejilla y que la
   carta entera sea el enlace. Sección normal: la página ya tiene sus dos
   escenas fijadas y no cabe una tercera. */

.guias {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem;
}

@media (min-width: 720px) {
  .guias {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1080px) {
  .guias {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.guias .senda {
  text-decoration: none;
  color: inherit;
}

.guias .senda h3 {
  margin-top: 0.7rem;
  transition: color var(--dur-cerca) var(--ease-suave);
}

.guias .senda:hover h3,
.guias .senda:focus-visible h3 {
  color: var(--acento-vivo);
}

.guias .senda .pie {
  color: var(--acento);
}

/* ── La conexión con el ERP, contada ──────────────────────────────────
   Una clavija recorre su cable hasta cada sistema y lo enciende. El
   cable mide lo mismo en las tres filas (un ancho fijo, no un 1fr), y
   por dos razones: los logos quedan alineados entre sí, y el viaje de
   la clavija puede escribirse como una traslación exacta en vez de
   depender de cuánto mida la columna. */

.conexiones {
  --cable: 104px;
  display: grid;
  gap: 1.1rem;
  margin-top: 1.75rem;
}

.conexion {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  min-height: 26px;
}

.conexion .cable {
  position: relative;
  flex: none;
  width: var(--cable);
  height: 1px;
  background: var(--filete);
}

/* La corriente: el tramo ya recorrido, encendido detrás de la clavija. */
.conexion .corriente {
  position: absolute;
  inset: 0;
  transform-origin: left;
  background: linear-gradient(90deg, transparent, var(--cyan) 85%);
}

.conexion .clavija {
  position: absolute;
  right: -3px;
  top: 50%;
  width: 26px;
  height: 14px;
  margin-top: -7px;
  stroke: var(--cyan-l);
  fill: none;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.conexion img {
  height: 20px;
  width: auto;
  flex: none;
}

.conexion img.l-odoo { height: 25px; }
.conexion img.l-holded { height: 17px; }

.conexion--otros {
  padding-left: calc(var(--cable) + 0.9rem);
}

.conexion .otros {
  font-family: var(--letra-cifra);
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  color: var(--texto-suave);
}

@media (max-width: 1100px) {
  .conexiones { --cable: 68px; }
}

/* ── El importador, contado ────────────────────────────────────────── */

.importador {
  margin-top: 1.6rem;
  padding: 1rem 1.15rem 1.1rem;
  border: 1px solid var(--filete);
  border-left: 2px solid var(--cyan);
  border-radius: var(--radio-s);
  background: rgba(255, 255, 255, 0.02);
}

.importador .libro {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.importador .hoja {
  flex: none;
  width: 19px;
  height: 19px;
  stroke: var(--cyan-l);
  fill: none;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.importador .nombre {
  font-size: 0.8125rem;
  color: var(--texto);
}

.importador .peso {
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--texto-suave);
}

.importador .progreso {
  height: 3px;
  border-radius: 2px;
  margin-top: 0.85rem;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}

.importador .progreso i {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--cyan);
  transform-origin: left;
}

.importador .leido {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin-top: 0.8rem;
  font-family: var(--letra-cifra);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--cyan-l);
}

.importador .visto {
  flex: none;
  width: 13px;
  height: 13px;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.importador .columnas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.7rem;
}

.importador .columnas li {
  font-family: var(--letra-cifra);
  font-size: 0.7rem;
  letter-spacing: 0.03em;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--filete);
  border-radius: 999px;
  color: var(--texto-suave);
}

/* ── El enlace de descarga ─────────────────────────────────────────── */

.descarga {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 0 1rem;
  margin-top: 1.5rem;
  padding: 0.85rem 1.15rem;
  border: 1px solid var(--linea-cyan);
  border-radius: var(--radio);
  background: var(--card-alta);
  box-shadow: var(--alza);
  text-decoration: none;
  transition:
    border-color var(--dur-cerca) var(--ease-suave),
    background-color var(--dur-cerca) var(--ease-suave);
}

.descarga:hover {
  border-color: var(--cyan);
}

.descarga .bajar {
  grid-row: span 2;
  width: 21px;
  height: 21px;
  stroke: var(--acento-vivo);
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.descarga .que {
  font-weight: 400;
  font-size: 0.9375rem;
  color: var(--texto);
}

.descarga .meta {
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--texto-suave);
}

.senda .pie {
  margin-top: auto;
  padding-top: 1.4rem;
  font-size: 0.8125rem;
  border-top: 1px solid var(--filete);
}

.senda .pie:not(:first-child) {
  margin-top: 1.6rem;
}

/* ── Los tres pasos, sobre su eje ───────────────────────────────────── */

.pasos {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.25rem;
}

/* El eje: nace completo; el bloque MOVIMIENTO lo dibuja si puede. */
.pasos::before {
  content: '';
  position: absolute;
  top: 5px;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--acento), var(--linea-cyan) 60%, transparent);
  opacity: 0.55;
}

@media (min-width: 880px) {
  .pasos {
    grid-template-columns: repeat(3, 1fr);
    gap: 2.75rem;
  }
}

.paso {
  padding-top: 2.1rem;
  position: relative;
}

.paso::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--bg);
  border: 2px solid var(--acento);
}

.paso .numero {
  color: var(--acento);
}

.paso h3 {
  margin-top: 0.5rem;
}

.paso p {
  margin-top: 0.6rem;
  font-size: 0.9375rem;
}

/* ── Los planes ─────────────────────────────────────────────────────── */

.planes {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem;
  align-items: stretch;
}

@media (min-width: 940px) {
  .planes {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 939.98px) {
  .planes {
    max-width: 430px;
    margin-inline: auto;
  }
}

.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--filete);
  border-radius: var(--radio);
  background: var(--card);
  box-shadow: var(--alza);
  padding: clamp(1.75rem, 1.4rem + 1.2vw, 2.4rem);
}

.plan-pro {
  border-color: var(--linea-cyan);
  background: var(--card-alta);
  box-shadow: var(--alza), var(--glow);
}

.plan .distintivo {
  position: absolute;
  top: -12px;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--letra-cifra);
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--tinta-boton);
  background: var(--acento);
  border-radius: 999px;
  padding: 0.3rem 0.9rem;
}

.plan .nombre {
  font-family: var(--letra-cifra);
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--acento-vivo);
}

.plan .lema {
  font-family: var(--letra-titular);
  font-size: 1.3rem;
  color: var(--texto);
  margin-top: 0.35rem;
}

.plan .precio {
  font-family: var(--letra-cifra);
  font-variant-numeric: tabular-nums;
  font-size: clamp(2.5rem, 2rem + 1.6vw, 3.25rem);
  line-height: 1;
  color: var(--texto);
  margin-top: 1.6rem;
}

.plan .precio small {
  font-size: 0.875rem;
  color: var(--texto-suave);
  letter-spacing: 0.02em;
}

.plan ul {
  margin: 1.6rem 0 1.9rem;
  display: grid;
  gap: 0.65rem;
  flex: 1;
}

.plan li {
  display: flex;
  gap: 0.65rem;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--texto-suave);
}

.plan li::before {
  content: '✓';
  color: var(--acento);
  font-weight: 400;
  flex: none;
}

.plan li.mas {
  color: var(--texto);
  font-weight: 400;
}

.plan .boton {
  justify-content: center;
}

.nota-planes {
  /* Los 2,6rem que separaban los planes de lo que viene debajo los
     ponía la nota del precio fundador, que ya no está. */
  margin-top: 2.6rem;
  text-align: center;
  font-size: 0.8125rem;
}

/* ── La noria de los planes ────────────────────────────────
   Tres columnas iguales dicen que los tres planes valen lo mismo. Una
   noria dice otra cosa: el del centro manda —de frente, más grande y
   delante— y los otros dos esperan a los lados, girados hacia él. Al
   pulsar uno de los lados la noria gira una posición y ese plan se
   pone delante; el que estaba en el centro cede el sitio y el tercero
   cruza por detrás, que es lo que hace que el giro se entienda.

   La entrada cuenta lo mismo en pequeño: primero emerge Pro desde el
   fondo, y cuando ya está puesto llegan Básico por la izquierda y Full
   por la derecha.

   Vive bajo tres guardas: que haya sitio (940 px), que haya JS (es
   `data-noria` quien la enciende) y que nadie haya pedido menos
   movimiento. Si falta cualquiera de las tres, los tres planes se leen
   como siempre, en fila y del mismo tamaño. */

@media (min-width: 940px) and (prefers-reduced-motion: no-preference) {
  /* Las cartas nacen fuera de la pantalla para poder entrar, y un
     elemento desplazado con `transform` SIGUE contando para el ancho
     desplazable: sin este recorte la página traía barra horizontal
     desde que carga hasta que los planes se revelan (medido: 184 px de
     sobra a 1128). Se recorta en la sección y no en el carril, porque
     `overflow` distinto de `visible` sobre el elemento que lleva
     `preserve-3d` lo aplana y se pierde el orden por profundidad. */
  #planes {
    overflow-x: clip;
  }

  .planes[data-noria] {
    --dur-noria: 660ms;
    grid-template-columns: minmax(0, 1fr);
    /* El punto de fuga, en el centro del carril. Sin `preserve-3d` las
       cartas no se ordenarían por profundidad y la que cruza pasaría
       por delante de la del centro en vez de por detrás. */
    perspective: 1600px;
    transform-style: preserve-3d;
    /* Y aquí está el truco que no se ve venir: en 3D, un hijo con
       `translateZ` negativo queda DETRÁS del plano de su propio padre.
       Se pinta igual (el padre no tiene fondo), pero el que recibe el
       clic es el padre, así que las cartas de los lados no se podían
       pulsar. El carril deja de ser blanco de los punteros y cada carta
       los recoge por su cuenta. */
    pointer-events: none;
  }

  .planes[data-noria] .plan {
    grid-area: 1 / 1;
    justify-self: center;
    width: min(25rem, 38%);
    pointer-events: auto;
  }

  /* Los tres sitios. `translateX` en porcentaje se mide sobre la propia
     carta, así que el reparto aguanta cualquier ancho. */
  .planes[data-noria] .plan[data-sitio='centro'] {
    --reposo: translateX(0) translateZ(0) rotateY(0deg) scale(1);
    --llegada: translateZ(-420px) scale(0.92);
    z-index: 3;
  }

  .planes[data-noria] .plan[data-sitio='izquierda'] {
    --reposo: translateX(-90%) translateZ(-170px) rotateY(20deg) scale(0.86);
    --llegada: translateX(-170%) translateZ(-300px) rotateY(34deg) scale(0.78);
    z-index: 2;
  }

  .planes[data-noria] .plan[data-sitio='derecha'] {
    --reposo: translateX(90%) translateZ(-170px) rotateY(-20deg) scale(0.86);
    --llegada: translateX(170%) translateZ(-300px) rotateY(-34deg) scale(0.78);
    z-index: 2;
  }

  /* El sitio de reposo, y el viaje entre sitios. La especificidad
     (cuatro clases) no es capricho: los reveals en cadencia escriben
     sobre estas mismas cartas más abajo en la hoja. */
  html.con-js .planes[data-noria] .plan[data-sitio],
  .planes[data-noria] .plan[data-sitio] {
    transform: var(--reposo);
    transition:
      transform var(--dur-noria) var(--ease-asentar),
      opacity var(--dur-noria) var(--ease-suave),
      box-shadow var(--dur-noria) var(--ease-suave);
    transition-delay: 0s;
  }

  /* Lo que está delante se nota también por el suelo que proyecta. */
  .planes[data-noria] .plan[data-sitio='centro'] {
    box-shadow: var(--alza), 0 40px 90px -42px rgba(0, 0, 0, 0.85);
  }

  .planes[data-noria] .plan-pro[data-sitio='centro'] {
    box-shadow: var(--alza), var(--glow), 0 40px 90px -42px rgba(0, 0, 0, 0.85);
  }

  /* Los lados invitan a pulsarse; el del centro ya está donde tiene que
     estar y no hace nada. Solo cuando NO manda el cursor de la casa: con
     él, lo que avisa es el anillo cerrándose, y una flecha del sistema
     encima sería el segundo cursor en pantalla. */
  html:not(.con-cursor) .planes[data-noria] .plan[data-sitio]:not([data-sitio='centro']) {
    cursor: pointer;
  }

  /* Y su botón no responde mientras está a un lado: pulsar una carta de
     lado la trae al centro, no abre el correo. Con el teclado sigue
     siendo alcanzable —`pointer-events` no quita el foco—, y al
     recibirlo la carta se pone delante sola. */
  .planes[data-noria] .plan[data-sitio]:not([data-sitio='centro']) .boton {
    pointer-events: none;
  }

  /* La entrada: escondidas y fuera de sitio hasta que la sección se
     revela. Bajo `html.con-js` como todo lo que se esconde, para que
     sin JS los planes nazcan visibles. */
  html.con-js .planes[data-noria] .plan[data-sitio] {
    opacity: 0;
    transform: var(--llegada);
  }

  html.con-js .planes[data-noria].es-visible .plan[data-sitio] {
    opacity: 1;
    transform: var(--reposo);
  }

  /* Primero Pro, y cuando ya está puesto, los dos lados. El retardo
     vive en un atributo que el JS retira al terminar: si se quedase,
     cada giro saldría tarde. Y va con `html.con-js` delante para pesar
     más que el `transition-delay: 0s` de arriba, que existe para que
     los reveals en cadencia no cuelen aquí sus propios retardos. */
  html.con-js .planes[data-noria][data-entrando] .plan[data-sitio='izquierda'] {
    transition-delay: 300ms;
  }

  html.con-js .planes[data-noria][data-entrando] .plan[data-sitio='derecha'] {
    transition-delay: 380ms;
  }
}

/* ── La noria de las guías ─────────────────────────────────
   La misma noria que la de los planes, con ocho cartas: tres a la
   vista (izquierda, centro, derecha) y cinco esperando al fondo,
   detrás de la del centro y sin punteros, que salen por un lado
   cuando la rueda gira. Con cinco escondidas hace falta decir que
   están: dos flechas y un contador bajo la rueda, que solo existen
   cuando la rueda gira (las mismas tres guardas). Sin rueda, las ocho
   se leen en rejilla, que es como deben leerse cuando no hay rueda.
   Las cartas son enlaces enteros: pulsar una de lado la trae al
   centro sin navegar, y navegar es cosa de la del centro. */

@media (min-width: 940px) and (prefers-reduced-motion: no-preference) {
  #guias {
    overflow-x: clip;
  }

  .guias[data-noria] {
    --dur-noria: 660ms;
    grid-template-columns: minmax(0, 1fr);
    perspective: 1600px;
    transform-style: preserve-3d;
    pointer-events: none;
  }

  .guias[data-noria] .senda {
    grid-area: 1 / 1;
    justify-self: center;
    width: min(25rem, 38%);
    pointer-events: auto;
  }

  .guias[data-noria] .senda[data-sitio='centro'] {
    --reposo: translateX(0) translateZ(0) rotateY(0deg) scale(1);
    --llegada: translateZ(-420px) scale(0.92);
    z-index: 3;
  }

  .guias[data-noria] .senda[data-sitio='izquierda'] {
    --reposo: translateX(-90%) translateZ(-170px) rotateY(20deg) scale(0.86);
    --llegada: translateX(-170%) translateZ(-300px) rotateY(34deg) scale(0.78);
    z-index: 2;
  }

  .guias[data-noria] .senda[data-sitio='derecha'] {
    --reposo: translateX(90%) translateZ(-170px) rotateY(-20deg) scale(0.86);
    --llegada: translateX(170%) translateZ(-300px) rotateY(-34deg) scale(0.78);
    z-index: 2;
  }

  /* Las del fondo: detrás de la del centro, y del tamaño de los lados
     para que al salir por uno de ellos no cambien de escala de golpe. */
  .guias[data-noria] .senda[data-sitio='fondo'] {
    --reposo: translateZ(-420px) scale(0.86);
    --llegada: translateZ(-420px) scale(0.86);
    z-index: 1;
  }

  html.con-js .guias[data-noria] .senda[data-sitio],
  .guias[data-noria] .senda[data-sitio] {
    transform: var(--reposo);
    transition:
      transform var(--dur-noria) var(--ease-asentar),
      opacity var(--dur-noria) var(--ease-suave),
      box-shadow var(--dur-noria) var(--ease-suave);
    transition-delay: 0s;
  }

  .guias[data-noria] .senda[data-sitio='centro'] {
    box-shadow: var(--alza), 0 40px 90px -42px rgba(0, 0, 0, 0.85);
  }

  html.con-js .guias[data-noria] .senda[data-sitio] {
    opacity: 0;
    transform: var(--llegada);
  }

  html.con-js .guias[data-noria].es-visible .senda[data-sitio] {
    opacity: 1;
    transform: var(--reposo);
  }

  /* Las del fondo no se ven ni se pulsan, también después de la
     entrada; el foco sí les llega, y las trae al centro. Va detrás de
     la regla de arriba y con su misma especificidad para ganarle. */
  html.con-js .guias[data-noria].es-visible .senda[data-sitio='fondo'],
  .guias[data-noria] .senda[data-sitio='fondo'] {
    opacity: 0;
    pointer-events: none;
  }

  html.con-js .guias[data-noria][data-entrando] .senda[data-sitio='izquierda'] {
    transition-delay: 300ms;
  }

  html.con-js .guias[data-noria][data-entrando] .senda[data-sitio='derecha'] {
    transition-delay: 380ms;
  }

  /* Los mandos, solo cuando la rueda gira: mismas tres guardas. */
  html.con-js .guias[data-noria] + .noria-mandos {
    display: flex;
  }
}

/* Las flechas y el contador de la noria. Nacen escondidos: sin rueda
   no hay nada que mandar. */
.noria-mandos {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 1.75rem;
}

.noria-paso {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--filete);
  border-radius: 50%;
  background: var(--card);
  color: var(--texto);
  cursor: pointer;
  transition:
    border-color var(--dur-cerca) var(--ease-asentar),
    background-color var(--dur-cerca) var(--ease-asentar);
}

.noria-paso:hover,
.noria-paso:focus-visible {
  border-color: var(--linea-cyan);
  background: var(--card-alta);
}

.noria-paso svg {
  width: 20px;
  height: 20px;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: none;
}

.noria-contador {
  min-width: 4.5rem;
  margin: 0;
  text-align: center;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  color: var(--texto-suave);
}

/* ── Preguntas ──────────────────────────────────────────────────────── */

/* Alineadas a la izquierda como el resto del cuerpo: los dos únicos
   momentos centrados de la portada son el héroe y el cierre. */
.preguntas {
  max-width: 720px;
  border-top: 1px solid var(--filete);
}

.preguntas details {
  border-bottom: 1px solid var(--filete);
}

.preguntas summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1.4rem 0.25rem;
  font-weight: 400;
  font-size: 1.0625rem;
  color: var(--texto);
  transition: color var(--dur-cerca) var(--ease-suave);
}

.preguntas summary::-webkit-details-marker {
  display: none;
}

.preguntas summary:hover {
  color: var(--acento-vivo);
}

.preguntas summary .mas {
  flex: none;
  font-family: var(--letra-cifra);
  font-size: 1.15rem;
  color: var(--acento);
  transition: transform var(--dur-cerca) var(--ease-asentar);
  transform-origin: center;
  align-self: center;
}

.preguntas details[open] summary .mas {
  transform: rotate(45deg);
}

.preguntas details p {
  padding: 0 2.5rem 1.5rem 0.25rem;
  font-size: 0.9375rem;
}

/* ── El cierre ──────────────────────────────────────────────────────── */

.final {
  text-align: center;
}

/* El eco de la curva: plana y sobre cero. La caja bajo control. */
.curva-calma {
  max-width: 560px;
  margin: 0 auto 2.75rem;
}

.curva-calma svg {
  display: block;
  width: 100%;
  height: 64px;
}

.curva-calma .linea {
  stroke: var(--acento);
  stroke-width: 2;
  fill: none;
  opacity: 0.55;
}

.curva-calma .cero {
  stroke: var(--texto-suave);
  stroke-width: 1;
  stroke-dasharray: 3 6;
  opacity: 0.3;
}

.final h2 {
  max-width: 24ch;
  margin-inline: auto;
}

.final .entradilla {
  max-width: 30rem;
  margin: 1.4rem auto 2.4rem;
}

/* ── El pie ─────────────────────────────────────────────────────────── */

.pie-pagina {
  border-top: 1px solid var(--filete);
  padding-block: clamp(3rem, 2.5rem + 2vw, 4.5rem) 2rem;
}

.pie-columnas {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
}

@media (min-width: 760px) {
  .pie-columnas {
    grid-template-columns: 1.4fr 1fr 1fr;
    gap: 2rem;
  }
}

.pie-pagina .marca img {
  width: 32px;
  height: 32px;
}

.pie-pagina .marca .logotipo {
  height: 17px;
}

.pie-pagina .descriptor {
  margin-top: 1rem;
  max-width: 24rem;
  font-size: 0.9375rem;
}

.pie-pagina .pie-titulo {
  font-family: var(--letra-cifra);
  font-weight: 400;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--texto-suave);
  margin-bottom: 1.1rem;
}

.pie-pagina nav ul {
  display: grid;
  gap: 0.55rem;
}

.pie-pagina nav a {
  font-size: 0.9375rem;
  font-weight: 400;
  text-decoration: none;
  color: var(--texto-suave);
  transition: color var(--dur-cerca) var(--ease-suave);
}

.pie-pagina nav a:hover,
.pie-pagina nav a:focus-visible {
  color: var(--acento-vivo);
}

.pie-final {
  margin-top: clamp(2.5rem, 2rem + 2vw, 4rem);
  padding-top: 1.6rem;
  border-top: 1px solid var(--filete);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  font-size: 0.8125rem;
}

.pie-final p,
.pie-final a {
  color: var(--texto-suave);
}

/* ── Páginas interiores (guías y legales) ───────────────────────────── */

.pagina-interior main {
  padding-top: clamp(8rem, 7rem + 4vw, 10.5rem);
  padding-bottom: clamp(4.75rem, 4rem + 3vw, 7.5rem);
}

.miga {
  font-family: var(--letra-cifra);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--texto-suave);
}

.pagina-interior h1 {
  font-size: clamp(2rem, 1.2rem + 2.8vw, 3.25rem);
  max-width: 22ch;
  margin-top: 1.1rem;
}

.pagina-interior .meta {
  font-family: var(--letra-cifra);
  font-size: 0.8125rem;
  color: var(--texto-suave);
  margin-top: 1.25rem;
}

/* El lienzo interior: prosa + índice pegajoso en pantallas anchas. */
.interior-lienzo {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 3rem;
  margin-top: clamp(2.5rem, 2rem + 2vw, 4rem);
}

@media (min-width: 1280px) {
  .interior-lienzo {
    grid-template-columns: minmax(0, 68ch) 250px;
    gap: 5rem;
  }

  .indice {
    position: sticky;
    top: 108px;
    align-self: start;
  }
}

.indice h2 {
  font-family: var(--letra-cifra);
  font-weight: 400;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--texto-suave);
  margin-bottom: 1rem;
}

.indice ul {
  display: grid;
  gap: 0.5rem;
  border-left: 1px solid var(--filete);
}

.indice a {
  display: block;
  padding-left: 1rem;
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
  text-decoration: none;
  color: var(--texto-suave);
  border-left: 1px solid transparent;
  margin-left: -1px;
  transition:
    color var(--dur-cerca) var(--ease-suave),
    border-color var(--dur-cerca) var(--ease-suave);
}

.indice a:hover,
.indice a:focus-visible {
  color: var(--acento-vivo);
  border-left-color: var(--acento);
}

/* La prosa: medida de lectura, aire y jerarquía serif. */
.prosa {
  max-width: 68ch;
}

.prosa > * + * {
  margin-top: 1.1rem;
}

.prosa p,
.prosa li {
  font-size: 1rem;
  line-height: 1.75;
}

.prosa h2 {
  font-size: clamp(1.4rem, 1.2rem + 1vw, 1.75rem);
  padding-top: 2.25rem;
}

.prosa h3 {
  font-size: 1.0625rem;
  padding-top: 1.1rem;
}

.prosa ul,
.prosa ol {
  display: grid;
  gap: 0.55rem;
  padding-left: 1.4rem;
}

.prosa ul {
  list-style: disc;
}

.prosa ol {
  list-style: decimal;
}

.prosa ::marker {
  color: var(--acento);
  font-family: var(--letra-cifra);
  font-size: 0.9em;
}

.prosa a {
  color: var(--acento-vivo);
  text-decoration: underline;
  text-decoration-color: var(--linea-cyan);
  text-underline-offset: 0.2em;
  transition: text-decoration-color var(--dur-cerca) var(--ease-suave);
}

.prosa a:hover {
  text-decoration-color: currentColor;
}

/* Los botones dentro de la prosa no son enlaces de prosa: recuperan su
   tinta y pierden el subrayado (la regla .prosa a los pisaba y dejaba
   cian sobre cian, 1,5:1 — lo cazó auditar.js). */
.prosa a.boton {
  text-decoration: none;
}

.prosa a.boton-primario,
.prosa a.boton-primario:hover {
  color: var(--tinta-boton);
}

/* Tablas: hairlines y cifras tabulares, sin cajas pesadas. */
.prosa table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.prosa th,
.prosa td {
  text-align: left;
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--filete);
  color: var(--texto-suave);
  vertical-align: top;
}

.prosa th {
  font-family: var(--letra-cifra);
  font-weight: 400;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--texto);
  border-bottom-color: var(--linea-fuerte);
}

.prosa td strong {
  color: var(--texto);
}

/* La caja destacada: un dato apoyado, no una banda. */
.prosa .caja {
  border: 1px solid var(--filete);
  border-left: 2px solid var(--acento);
  border-radius: var(--radio-s);
  background: var(--card);
  padding: 1.25rem 1.5rem;
}

/* La firma de la guía: quién la escribe, en la caja destacada. Va con
   clase propia porque .caja también viste el titular de las legales, y
   porque el aire entre párrafos de la prosa solo alcanza a los hijos
   directos de .prosa. */
.prosa .autor {
  margin-top: 2.75rem;
}

.prosa .autor > * + * {
  margin-top: 0.55rem;
}

.prosa .autor .miga {
  margin-bottom: 0.35rem;
}

.prosa .autor p {
  font-size: 0.9375rem;
}

/* La banda de CTA de las guías y la de descarga. */
.prosa .cta-caja,
.prosa .descarga {
  border: 1px solid var(--linea-cyan);
  border-radius: var(--radio);
  background: var(--card-alta);
  box-shadow: var(--alza);
  padding: 1.75rem 2rem;
  margin-block: 2.25rem;
}

.prosa .cta-caja p,
.prosa .descarga p {
  margin: 0 0 1.25rem;
}

.prosa .descarga {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  flex-wrap: wrap;
}

.prosa .descarga p {
  margin: 0;
  flex: 1;
  min-width: 220px;
}

.enlaces-relacionados {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--filete);
  font-size: 0.9375rem;
}

/* Pie compacto de las interiores. */
.pie-simple {
  border-top: 1px solid var(--filete);
  padding-block: 2rem;
}

.pie-simple .wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
  font-size: 0.8125rem;
}

.pie-simple p {
  color: var(--texto-suave);
}

.pie-simple nav {
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
}

.pie-simple a {
  color: var(--texto-suave);
  text-decoration: none;
  transition: color var(--dur-cerca) var(--ease-suave);
}

.pie-simple a:hover,
.pie-simple a:focus-visible {
  color: var(--acento-vivo);
}

/* ═════════════════════════════════════════════════════════════════════
   MOVIMIENTO
   El fluir: fundidos y desplazamientos cortos hacia arriba, curvas que
   asientan, ninguna salida. Mecanismo de revelado: IntersectionObserver
   con la receta de la referencia (threshold .12, rootMargin -40px,
   clase .es-visible UNA vez). Se eligió IO y no ViewTimeline porque es
   «una vez» de verdad, es la receta de oakandgrid.com, y es verificable
   por DOM en el navegador integrado.

   Guarda anti-contenido-oculto: el estado oculto de .revela vive SOLO
   bajo html.con-js (la pone un script inline solo si existe
   IntersectionObserver) y bajo no-preference. Sin JS o con movimiento
   reducido, la página nace completa y quieta.
   ═════════════════════════════════════════════════════════════════════ */

/* ── 1 · Transiciones entre páginas (continuidad, CSS puro) ─────────── */

@view-transition {
  navigation: auto;
}

/* Asimetría deliberada: la que sale solo se apaga, rápida; la que entra
   sube por encima, más lenta. El agua no da portazos. */
::view-transition-old(root) {
  animation: vt-salir 240ms var(--ease-suave) both;
}

::view-transition-new(root) {
  animation: vt-entrar var(--dur-vista) var(--ease-asentar) both;
}

@keyframes vt-salir {
  to {
    opacity: 0;
  }
}

@keyframes vt-entrar {
  from {
    opacity: 0;
    transform: translateY(0.55rem);
  }
}

/* ── 1b · La portada (solo Inicio, una vez por visita) ───────────────
   La cubierta de carga: el navy de la casa con la marca en el centro y
   una línea que se llena como sube el nivel de un depósito, ~4 s en
   total y la página descubierta al abrirse hacia arriba. Sin contador
   de porcentaje: no hay carga que medir y esta web no enseña cifras
   que no son; la línea llenándose es el gesto, no un dato.

   Existe solo si el script de cabecera puso html.con-portada (una vez
   por visita vía sessionStorage; cualquier página del sitio deja la
   marca) y bajo la guarda de movimiento reducido: sin JS o con
   reducido, este div ni llega a pintarse. pagereveal la retira en
   llegadas por transición de vista. Es LA excepción deliberada a
   «ninguna salida»: la cubierta yéndose es el gesto que descubre.

   Compás: icono 150-800 ms · wordmark 350-1000 · línea 500-3100 ·
   la marca se apaga 3050-3350 · apertura 3300-3980. El héroe arranca
   en 3650 (--espera-heroe), cuando la cubierta ya despeja su tercio.

   Y el héroe está PINTADO debajo desde el primer pintado: con la
   cubierta puesta su entrada es solo desplazamiento («posarse», en el
   bloque 2). Un h1 a opacidad 0 no cuenta como LCP, y con el fundido de
   siempre el LCP de escritorio se iba a 4,7 s (medido con
   _fuente/pruebas/vitales.mjs); lo que está tapado sí cuenta. */

.portada {
  display: none;
}

@media (prefers-reduced-motion: no-preference) {
  html.con-portada {
    --espera-heroe: 3650ms;
  }

  html.con-portada .portada {
    display: grid;
    place-items: center;
    position: fixed;
    inset: 0;
    /* Sobre la barra (100), bajo el grano (130): también es material. */
    z-index: 120;
    background: var(--bg);
    animation: portada-abrirse 680ms ease-in-out 3300ms both;
  }

  html.con-portada .portada-contenido {
    display: grid;
    justify-items: center;
    gap: 1.4rem;
    animation: portada-apagarse 300ms var(--ease-suave) 3050ms forwards;
  }

  html.con-portada .portada .icono {
    width: 76px;
    height: 76px;
    filter: drop-shadow(0 10px 34px rgba(40, 202, 190, 0.4));
    animation: alzar var(--dur-focal) var(--ease-asentar) 150ms backwards;
  }

  html.con-portada .portada .wordmark {
    /* Baldosa de 76 px: mayuscula de 33, o sea 41 de caja. */
    height: 41px;
    width: auto;
    color: var(--txt);
    animation: alzar var(--dur-focal) var(--ease-asentar) 350ms backwards;
  }

  html.con-portada .portada .linea-carga {
    width: 180px;
    height: 2px;
    border-radius: 1px;
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
    animation: fundir 300ms var(--ease-suave) 500ms backwards;
  }

  html.con-portada .portada .linea-carga::before {
    content: '';
    display: block;
    height: 100%;
    background: var(--cyan);
    box-shadow: 0 0 12px rgba(40, 202, 190, 0.55);
    transform-origin: left;
    animation: portada-llenarse 2600ms ease-in-out 500ms both;
  }
}

@keyframes portada-llenarse {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}

@keyframes portada-apagarse {
  to {
    opacity: 0;
  }
}

@keyframes portada-abrirse {
  to {
    transform: translateY(-100%);
    visibility: hidden;
  }
}

/* ── 2 · La entrada del héroe (el momento focal) ─────────────────────
   Solo en llegadas directas: si la página entra por transición de
   vista, pagereveal marca html.llega-con-transicion y la entrada se
   salta para que el fundido aterrice sobre página completa. Si hay
   portada, todo el compás se desplaza --espera-heroe. */

@media (prefers-reduced-motion: no-preference) {
  html:not(.llega-con-transicion) .heroe .kicker {
    animation: alzar var(--dur-focal) var(--ease-asentar) var(--espera-heroe, 0ms) backwards;
  }

  html:not(.llega-con-transicion) .heroe h1 {
    animation: alzar var(--dur-focal) var(--ease-asentar) calc(var(--espera-heroe, 0ms) + 90ms) backwards;
  }

  html:not(.llega-con-transicion) .heroe .entradilla {
    animation: alzar var(--dur-focal) var(--ease-asentar) calc(var(--espera-heroe, 0ms) + 180ms) backwards;
  }

  html:not(.llega-con-transicion) .heroe .cta {
    animation: alzar var(--dur-focal) var(--ease-asentar) calc(var(--espera-heroe, 0ms) + 260ms) backwards;
  }

  html:not(.llega-con-transicion) .heroe .fiabilidad {
    animation: alzar var(--dur-focal) var(--ease-asentar) calc(var(--espera-heroe, 0ms) + 320ms) backwards;
  }

  html:not(.llega-con-transicion) .heroe .escenario {
    animation: aterrizar 700ms var(--ease-asentar) calc(var(--espera-heroe, 0ms) + 380ms) backwards;
  }

  /* La curva se traza cuando el H1 ya se ha posado. pathLength="1" en
     el SVG normaliza el trazo; el dasharray existe solo aquí dentro,
     así que sin esta guarda la curva está completa desde el primer
     frame. El punto y la etiqueta funden al terminar el trazo. */
  html:not(.llega-con-transicion) .curva-caja .linea {
    stroke-dasharray: 1;
    animation: trazar-caja var(--dur-trazo) ease-in-out calc(var(--espera-heroe, 0ms) + 500ms) both;
  }

  html:not(.llega-con-transicion) .curva-caja .marcador {
    animation: fundir 300ms var(--ease-suave) calc(var(--espera-heroe, 0ms) + 1800ms) backwards;
  }

  /* Con la cubierta puesta, el héroe NO se funde: está pintado a
     opacidad 1 debajo de la cubierta opaca desde el primer pintado y al
     arrancar solo se posa (transform). Así el h1 cuenta como LCP en el
     primer pintado (~1 s) y no cuando la cubierta lo descubre (4,7 s
     medidos): la cubierta yéndose ya es el fundido, y fundir dos veces
     era pagar dos veces. Solo cambia el nombre de la animación; duración,
     retardo y relleno siguen siendo los del compás. Sin cubierta, la
     entrada es la de siempre. Si alguien vuelve a meter opacidad aquí,
     el LCP vuelve a los 4,7 s. */
  html.con-portada:not(.llega-con-transicion) .heroe .kicker,
  html.con-portada:not(.llega-con-transicion) .heroe h1,
  html.con-portada:not(.llega-con-transicion) .heroe .entradilla,
  html.con-portada:not(.llega-con-transicion) .heroe .cta,
  html.con-portada:not(.llega-con-transicion) .heroe .fiabilidad {
    animation-name: posarse;
  }

  html.con-portada:not(.llega-con-transicion) .heroe .escenario {
    animation-name: aterrizar-quieto;
  }
}

@keyframes alzar {
  from {
    opacity: 0;
    transform: translateY(0.8rem);
  }
}

@keyframes aterrizar {
  from {
    opacity: 0;
    transform: translateY(1.4rem) scale(0.97);
  }
}

/* Los gemelos sin opacidad de alzar y aterrizar, para el héroe bajo la
   cubierta. */
@keyframes posarse {
  from {
    transform: translateY(0.8rem);
  }
}

@keyframes aterrizar-quieto {
  from {
    transform: translateY(1.4rem) scale(0.97);
  }
}

@keyframes trazar-caja {
  from {
    stroke-dashoffset: 1;
  }

  to {
    stroke-dashoffset: 0;
  }
}

@keyframes fundir {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

/* ── 2a · El estudio: de lado, de frente, y dentro ───────────────────
   Qué fotograma toca lo decide JS (un canvas no sabe de líneas de
   tiempo en CSS), pero lo que pasa DENTRO de la pantalla —el velo que se
   apaga, el producto que se enfoca, las columnas que se abren— sigue
   siendo CSS, con la línea de tiempo del escenario. Las dos cuentas
   miden lo mismo: u, en pantallas de scroll desde que el escenario
   asoma por abajo (ver estudio.js).

     entry 40 % → contain 36vh   la cámara rodea la mesa hasta el frente
                                 (y a partir de entry 90 % se enciende)
     contain 36vh → 144vh        la cámara entra en la pantalla
     contain 144vh → 160vh       un respiro para leerla a 1:1 (unos dos
                                 golpes de rueda: con 56vh, seis, se
                                 hacía larga)
     los últimos 100vh           las columnas del calendario se abren

   Los tramos van en vh y no en % a propósito: así el recorrido se puede
   acortar o alargar tocando solo el alto del escenario, sin descuadrar
   el giro ni la entrada (y estudio.js cuenta igual, en vh de scroll).

   Esos últimos 100vh no son un número al azar: la sección siguiente
   sube 100vh por debajo (margen negativo, ver 2b) y se queda quieta
   mientras tanto, así que lo que aparece en el centro al abrirse las
   columnas es ELLA, no una copia. Cuando el lienzo del estudio se
   suelta, ella ya está fijada en su sitio y la costura no se ve.

   Sin escena (poco sitio, sin líneas de tiempo, movimiento reducido) el
   estudio no se fija: la cámara hace el giro una vez, en el tiempo, al
   verse, y se queda de frente. Es la tercera sección fijada; ver el
   aviso del README antes de pensar en una cuarta. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 1000px) and (min-height: 700px) {
    html.con-estudio .heroe {
      padding-bottom: 0;
    }

    html.con-estudio:not(.llega-con-transicion) .heroe .escenario {
      animation: none;
    }

    html.con-estudio .escenario {
      /* 100vh de lienzo + 260vh de recorrido. */
      height: 360vh;
      margin-top: clamp(1rem, 0.5rem + 2vw, 2.5rem);
      view-timeline-name: --portatil;
      view-timeline-axis: block;
      /* Sin esto la línea de tiempo descuenta el scroll-padding de la
         barra (92 px) y los tramos dejan de medir lo que dicen: aquí
         cada vh de rango tiene que ser un vh de scroll, porque el
         relevo con la sección siguiente se cuadra al píxel, y porque
         estudio.js cuenta en vh de scroll. */
      view-timeline-inset: 0px;
    }

    html.con-estudio .portatil-lienzo {
      position: sticky;
      top: 0;
      z-index: 2;
      height: 100vh;
      /* Al final el lienzo está vacío pero sigue encima de la sección
         siguiente: que no se quede con sus clics. */
      pointer-events: none;
    }

    html.con-estudio .portatil-lienzo .vista-heroe {
      pointer-events: auto;
    }

    /* Fijado, el lienzo es la ventana: no tiene canto que fundir. Y la
       máscara se comería el pie de la pantalla justo antes del relevo. */
    html.con-estudio .estudio {
      -webkit-mask-image: none;
      mask-image: none;
    }

    /* Cuando la pantalla ya cubre la ventana, el plató sobra: se apaga
       de golpe (nadie lo ve) y deja de pintarse. Tiene que irse antes
       de que el fondo de la aplicación se vuelva transparente. */
    html.estudio-listo .estudio {
      transition: none;
      animation: portatil-soltar step-end both;
      animation-timeline: --portatil;
      animation-range: contain 144vh contain 147vh;
    }

    /* La pantalla se enciende al ponerse de frente: el velo con su
       «Descubre Lyquia» se apaga y el producto se enfoca. El hover no
       manda aquí (su transición pisaría a la animación a medio tramo). */
    html.con-estudio .portatil-lienzo .velo-demo {
      transition: none;
      animation: portatil-apagar linear both;
      animation-timeline: --portatil;
      animation-range: entry 90% contain 36vh;
    }

    html.con-estudio .portatil-lienzo .vista-isla .lyq {
      transition: none;
      animation: portatil-encender linear both;
      animation-timeline: --portatil;
      animation-range: entry 90% contain 36vh;
    }

    /* El brillo del cristal se queda con la pantalla ya encendida (es lo
       que hace que el HTML se lea DETRÁS de un cristal y no pegado encima
       del render) y se va mientras la cámara entra. */
    html.con-estudio .portatil-reflejo,
    html.con-estudio .portatil-lienzo .vista-heroe.revelada .portatil-reflejo {
      opacity: 1;
      transition: none;
      animation: portatil-apagar linear both;
      animation-timeline: --portatil;
      animation-range: contain 30vh contain 120vh;
    }

    /* La muesca se va cuando la pantalla ya casi es la ventana. */
    html.con-estudio .portatil-muesca {
      animation: portatil-apagar linear both;
      animation-timeline: --portatil;
      animation-range: contain 108vh contain 138vh;
    }

    /* ── Las columnas se abren ──
       Primero se retira lo que enmarca el calendario (la cabecera de
       indicadores sube, el raíl se va a la izquierda, las pestañas a la
       derecha, la barra de abajo baja) y enseguida las columnas se
       separan: las de la mitad izquierda hacia la izquierda y las de la
       derecha hacia la derecha, más lejos cuanto más de fuera, así que
       además de abrirse se despliegan. Qué lado le toca a cada una lo
       decide estudio.js por su posición (--lado, --paso); sin él, se
       quedan donde están y solo se apagan.

       El fondo de la aplicación es el de la página (ver el puente de la
       isla): al retirarlo, entre las columnas asoma la sección
       siguiente, que está justo debajo. */
    html.con-estudio .portatil-lienzo .lyq .oce-lab-scroll {
      overflow: visible;
    }

    html.con-estudio .portatil-lienzo .vista-isla,
    html.con-estudio .portatil-lienzo .lyq .min-h-screen {
      animation: portatil-transparentar linear both;
      animation-timeline: --portatil;
      animation-range: contain calc(100% - 100vh) contain calc(100% - 70vh);
    }

    html.con-estudio .portatil-lienzo .lyq aside {
      --sale: -100% 0;
    }

    html.con-estudio .portatil-lienzo .lyq main > :first-child {
      --sale: 0 -100%;
    }

    html.con-estudio .portatil-lienzo .lyq main > button {
      --sale: 100% 0;
    }

    html.con-estudio .portatil-lienzo .lyq main > :last-child {
      --sale: 0 100%;
    }

    html.con-estudio .portatil-lienzo .lyq aside,
    html.con-estudio .portatil-lienzo .lyq main > :not(.oce-lab-scroll) {
      animation: portatil-retirar cubic-bezier(0.5, 0, 0.75, 0) both;
      animation-timeline: --portatil;
      animation-range: contain calc(100% - 100vh) contain calc(100% - 62vh);
    }

    /* Las columnas del producto son un velo blanco al 2,4 % sobre el
       lienzo: al pasar por encima de la sección siguiente se leerían
       las dos cosas a la vez. Se les da su color ya compuesto sobre el
       fondo de la página, que es el mismo píxel mientras hay fondo
       debajo y un canto opaco cuando ya no lo hay. */
    html.con-estudio .portatil-lienzo .lyq .oce-lab-scroll > div > div {
      background-color: rgb(14, 21, 36);
      animation: portatil-abrir cubic-bezier(0.5, 0, 0.3, 1) both;
      animation-timeline: --portatil;
      animation-range: contain calc(100% - 100vh) contain calc(100% - 8vh);
    }

    /* Cuando ya no queda nada que ver, la pantalla deja de existir para
       el ratón y para el teclado: su asa no debe seguir tabulable
       encima de la sección que ya manda. */
    html.con-estudio .portatil-lienzo .vista-heroe {
      animation: portatil-soltar step-end both;
      animation-timeline: --portatil;
      animation-range: contain calc(100% - 2vh) contain 100%;
    }
  }
}

@keyframes portatil-apagar {
  to {
    opacity: 0;
  }
}

@keyframes portatil-encender {
  from {
    filter: blur(7px) saturate(0.7);
    opacity: 0.5;
  }

  to {
    filter: none;
    opacity: 1;
  }
}

@keyframes portatil-transparentar {
  to {
    background-color: transparent;
  }
}

@keyframes portatil-retirar {
  to {
    translate: var(--sale);
    opacity: 0;
  }
}

@keyframes portatil-abrir {
  62% {
    opacity: 1;
  }

  to {
    translate: calc(var(--lado, 0) * (60vw + var(--paso, 0) * 12vw)) 0;
    opacity: 0;
  }
}

@keyframes portatil-soltar {
  to {
    visibility: hidden;
  }
}

/* ── 2b · La escena: el bento se retira y el relevo emerge ────────────
   La única sección fijada de la web. El scroll no se secuestra —la barra
   sigue siendo del lector y avanza a su ritmo—: lo que se fija es el
   lienzo, y el recorrido de esos 220vh se reparte entre las seis celdas
   escapando cada una por su lado y la cabecera siguiente creciendo desde
   el centro.

   Nace apagada. Solo existe donde hay líneas de tiempo de scroll en CSS,
   con movimiento permitido y sitio de sobra (en móvil el bento es una
   columna y fijar la pantalla ahí solo estorbaría). En cualquier otro
   caso las dos capas se apilan y se leen seguidas, que es exactamente
   lo que la sección era antes. */

.escena-capa {
  min-width: 0;
}

.escena-relevo {
  padding-block: clamp(3.5rem, 3rem + 2vw, 5.5rem) 0;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 1000px) and (min-height: 700px) {
    /* Dentro de la escena el bento es un vistazo, no una lectura: hay
       que meterlo entero en una pantalla o la banda de abajo se queda
       fuera del lienzo (medido: 911px de bento contra 796 de alto útil
       en un portátil de 1280×800). Se aprieta el aire, no el texto. */
    .escena-bento .cabecera-seccion {
      margin-bottom: 1.6rem;
    }

    .escena-bento .cabecera-seccion .entradilla {
      display: none;
    }

    .escena-bento .bento {
      gap: 0.7rem;
    }

    .escena-bento .celda {
      padding: 1.15rem 1.35rem;
      gap: 0.45rem;
    }

    .escena-bento .celda p {
      font-size: 0.875rem;
      line-height: 1.55;
    }

    .escena-bento .celda .motivo {
      padding-top: 0.8rem;
    }

    .escena-bento .motivo-curva svg {
      height: 40px;
    }

    .escena {
      /* 100vh de lienzo + 220vh de recorrido para la coreografía. */
      height: 320vh;
      padding-block: 0;
      view-timeline-name: --escena;
      view-timeline-axis: block;
    }

    .escena-lienzo {
      position: sticky;
      top: 0;
      height: 100vh;
      display: grid;
      align-content: center;
      /* clip y no hidden: no crea contenedor de scroll, y sin él las
         celdas que escapan ensancharían la página. */
      overflow: clip;
    }

    .escena-capa {
      grid-area: 1 / 1;
    }

    .escena-relevo {
      padding-block: 0;
      text-align: center;
      opacity: 0;
      animation: emerger linear both;
      animation-timeline: --escena;
      animation-range: contain 50% contain 88%;
    }

    .escena-relevo .cabecera-seccion {
      margin-bottom: 0;
      margin-inline: auto;
    }

    .escena-relevo .entradilla {
      margin-inline: auto;
    }

    /* Dentro de la escena manda la coreografía, no los reveals: dejar
       el estado oculto de .revela debajo de una animación que hereda su
       valor base es la manera de que algo no aparezca nunca. */
    .escena-bento .cabecera-seccion.revela,
    .escena-bento .cadencia > * {
      opacity: 1;
      transform: none;
      transition: none;
    }

    /* El titular del bento se va primero: abre el camino. */
    .escena-bento .cabecera-seccion {
      animation: escapar linear both;
      animation-timeline: --escena;
      animation-range: contain 4% contain 42%;
      --sale-y: -34vh;
    }

    .escena-bento .celda {
      animation: escapar linear both;
      animation-timeline: --escena;
      animation-range: contain 10% contain 58%;
    }

    /* Cada una por su lado: la de la izquierda por la izquierda, la de
       abajo por abajo, y la del centro hacia quien mira. */
    .escena-bento .celda:nth-child(1) { --sale-x: -72vw; --sale-y: -18vh; }
    .escena-bento .celda:nth-child(2) { --sale-x: 72vw; --sale-y: -18vh; }
    .escena-bento .celda:nth-child(3) { --sale-x: -78vw; animation-range: contain 14% contain 60%; }
    .escena-bento .celda:nth-child(4) { --sale-escala: 1.4; animation-range: contain 20% contain 62%; }
    .escena-bento .celda:nth-child(5) { --sale-x: 78vw; animation-range: contain 14% contain 60%; }
    .escena-bento .celda:nth-child(6) { --sale-y: 82vh; animation-range: contain 8% contain 56%; }

    /* ── Debajo del portátil ──
       La sección sube 100vh y se mete bajo los últimos 100vh de la
       escena del portátil (2a), que la tapa con su pantalla. Mientras
       sube, su lienzo se contrarresta hacia arriba en la misma medida,
       o sea que se queda quieto, como ya fijado: cuando las columnas se
       abren, ella está esperando en el centro, y crece un poco al
       asomar. Todo esto ocurre en su tramo `entry`, que su coreografía
       no usa: sus rangos `contain` quedan exactamente como estaban. */
    html.con-estudio .heroe + .escena {
      margin-top: -100vh;
      /* Una segunda línea de tiempo, sin descontar la barra: la de la
         coreografía (--escena) cuenta con el scroll-padding y así está
         afinada, pero contrarrestar la subida exige que un tramo de
         rango sea exactamente un tramo de scroll. */
      view-timeline-name: --escena, --llegada;
      view-timeline-axis: block, block;
      view-timeline-inset: auto, 0px;
    }

    html.con-estudio .heroe + .escena .escena-lienzo {
      animation: quedarse-debajo linear forwards;
      animation-timeline: --llegada;
      animation-range: entry 0% entry 100%;
    }

    html.con-estudio .heroe + .escena .escena-bento {
      animation: asomar-del-centro var(--ease-suave) both;
      animation-timeline: --llegada;
      animation-range: entry 18% entry 92%;
    }
  }
}

@keyframes quedarse-debajo {
  from {
    transform: translateY(-100vh);
  }

  to {
    transform: none;
  }
}

@keyframes asomar-del-centro {
  from {
    opacity: 0;
    scale: 0.88;
  }
}

/* ── 2c · Los capítulos, en el portátil ───────────────────────────────
   La segunda escena del estudio, con los mismos fotogramas que el héroe
   recorridos al revés: la cámara sale de la pantalla hacia atrás hasta
   ver el portátil de frente sobre la mesa, que se queda a la derecha. En
   su pantalla, los cinco capítulos pasan de derecha a izquierda; el
   texto de cada uno va FUERA, en una columna a la izquierda, sobre el
   fondo de la página.

   Aquí no hay líneas de tiempo en CSS: el recorrido lo cuenta estudio.js
   (qué fotograma, dónde cae, qué capítulo, cuánto se ve de cada texto),
   porque el fotograma, la pantalla y el texto tienen que ir al mismo
   paso. El CSS solo fija el lienzo y coloca las piezas.

   Las pantallas no se pulsan. Ya no hay lupa en ninguna.

   Las mismas guardas que el resto de escenas (líneas de tiempo, sitio y
   movimiento permitido) y además html.con-estudio, que es quien trae los
   fotogramas. Sin todo eso, los capítulos se leen uno debajo de otro con
   su pantalla plana, como siempre. */

.estudio-capitulos {
  display: none;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 1000px) and (min-height: 700px) {
    html.con-estudio .escena-h {
      /* 100vh de lienzo + 370vh de recorrido: la salida de la pantalla y
         los cinco turnos (los tramos, en estudio.js). */
      height: 470vh;
      padding-block: 0;
    }

    html.con-estudio .escena-h-lienzo {
      position: sticky;
      top: 0;
      height: 100vh;
      overflow: clip;
    }

    html.con-estudio .estudio-capitulos {
      display: block;
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
    }

    /* Cada capítulo ocupa el lienzo entero y no pinta nada: sus dos
       piezas se colocan por separado. Los reveals no mandan aquí. */
    html.con-estudio .escena-h .capitulo,
    html.con-estudio .escena-h .capitulo.revela {
      position: absolute;
      inset: 0;
      display: block;
      max-width: none;
      margin: 0;
      padding: 0;
      border-top: 0;
      opacity: 1;
      transform: none;
      transition: none;
      pointer-events: none;
    }

    /* El texto, fuera del portátil: una columna a la izquierda. Su
       opacidad y su deriva las pone estudio.js. */
    /* Alineado con la retícula de la página (el borde de .wrap, donde
       empieza el logotipo), y sin llegar al portátil, que arranca hacia
       el 40 % del ancho. */
    html.con-estudio .escena-h .capitulo-texto {
      --borde: calc(max(0px, (100vw - var(--wrap)) / 2) + clamp(1.25rem, 4vw, 2.5rem));
      position: absolute;
      top: 50%;
      left: var(--borde);
      width: clamp(17rem, calc(38vw - var(--borde)), 27rem);
      translate: 0 -50%;
      opacity: 0;
      visibility: hidden;
      pointer-events: auto;
    }

    html.con-estudio .escena-h .capitulo .numero {
      margin-bottom: 0.7rem;
    }

    html.con-estudio .escena-h .capitulo-texto p {
      margin-top: 0.9rem;
      font-size: 0.9375rem;
    }

    /* La pantalla, dentro del portátil: a un tamaño lógico fijo
       (1440×900, el de la captura del render) en la esquina del lienzo,
       y de ahí la lleva estudio.js al panel con una homografía. */
    html.con-estudio .escena-h .vista {
      --vista-alto: 900px;
      position: absolute;
      top: 0;
      left: 0;
      width: 1440px;
      height: 900px;
      transform-origin: 0 0;
      border-radius: 11px 11px 0 0;
      visibility: hidden;
    }

    html.con-estudio .escena-h .vista-isla {
      border-radius: inherit;
      background-color: var(--bg);
      -webkit-mask-image: none;
      mask-image: none;
    }
  }
}

/* ── 2d · La conexión con el ERP, contada ─────────────────────────────
   La tercera escena del estudio, en «Tus datos entran como tú trabajas».
   Un iPhone flotando se enciende y se pulsa «Conecta tu ERP»; la señal
   sale en ondas de puntos hacia la derecha mientras el iPhone se va por
   la izquierda; entra un portátil, se enciende con el ERP y aparece el
   aviso «Conectando con Lyquia»; el portátil se recoge hacia el centro y
   Odoo, Holded y Sage quedan orbitando entre los puntos, que vibran y se
   apartan a su paso. Al final emerge la plantilla de Excel.

   Como en los capítulos, el recorrido lo cuenta erp.js (y el tiempo, que
   aquí también cuenta: los puntos vibran y las marcas giran aunque no se
   haga scroll). El CSS coloca las piezas y las viste.

   Los dispositivos son renders con fondo transparente
   (_fuente/estudio/dispositivos.py); sus pantallas, HTML, puestas sobre
   el panel con una homografía, como en el héroe. El panel del portátil
   es un ERP genérico con el logotipo de Holded: no copia su interfaz.

   Sin escena, nada de esto se pinta y las dos sendas se leen como
   siempre, con su propia animación (3b). */

.erp-escenario,
.erp-frase {
  display: none;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 1000px) and (min-height: 700px) {
    html.con-estudio #datos {
      padding-bottom: 0;
    }

    html.con-estudio .erp-escena {
      /* 100vh de lienzo + 490vh de recorrido (los tramos, en erp.js): los
         últimos 150vh son de los tres pasos (2e), que se fijan encima. */
      height: 590vh;
      margin-top: clamp(1.5rem, 1rem + 2vw, 3rem);
    }

    html.con-estudio .erp-lienzo {
      position: sticky;
      top: 0;
      height: 100vh;
      overflow: clip;
    }

    html.con-estudio .erp-escenario {
      display: block;
      position: absolute;
      inset: 0;
    }

    html.con-estudio .erp-puntos {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
    }

    /* Los dos dispositivos: centrados, y desde ahí los mueve erp.js. */
    html.con-estudio .erp-movil,
    html.con-estudio .erp-mac {
      position: absolute;
      left: 50%;
      top: 50%;
      visibility: hidden;
    }

    html.con-estudio .erp-movil {
      height: min(80vh, 56vw);
      aspect-ratio: 1200 / 1700;
    }

    html.con-estudio .erp-mac {
      width: min(80vw, 108vh);
      aspect-ratio: 4 / 3;
    }

    html.con-estudio .erp-foto {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
    }

    html.con-estudio .erp-pantalla {
      position: absolute;
      top: 0;
      left: 0;
      transform-origin: 0 0;
      overflow: clip;
    }

    /* Las marcas que orbitan, y la hoja de cálculo. */
    html.con-estudio .erp-logos {
      position: absolute;
      inset: 0;
    }

    html.con-estudio .erp-logo {
      position: absolute;
      left: 0;
      top: 0;
      display: grid;
      place-items: center;
      width: 11.5rem;
      height: 4.6rem;
      margin: -2.3rem 0 0 -5.75rem;
      border-radius: 1.2rem;
      background: rgba(20, 31, 54, 0.72);
      border: 1px solid rgba(255, 255, 255, 0.1);
      box-shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.8), 0 0 36px -10px rgba(40, 202, 190, 0.35);
      backdrop-filter: blur(8px);
      -webkit-backdrop-filter: blur(8px);
      opacity: 0;
    }

    html.con-estudio .erp-logo img {
      height: 1.9rem;
      width: auto;
    }

    /* A la misma altura óptica: Odoo es un logotipo corto y alto, Holded
       uno largo y bajo. */
    html.con-estudio .erp-logo:nth-child(1) img {
      height: 2.7rem;
    }

    html.con-estudio .erp-logo:nth-child(2) img {
      height: 1.35rem;
    }

    html.con-estudio .erp-excel {
      position: absolute;
      left: 50%;
      top: 44%;
      width: min(19vh, 10rem);
      aspect-ratio: 1;
      margin: calc(min(19vh, 10rem) / -2) 0 0 calc(min(19vh, 10rem) / -2);
      filter: drop-shadow(0 22px 40px rgba(29, 138, 82, 0.35));
      opacity: 0;
    }

    html.con-estudio .erp-excel svg {
      display: block;
      width: 100%;
      height: 100%;
    }

    html.con-estudio .erp-frase {
      display: block;
      position: absolute;
      left: 50%;
      top: calc(44% + min(19vh, 10rem) / 2 + 2.2rem);
      width: min(44rem, 88vw);
      translate: -50% 0;
      margin: 0;
      text-align: center;
      font-family: var(--letra-titular);
      font-size: clamp(1.6rem, 1.2rem + 1.5vw, 2.35rem);
      line-height: 1.22;
      color: var(--txt);
      opacity: 0;
    }

    /* Lo que se lee, fuera de la animación: las dos sendas, sin cajas.
       La del ERP, como pie abajo a la izquierda mientras orbitan las
       marcas; la de Excel se queda solo con su descarga, bajo la frase. */
    html.con-estudio .erp-lienzo .sendas {
      display: contents;
    }

    html.con-estudio .erp-lienzo .sendas.cadencia > * {
      transform: none;
      transition: none;
    }

    html.con-estudio .erp-lienzo .senda-excel {
      display: contents;
    }

    html.con-estudio .erp-lienzo .sendas.cadencia > .senda-erp {
      --borde: calc(max(0px, (100vw - var(--wrap)) / 2) + clamp(1.25rem, 4vw, 2.5rem));
      display: block;
      position: absolute;
      left: var(--borde);
      bottom: 8vh;
      width: min(27rem, 34vw);
      padding: 0;
      background: none;
      border: 0;
      box-shadow: none;
      opacity: 0;
      visibility: hidden;
    }

    html.con-estudio .erp-lienzo .senda-erp .conexiones {
      display: none;
    }

    html.con-estudio .erp-lienzo .senda-excel > :not(.descarga) {
      display: none;
    }

    html.con-estudio .erp-lienzo .senda-excel .descarga {
      position: absolute;
      left: 50%;
      top: calc(44% + min(19vh, 10rem) / 2 + 2.2rem + 3.6rem + clamp(1.6rem, 1.2rem + 1.5vw, 2.35rem) * 1.22);
      translate: -50% 0;
      opacity: 0;
      visibility: hidden;
    }
  }
}

/* ── 2e · Los tres pasos, en el mismo mar de puntos ───────────────────
   La continuación de la escena del ERP. Tras el Excel, la cámara se va a
   la derecha por el mismo campo de puntos (el lienzo del ERP, que sigue
   fijado debajo: su escena mide 150vh más por esto) y los puntos generan
   el primer paso como una tarjeta flotante a la derecha, con el titular
   de la sección a la izquierda. La flecha de abajo a la derecha pasa al
   segundo y al tercero, y todo se desplaza a la izquierda; en el tercero,
   la flecha se da la vuelta y vuelve al primero.

   #como sube 250vh y se mete encima de los últimos 250vh de la escena del
   ERP: su lienzo se fija cuando el del ERP va por w = 3,4 y los dos se
   sueltan a la vez. Es transparente y no se queda con los clics (la
   descarga de la plantilla, debajo, sigue pulsándose); solo las tarjetas
   y el mando los reciben. Lo mueve erp.js, con sus mismos tramos.

   Sin escena, los envoltorios no pintan caja, los dibujos y el mando no
   se ven, y los tres pasos son la fila de siempre. */

.pasos-escena,
.pasos-lienzo {
  display: contents;
}

.paso-dibujo,
.pasos-mando {
  display: none;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (min-width: 1000px) and (min-height: 700px) {
    html.con-estudio #como {
      position: relative;
      margin-top: -250vh;
      padding-top: 0;
      border-top: 0;
      pointer-events: none;
      /* «Cómo funciona», en la barra, lleva a la primera tarjeta ya
         hecha (w = 4,35), no al Excel: 95vh más abajo de donde empieza
         la sección, y sin el hueco de la barra, que ya lo pone el
         scroll-padding. */
      scroll-margin-top: calc(-95vh - 92px);
    }

    html.con-estudio .pasos-escena {
      display: block;
      height: 250vh;
    }

    html.con-estudio .pasos-lienzo {
      --borde: calc(max(0px, (100vw - var(--wrap)) / 2) + clamp(1.25rem, 4vw, 2.5rem));
      display: block;
      position: sticky;
      top: 0;
      height: 100vh;
      overflow: clip;
    }

    html.con-estudio #como .wrap {
      display: contents;
    }

    /* El titular, fuera de la animación: a la izquierda, en la retícula
       de la página, como el texto de los capítulos. */
    html.con-estudio #como .cabecera-seccion,
    html.con-estudio #como .cabecera-seccion.revela {
      position: absolute;
      top: 47%;
      left: var(--borde);
      width: min(27rem, calc((100vw - 2 * var(--borde)) * 0.38));
      margin: 0;
      translate: 0 -50%;
      transform: none;
      transition: none;
      opacity: 0;
      visibility: hidden;
    }

    html.con-estudio #como .pasos {
      position: absolute;
      inset: 0;
      display: block;
    }

    html.con-estudio #como .pasos::before,
    html.con-estudio #como .paso::before {
      display: none;
    }

    /* Las tarjetas, flotando sobre los puntos: de cristal, como las
       marcas que orbitan en la escena del ERP. Todas en el mismo sitio
       (--hueco, lo pone erp.js en la retícula); de ahí las desplaza. */
    html.con-estudio #como .paso {
      position: absolute;
      left: var(--hueco, 70%);
      top: 48%;
      width: min(30rem, 36vw);
      translate: -50% -50%;
      padding: 1.8rem 2rem 2.1rem;
      border-radius: var(--radio-l);
      background: rgba(14, 28, 51, 0.74);
      border: 1px solid rgba(255, 255, 255, 0.1);
      box-shadow:
        var(--alza),
        0 34px 70px -34px rgba(0, 0, 0, 0.9),
        0 0 70px -18px rgba(40, 202, 190, 0.32);
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      opacity: 0;
      visibility: hidden;
      pointer-events: auto;
    }

    html.con-estudio #como .paso .numero {
      display: block;
      font-size: 1.5rem;
      line-height: 1;
      letter-spacing: 0.02em;
    }

    html.con-estudio #como .paso p {
      margin-top: 0.7rem;
    }

    /* Cada paso con su dibujo, que se anima al quedarse delante
       (.es-actual, lo pone erp.js). */
    html.con-estudio #como .paso-dibujo {
      display: block;
      position: relative;
      height: 8.75rem;
      margin: 1rem 0 1.4rem;
      border-radius: var(--radio);
      background: rgba(8, 15, 31, 0.6);
      border: 1px solid var(--linea);
      overflow: hidden;
    }

    /* Los dos que son rejilla. (Solo aquí: fuera de la escena, los
       dibujos no se ven.) */
    html.con-estudio #como .paso-dibujo.dibujo-conecta,
    html.con-estudio #como .paso-dibujo.dibujo-decide {
      display: grid;
    }

    html.con-estudio #como .pasos-mando {
      display: flex;
      align-items: center;
      gap: 1.1rem;
      position: absolute;
      right: var(--borde);
      bottom: 8vh;
      opacity: 0;
      visibility: hidden;
      pointer-events: auto;
    }
  }
}

/* 01 · Conecta o sube: el ERP y el Excel entran por tres cables y el
   calendario de caja se monta, mes a mes. */
.dibujo-conecta {
  grid-template-columns: 5rem 1fr 7.4rem;
  align-items: center;
  gap: 0.35rem;
  padding: 0 1.1rem;
}

.dibujo-conecta .fuentes {
  display: grid;
  gap: 0.45rem;
}

.dibujo-conecta .fuente {
  display: grid;
  place-items: center;
  height: 1.9rem;
  border-radius: var(--radio-s);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--linea);
}

.dibujo-conecta .fuente img {
  height: 0.8rem;
  width: auto;
  max-width: 78%;
}

.dibujo-conecta .fuente:first-child img {
  height: 1.05rem;
}

.dibujo-conecta .fuente-excel svg {
  width: 1.1rem;
  height: 1.1rem;
}

.dibujo-conecta .flujo {
  width: 100%;
  height: 6rem;
  overflow: visible;
}

.dibujo-conecta .flujo path {
  fill: none;
  stroke: var(--linea-cyan);
  stroke-width: 1.5;
  stroke-dasharray: 2 5;
  vector-effect: non-scaling-stroke;
}

.dibujo-conecta .calendario {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.35rem;
}

.dibujo-conecta .calendario i {
  height: 2.6rem;
  border-radius: 0.4rem;
  border: 1px solid rgba(40, 202, 190, 0.45);
  background: linear-gradient(rgba(40, 202, 190, 0.16), rgba(40, 202, 190, 0.04));
  color: var(--cyan);
  opacity: 0;
  transform: translateY(6px) scale(0.9);
  transition:
    opacity 400ms var(--ease-suave) calc(var(--turno) * 90ms + 300ms),
    transform 500ms var(--ease-asentar) calc(var(--turno) * 90ms + 300ms);
}

.dibujo-conecta .calendario i::before {
  content: '';
  display: block;
  margin: 0.45rem 0.4rem 0;
  height: 3px;
  border-radius: 2px;
  background: currentColor;
  box-shadow: 0 7px 0 rgba(255, 255, 255, 0.14), 0 14px 0 rgba(255, 255, 255, 0.14);
}

.dibujo-conecta .calendario i.rojo {
  border-color: rgba(242, 126, 107, 0.6);
  background: linear-gradient(rgba(242, 126, 107, 0.2), rgba(242, 126, 107, 0.05));
  color: var(--rojo-cursor);
}

.paso.es-actual .dibujo-conecta .calendario i {
  opacity: 1;
  transform: none;
}

/* 02 · Ve lo que viene: la caja de los próximos 12 meses se dibuja y
   el punto de rotura se enciende donde cruza el cero. */
.dibujo-ve .curva {
  position: absolute;
  left: 0.9rem;
  top: 1.5rem;
  width: calc(100% - 1.8rem);
  height: auto;
  overflow: visible;
}

.dibujo-ve .cero {
  fill: none;
  stroke: rgba(255, 255, 255, 0.2);
  stroke-dasharray: 4 5;
}

.dibujo-ve .area {
  fill: rgba(40, 202, 190, 0.07);
}

.dibujo-ve .linea {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1300ms var(--ease-suave) 250ms;
}

.dibujo-ve .rotura {
  fill: var(--rojo-cursor);
  stroke: rgba(242, 126, 107, 0.35);
  stroke-width: 8;
  paint-order: stroke;
  transform-box: fill-box;
  transform-origin: center;
  opacity: 0;
  transform: scale(0.3);
  transition:
    opacity 300ms var(--ease-suave) 750ms,
    transform 500ms var(--ease-asentar) 750ms;
}

.dibujo-ve .rotulo-rotura {
  position: absolute;
  top: 0.55rem;
  right: 0.9rem;
  font-size: 0.6875rem;
  color: var(--mut);
  opacity: 0;
  transition: opacity 400ms var(--ease-suave) 900ms;
}

.dibujo-ve .rotulo-rotura b {
  font-weight: 500;
  color: var(--rojo-cursor);
}

.dibujo-ve .meses {
  position: absolute;
  left: 0.9rem;
  right: 0.9rem;
  bottom: 0.5rem;
  font-size: 0.5625rem;
  letter-spacing: 0.02em;
  color: var(--mut);
  text-align: center;
  white-space: nowrap;
}

.paso.es-actual .dibujo-ve .linea {
  stroke-dashoffset: 0;
}

.paso.es-actual .dibujo-ve .rotura {
  opacity: 1;
  transform: none;
}

.paso.es-actual .dibujo-ve .rotulo-rotura {
  opacity: 1;
}

/* 03 · Decide con datos: tres movimientos, cada uno con su coste, se
   marcan uno tras otro y el plan queda en positivo. */
.dibujo-decide {
  align-content: center;
  gap: 0.3rem;
  padding: 0.6rem 0.9rem;
}

.dibujo-decide .accion {
  display: grid;
  grid-template-columns: 0.95rem 1fr auto;
  align-items: center;
  gap: 0.6rem;
  padding: 0.22rem 0.6rem;
  border-radius: var(--radio-s);
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--linea);
  font-size: 0.71875rem;
  line-height: 1.35;
  color: var(--txt);
  opacity: 0;
  transform: translateX(10px);
  transition:
    opacity 400ms var(--ease-suave) calc(var(--turno) * 220ms + 250ms),
    transform 500ms var(--ease-asentar) calc(var(--turno) * 220ms + 250ms);
}

.dibujo-decide .accion b {
  font-weight: 500;
  color: var(--cyan-l);
}

.dibujo-decide .accion i {
  position: relative;
  width: 0.95rem;
  height: 0.95rem;
  border-radius: 50%;
  border: 1.5px solid var(--linea-cyan);
  transition:
    background-color 250ms var(--ease-suave) calc(var(--turno) * 220ms + 550ms),
    border-color 250ms var(--ease-suave) calc(var(--turno) * 220ms + 550ms);
}

.dibujo-decide .accion i::after {
  content: '';
  position: absolute;
  left: 0.26rem;
  top: 0.12rem;
  width: 0.22rem;
  height: 0.42rem;
  border: solid var(--tinta-boton);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg) scale(0);
  transition: transform 250ms var(--ease-asentar) calc(var(--turno) * 220ms + 600ms);
}

.dibujo-decide .resultado {
  justify-self: start;
  margin-top: 0.15rem;
  padding-left: 0.2rem;
  font-size: 0.6875rem;
  letter-spacing: 0.03em;
  color: var(--cyan);
  opacity: 0;
  transition: opacity 400ms var(--ease-suave) calc(var(--turno) * 220ms + 500ms);
}

.paso.es-actual .dibujo-decide .accion {
  opacity: 1;
  transform: none;
}

.paso.es-actual .dibujo-decide .accion i {
  background-color: var(--cyan);
  border-color: var(--cyan);
}

.paso.es-actual .dibujo-decide .accion i::after {
  transform: rotate(45deg) scale(1);
}

.paso.es-actual .dibujo-decide .resultado {
  opacity: 1;
}

/* El mando: la cuenta y la flecha, con un aro que dice cuánto queda. */
.pasos-cuenta {
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  color: var(--mut);
}

.pasos-cuenta b {
  font-weight: 500;
  color: var(--txt);
}

.pasos-siguiente {
  position: relative;
  display: grid;
  place-items: center;
  width: 3.75rem;
  height: 3.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(40, 202, 190, 0.1);
  box-shadow: inset 0 0 0 1px rgba(40, 202, 190, 0.2), 0 0 40px -8px rgba(40, 202, 190, 0.35);
  color: var(--cyan-l);
  cursor: pointer;
  transition:
    background-color var(--dur-cerca) var(--ease-suave),
    color var(--dur-cerca) var(--ease-suave),
    transform var(--dur-cerca) var(--ease-asentar);
}

.pasos-siguiente:hover {
  background-color: var(--cyan);
  color: var(--tinta-boton);
}

.pasos-siguiente:active {
  transform: scale(0.94);
}

.pasos-siguiente:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 4px;
}

.pasos-siguiente .aro {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.pasos-siguiente .aro circle {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 1.5;
  stroke-dasharray: 1;
  stroke-dashoffset: calc(1 - var(--avance, 0.3333));
  transition: stroke-dashoffset var(--dur-focal) var(--ease-asentar);
}

.pasos-siguiente .flecha {
  width: 1.4rem;
  height: 1.4rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform var(--dur-panel) var(--ease-asentar);
}

.pasos-siguiente.vuelve .flecha {
  transform: rotate(180deg);
}

/* ── Las pantallas de los dispositivos ────────────────────────────────
   A su tamaño lógico (el iPhone, 390×844; el portátil, 1440×900), y de
   ahí las lleva erp.js a su sitio. Solo se pintan dentro de la escena. */

.erp-pantalla-movil {
  width: 390px;
  height: 844px;
  border-radius: 55px;
}

.movil-app {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: inherit;
  background:
    radial-gradient(120% 70% at 50% 0%, rgba(40, 202, 190, 0.22), transparent 60%),
    linear-gradient(180deg, #0b1628, #080f1f 70%);
  color: #fff;
  font-family: var(--letra-cuerpo);
}

.movil-estado {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 18px 34px 0 42px;
  font-size: 16px;
  font-weight: 500;
}

.movil-iconos {
  display: flex;
  gap: 6px;
}

.movil-iconos i {
  display: block;
  width: 17px;
  height: 11px;
  border-radius: 3px;
  background: #fff;
  opacity: 0.9;
}

.movil-iconos i:first-child {
  width: 14px;
  opacity: 0.8;
}

.movil-isla {
  position: absolute;
  top: 11px;
  left: 50%;
  width: 124px;
  height: 36px;
  margin-left: -62px;
  border-radius: 20px;
  background: #000;
}

.movil-cuerpo {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 150px 34px 0;
  text-align: center;
}

.movil-icono {
  width: 96px;
  height: 96px;
  border-radius: 22px;
  box-shadow: 0 16px 40px -12px rgba(40, 202, 190, 0.55);
}

.movil-titulo {
  margin-top: 38px;
  font-family: var(--letra-titular);
  font-size: 36px;
  line-height: 1.15;
}

.movil-texto {
  margin-top: 18px;
  font-size: 17px;
  line-height: 1.45;
  color: rgba(255, 255, 255, 0.7);
}

.movil-boton {
  position: relative;
  overflow: hidden;
  margin-top: 70px;
  width: 300px;
  padding: 20px 0;
  border-radius: 18px;
  background: var(--cyan, #28cabe);
  color: #04121f;
  font-size: 19px;
  font-weight: 600;
  box-shadow: 0 18px 40px -16px rgba(40, 202, 190, 0.8);
}

.movil-toque {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 60px;
  height: 60px;
  margin: -30px 0 0 -30px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.55);
  opacity: 0;
  transform: scale(0.2);
}

.movil-casa {
  position: absolute;
  bottom: 9px;
  left: 50%;
  width: 136px;
  height: 5px;
  margin-left: -68px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.75);
}

/* El ERP del portátil: un panel genérico, claro, con la marca de Holded
   en una barra oscura (su logotipo es blanco y rojo). */
.erp-pantalla-mac {
  width: 1440px;
  height: 900px;
  border-radius: 11px 11px 0 0;
}

.erp-app {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  background: #f3f5f8;
  color: #1c2433;
  font-family: var(--letra-cuerpo);
  font-size: 15px;
}

.erp-barra {
  display: flex;
  align-items: center;
  gap: 40px;
  height: 66px;
  padding: 0 30px;
  background: #151b27;
  color: rgba(255, 255, 255, 0.7);
}

.erp-marca {
  height: 24px;
  width: auto;
}

.erp-nav {
  display: flex;
  gap: 30px;
  font-size: 15px;
}

.erp-nav b {
  color: #fff;
  font-weight: 600;
}

.erp-empresa {
  margin-left: auto;
  font-size: 14px;
}

.erp-avatar {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #ef4444;
  color: #fff;
  font-size: 13px;
  font-weight: 600;
}

.erp-cuerpo {
  display: flex;
  flex: 1;
  min-height: 0;
}

.erp-menu {
  display: flex;
  flex-direction: column;
  gap: 26px;
  width: 72px;
  padding-top: 28px;
  align-items: center;
  background: #fff;
  border-right: 1px solid #e3e7ee;
}

.erp-menu i {
  display: block;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: #d9dee8;
}

.erp-menu i:first-child {
  background: #ef4444;
}

.erp-panel {
  flex: 1;
  padding: 30px 36px;
}

.erp-titulo {
  font-size: 26px;
  font-weight: 600;
}

.erp-titulo span {
  color: #7a8599;
  font-weight: 400;
}

.erp-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 18px;
  margin-top: 24px;
}

.erp-kpis > div,
.erp-grafica,
.erp-facturas {
  padding: 20px 22px;
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(20, 27, 40, 0.06), 0 8px 24px -16px rgba(20, 27, 40, 0.25);
}

.erp-kpis span,
.erp-rotulo {
  display: block;
  color: #7a8599;
  font-size: 14px;
}

.erp-kpis b {
  display: block;
  margin-top: 8px;
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.erp-kpis em {
  display: inline-block;
  margin-top: 8px;
  font-style: normal;
  font-size: 13px;
  color: #7a8599;
}

.erp-kpis em.sube {
  color: #16a34a;
}

.erp-kpis em.baja {
  color: #dc2626;
}

.erp-fila {
  display: grid;
  grid-template-columns: 1.25fr 1fr;
  gap: 18px;
  margin-top: 18px;
}

.erp-barras {
  display: flex;
  align-items: flex-end;
  gap: 14px;
  height: 330px;
  margin-top: 22px;
  padding-bottom: 6px;
  border-bottom: 1px solid #e3e7ee;
}

.erp-barras i {
  position: relative;
  flex: 1;
  height: 100%;
}

.erp-barras i::before,
.erp-barras i::after {
  content: '';
  position: absolute;
  bottom: 0;
  width: 46%;
  border-radius: 5px 5px 0 0;
}

.erp-barras i::before {
  left: 0;
  height: calc(var(--v) * 100%);
  background: #ef4444;
}

.erp-barras i::after {
  right: 0;
  height: calc(var(--g) * 100%);
  background: #cbd2de;
}

.erp-factura {
  display: grid;
  grid-template-columns: 110px 1fr auto 104px;
  gap: 12px;
  align-items: center;
  padding: 15px 0;
  border-bottom: 1px solid #eef1f5;
  font-size: 14px;
}

.erp-factura:last-child {
  border-bottom: 0;
}

.erp-factura span:first-child {
  color: #7a8599;
}

.erp-factura b {
  font-weight: 600;
}

.erp-factura em {
  justify-self: end;
  padding: 4px 10px;
  border-radius: 999px;
  font-style: normal;
  font-size: 12px;
  font-weight: 600;
}

.erp-factura em.pagada {
  background: #dcfce7;
  color: #15803d;
}

.erp-factura em.vence {
  background: #fef3c7;
  color: #b45309;
}

.erp-factura em.vencida {
  background: #fee2e2;
  color: #b91c1c;
}

/* El aviso blanco: «Conectando con Lyquia». */
.erp-aviso {
  position: absolute;
  left: 50%;
  top: 290px;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  column-gap: 20px;
  width: 640px;
  margin-left: -320px;
  padding: 30px 34px 26px;
  border-radius: 22px;
  background: #fff;
  color: #0b1628;
  box-shadow: 0 40px 90px -30px rgba(8, 15, 31, 0.65), 0 0 0 1px rgba(8, 15, 31, 0.06);
  font-family: var(--letra-cuerpo);
  opacity: 0;
}

.erp-aviso img {
  width: 56px;
  height: 56px;
  border-radius: 14px;
}

.erp-aviso-texto {
  font-size: 27px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.erp-aviso-texto small {
  display: block;
  margin-top: 4px;
  font-size: 15px;
  font-weight: 400;
  color: #5b6577;
}

.erp-progreso {
  grid-column: 1 / -1;
  display: block;
  height: 6px;
  margin-top: 22px;
  border-radius: 3px;
  background: #e6ebf2;
  overflow: hidden;
}

.erp-progreso i {
  display: block;
  width: calc(var(--p, 0) * 100%);
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #28cabe, #5fe3d7);
}

@keyframes escapar {
  to {
    opacity: 0;
    transform: translate(var(--sale-x, 0), var(--sale-y, 0)) scale(var(--sale-escala, 1));
  }
}

@keyframes emerger {
  from {
    opacity: 0;
    transform: scale(0.82);
  }

  60% {
    opacity: 1;
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* ── 3 · El scroll trae contenido (reveals, una sola vez) ───────────── */

@media (prefers-reduced-motion: no-preference) {
  html.con-js .revela {
    opacity: 0;
    transform: translateY(14px);
    transition:
      opacity var(--dur-focal) var(--ease-revelar),
      transform var(--dur-focal) var(--ease-revelar);
  }

  html.con-js .revela.es-visible {
    opacity: 1;
    transform: none;
  }

  /* Cadencia en rejillas: los hijos llegan en oleada corta (tope 5). */
  html.con-js .cadencia > * {
    opacity: 0;
    transform: translateY(14px);
    transition:
      opacity var(--dur-focal) var(--ease-revelar),
      transform var(--dur-focal) var(--ease-revelar);
  }

  html.con-js .cadencia.es-visible > * {
    opacity: 1;
    transform: none;
  }

  html.con-js .cadencia.es-visible > :nth-child(2) { transition-delay: 60ms; }
  html.con-js .cadencia.es-visible > :nth-child(3) { transition-delay: 120ms; }
  html.con-js .cadencia.es-visible > :nth-child(4) { transition-delay: 180ms; }
  html.con-js .cadencia.es-visible > :nth-child(5) { transition-delay: 240ms; }
  html.con-js .cadencia.es-visible > :nth-child(n + 6) { transition-delay: 300ms; }

  /* El eje de los pasos se dibuja de izquierda a derecha al revelarse. */
  html.con-js .pasos::before {
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 900ms ease-in-out 120ms;
  }

  html.con-js .pasos.es-visible::before {
    transform: scaleX(1);
  }
}

/* ── 3b · La secuencia de las dos sendas, en dos actos ────────────────
   Primero se cuenta el ERP, con la tarjeta sola en el centro: una
   clavija recorre su cable y enciende el sistema, por turnos. Cuando
   los tres están conectados, esa tarjeta CEDE EL SITIO —se desplaza a
   su mitad— y entra por la derecha la del Excel, que cuenta lo suyo: el
   libro llega, la barra avanza y aparecen las columnas reconocidas.

   Todo el compás vive en las cinco variables de abajo. Para que la
   secuencia entera vaya más rápida o más lenta se tocan ahí y en un
   solo sitio, no en catorce reglas.

   Como el resto de la casa: el estado apagado vive SOLO bajo html.con-js
   y movimiento permitido. Sin JS o con reduced-motion, las dos tarjetas
   están en su sitio, los sistemas conectados y el Excel leído desde el
   primer instante — que es el final de la historia, no un fallo. */

.sendas {
  --sec-base: 320ms;    /* cuándo arranca la primera clavija */
  --sec-viaje: 1000ms;  /* lo que tarda una clavija en llegar */
  --sec-paso: 1040ms;   /* de una conexión a la siguiente */
  --sec-relevo: 3750ms; /* cuándo el ERP cede el sitio */
  --sec-excel: 4350ms;  /* cuándo arranca el importador */
}

@media (prefers-reduced-motion: no-preference) {
  html.con-js .sendas .corriente {
    transform: scaleX(0);
  }

  html.con-js .sendas .clavija {
    transform: translateX(calc(-1 * var(--cable)));
  }

  html.con-js .sendas .conexion img {
    filter: grayscale(1) brightness(1.7);
    opacity: 0.45;
  }

  html.con-js .sendas .conexion--otros,
  html.con-js .sendas .importador .libro,
  html.con-js .sendas .importador .leido,
  html.con-js .sendas .importador .columnas li {
    opacity: 0;
  }

  html.con-js .sendas .progreso i {
    transform: scaleX(0);
  }

  /* ACTO 1 · las tres conexiones, una detrás de otra. */
  html.con-js .sendas.es-visible .clavija {
    animation: enchufar var(--sec-viaje) var(--ease-asentar)
      calc(var(--sec-base) + var(--turno) * var(--sec-paso)) both;
  }

  html.con-js .sendas.es-visible .corriente {
    animation: dar-corriente var(--sec-viaje) var(--ease-asentar)
      calc(var(--sec-base) + var(--turno) * var(--sec-paso)) both;
  }

  html.con-js .sendas.es-visible .conexion img {
    animation: encender 520ms var(--ease-asentar)
      calc(var(--sec-base) + var(--turno) * var(--sec-paso) + 780ms) both;
  }

  html.con-js .sendas.es-visible .conexion--otros {
    animation: fundir 600ms var(--ease-suave)
      calc(var(--sec-base) + var(--turno) * var(--sec-paso)) both;
  }

  /* ACTO 2 · el relevo y el importador. */
  html.con-js .sendas.es-visible .senda-excel {
    animation: entrar-por-la-derecha 1100ms var(--ease-asentar) var(--sec-relevo) both;
  }

  html.con-js .sendas.es-visible .importador .libro {
    animation: caer 760ms var(--ease-asentar) var(--sec-excel) both;
  }

  html.con-js .sendas.es-visible .progreso i {
    animation: llenar 1500ms var(--ease-suave) calc(var(--sec-excel) + 620ms) both;
  }

  html.con-js .sendas.es-visible .importador .leido {
    animation: fundir 460ms var(--ease-suave) calc(var(--sec-excel) + 2160ms) both;
  }

  html.con-js .sendas.es-visible .columnas li {
    animation: asomar 460ms var(--ease-asentar)
      calc(var(--sec-excel) + 2300ms + var(--turno) * 140ms) both;
  }

  /* El desplazamiento solo tiene sentido con las dos tarjetas en fila:
     en una sola columna no hay sitio que ceder, y mover media anchura
     sacaría la tarjeta de la pantalla. */
  @media (min-width: 880px) {
    html.con-js .sendas .senda-erp {
      transform: translateX(calc(50% + 0.45rem));
    }

    html.con-js .sendas.es-visible .senda-erp {
      animation: ceder-el-sitio 1100ms var(--ease-asentar) var(--sec-relevo) both;
    }
  }
}

@keyframes ceder-el-sitio {
  from {
    transform: translateX(calc(50% + 0.45rem));
  }

  to {
    transform: none;
  }
}

@keyframes entrar-por-la-derecha {
  from {
    opacity: 0;
    transform: translateX(26%);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes enchufar {
  from {
    transform: translateX(calc(-1 * var(--cable)));
  }

  to {
    transform: none;
  }
}

@keyframes dar-corriente {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}

@keyframes encender {
  0% {
    filter: grayscale(1) brightness(1.7);
    opacity: 0.45;
    transform: scale(0.97);
  }

  55% {
    transform: scale(1.035);
  }

  100% {
    filter: none;
    opacity: 1;
    transform: none;
  }
}

@keyframes caer {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes llenar {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}

@keyframes asomar {
  from {
    opacity: 0;
    transform: translateY(6px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* ── 4 · Hovers: solo donde hay ratón de verdad ─────────────────────── */

@media (hover: hover) and (pointer: fine) {
  .celda:hover {
    background: var(--card-alta);
    border-color: var(--linea-fuerte);
  }

  @media (prefers-reduced-motion: no-preference) {
    .celda,
    .senda,
    .plan {
      transition:
        background-color var(--dur-cerca) var(--ease-asentar),
        border-color var(--dur-cerca) var(--ease-asentar),
        transform var(--dur-cerca) var(--ease-asentar),
        box-shadow var(--dur-cerca) var(--ease-asentar);
    }

    .celda:hover,
    .senda:hover,
    .plan:hover {
      transform: translateY(-2px);
    }
  }
}

/* La pulsación baja más rápido de lo que subió. */
@media (prefers-reduced-motion: no-preference) {
  .boton {
    transition:
      background-color var(--dur-cerca) var(--ease-suave),
      border-color var(--dur-cerca) var(--ease-suave),
      color var(--dur-cerca) var(--ease-suave),
      transform var(--dur-toque) var(--ease-suave);
  }

  .boton:active {
    transform: scale(0.97);
  }
}

/* ── 5 · Las preguntas se despliegan como agua (mejora progresiva) ──── */

@supports (interpolate-size: allow-keywords) {
  @media (prefers-reduced-motion: no-preference) {
    .preguntas details::details-content {
      block-size: 0;
      overflow-y: clip;
      opacity: 0;
      transition:
        block-size var(--dur-panel) var(--ease-asentar),
        opacity var(--dur-panel) var(--ease-suave),
        content-visibility var(--dur-panel) allow-discrete;
    }

    .preguntas details[open]::details-content {
      block-size: auto;
      opacity: 1;
      interpolate-size: allow-keywords;
    }
  }
}

/* ── Movimiento reducido: menos y más suave, no cero ─────────────────
   Mueren los desplazamientos, el trazado y las transiciones de página;
   sobreviven el color y la opacidad de hovers y foco. Todas las
   animaciones espaciales de esta hoja ya viven detrás de la guarda
   no-preference; aquí se apaga lo que quedaba. */

@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }

  html {
    scroll-behavior: auto;
  }
}

/* ── Impresión ──────────────────────────────────────────────────────── */

@media print {
  .barra,
  .curva-caja,
  .curva-calma,
  .vista,
  body::after {
    display: none;
  }

  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }

  body {
    background: #fff;
    color: #000;
  }

  body,
  .prosa p,
  .prosa li,
  p {
    --texto: #000;
    --texto-suave: #333;
    color: #000;
  }

  .pagina-interior main {
    padding-top: 2rem;
  }
}
