/* ============================================================================
   myvigia — LANDING "LA PELÍCULA" · capa cinematográfica (art direction v2.2)
   ----------------------------------------------------------------------------
   Se carga DESPUÉS de landing.css. Contiene: hero NOVA (hebras de luz + display
   gigante), chrome editorial-instrumento (contadores, marcadores, hairlines),
   grano + viñeta, el DISPOSITIVO QUE SE VOLTEA (acto 3), el acto propose-confirm
   (acto 4) y el aterrizaje editorial. Todo cuelga de tokens Atalaya (Iris/Pulso
   sobre dusk). El wow es LUZ + MOVIMIENTO + composición, no colores nuevos.

   Reglas duras: transforms/opacity para animar; overflow:clip (nunca hidden)
   sobre sticky; reduced-motion = versión editorial legible; touch sin cursor.
   ============================================================================ */

/* ── Grano feTurbulence 2-3% + viñeta sutilísima (fijos sobre la película) ── */
.lp-grain {
  position: fixed; inset: 0; z-index: 91; pointer-events: none;
  opacity: .035; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.lp-vignette {
  position: fixed; inset: 0; z-index: 90; pointer-events: none;
  background: radial-gradient(130% 100% at 50% 42%, transparent 58%, rgba(0,0,0,.34) 100%);
}

/* Selección Iris (detalle de marca) */
.lp ::selection { background: color-mix(in srgb, var(--brand) 42%, transparent); color: var(--text-strong); }

/* ══════════════════════════════════════════════════════════════════════════
   ACTO 1 · HERO NOVA — hebras de luz + display gigante abajo-izquierda
   El hero deja de ser grid izq/dcha. Es un lienzo a viewport completo con el
   texto colgado abajo-izquierda y la escena viviendo detrás/derecha.
   Se SOBREESCRIBE la .lp-hero de landing.css.
   ══════════════════════════════════════════════════════════════════════════ */
.lp-hero {
  position: relative; isolation: isolate;
  min-height: 100svh; min-height: 100vh;
  display: flex; flex-direction: column;
  padding: 0 !important; overflow: clip;
  background: var(--canvas);
}
/* Se anulan los adornos del hero viejo (rejilla + gradientes de landing.css) */
.lp-hero::after { content: none; }
.lp-hero::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background:
    radial-gradient(1100px 720px at 74% 22%, color-mix(in srgb, var(--brand) 14%, transparent), transparent 62%),
    radial-gradient(760px 520px at 60% 8%, color-mix(in srgb, var(--accent) 8%, transparent), transparent 64%);
}
.lp-scene { position: absolute; inset: 0; z-index: -1; pointer-events: none; overflow: clip; }
/* El canvas nace invisible (el ::before del hero pinta el mismo fondo) y se
   funde cuando el motor presenta su primer frame con bloom (.is-live). Así el
   init diferido no produce pop y el LCP del H1 nunca espera al WebGL. */
.lp-scene canvas {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  opacity: 0; transition: opacity 1.1s var(--ease);
}
.lp-scene.is-live canvas { opacity: 1; }

.lp-hero-wrap {
  position: relative; z-index: 2;
  width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 24px;
  flex: 1; display: flex; flex-direction: column; justify-content: flex-end;
  padding-top: 84px; padding-bottom: clamp(20px, 3.5vh, 44px);
}
.lp-hero-top { margin-bottom: auto; padding-top: clamp(16px, 4vh, 48px); }

/* Display GIGANTE, alineado abajo-izquierda, mezcla de pesos + itálica.
   v6 «Una vuelta»: cuatro líneas, y la más larga —ENTRA UNA ACTUACIÓN.— mide
   11,4 em. La escala baja lo justo para que NINGUNA línea (nowrap) desborde
   ni invada la columna de salida: verificado a 320, 375, 1024, 1280 y 1990. */
.lp-hero-display { max-width: 720px; }
.lp-display { max-width: 20ch; }   /* solo el titular se estrecha; el lead respira */
.lp-display {
  font-family: var(--font-sans);
  font-size: clamp(1.72rem, 3.05vw + 1.16rem, 4.2rem);
  line-height: .98; letter-spacing: -.045em; font-weight: 300;
  color: var(--text-strong); margin: 0 0 20px;
}
/* Cada línea es su propia máscara vertical. Clip SOLO vertical: se deja aire
   horizontal (padding) para no cortar itálicas ni el trazo del glow. */
.lp-display .ln {
  display: block; overflow-y: clip; overflow-x: visible;
  white-space: nowrap; padding: .04em 0;
}
.lp-display .ln .i { display: inline-block; }
.lp-display b { font-weight: 760; }
.lp-display em {
  font-style: italic; font-weight: 400;
  color: var(--brand-text); padding: 0 .06em;
}
.lp-display .slash { color: var(--accent); font-weight: 300; font-style: normal; opacity: .85; margin-left: .04em; }

/* Revelado por línea (máscara que sube). Se dispara con .lp-in (JS/CSS). */
.lp-display .ln .i { transform: translateY(118%); opacity: 0; }
.lp-in .lp-display .ln .i {
  transform: none; opacity: 1;
  transition: transform 1s var(--ease-emph), opacity .8s var(--ease);
}
.lp-in .lp-display .ln:nth-child(1) .i { transition-delay: .05s; }
.lp-in .lp-display .ln:nth-child(2) .i { transition-delay: .16s; }
.lp-in .lp-display .ln:nth-child(3) .i { transition-delay: .27s; }
.lp-in .lp-display .ln:nth-child(4) .i { transition-delay: .38s; }

.lp-hero-display .lead { max-width: 54ch; margin-bottom: 22px; color: var(--text-muted); font-size: clamp(.97rem, 1.42vw, 1.08rem); }
.lp-hero-cta { display: flex; flex-wrap: wrap; gap: 14px; }

.lp-hero-foot {
  margin-top: clamp(28px, 6vh, 64px);
  display: flex; align-items: flex-end; justify-content: space-between; gap: 20px;
  border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
  padding-top: 18px;
}
.lp-hero-trust {
  margin: 0; display: flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .02em;
  color: var(--text-subtle); text-transform: none;
}
.lp-hero-trust svg { width: 14px; height: 14px; color: var(--brand); flex-shrink: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   LA SALIDA · el hilo y la ficha
   Una vez por vuelta del barrido (~12 s) la aguja cruza el nodo designado. De
   ahí sale un hilo de 1px con dos quiebres en ángulo recto —trazo de
   instrumento— y donde muere se imprime la ficha: qué llegó, el escrito
   insinuado con su cita anclada y el término con el sello de revisión.

   REGLA DE ORO DE ESTE BLOQUE: el estado por defecto es la ficha IMPRESA y
   completa —así la leen el papel, el sin-JS, el móvil y el lite sin un solo
   frame de animación—. Donde SÍ cabe película (≥941px y con motion) la ficha
   nace vacía por media query, para no enseñarla antes de que el JS decida; y
   las transiciones solo existen bajo .sal-cine, que pone landing-salida.js.
   ══════════════════════════════════════════════════════════════════════════ */

/* El hilo: hermano del canvas y en SUS MISMAS coordenadas (sin viewBox, una
   unidad de usuario = 1 px CSS). Solo existe en modo cine. */
.lp-hilo { display: none; }
.lp-hero.sal-cine .lp-hilo {
  display: block; position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 1; pointer-events: none; overflow: visible;
}
/* Cada segmento crece desde su origen con transform (jamás stroke-dashoffset):
   el horizontal escala en x y el vertical en y, así el trazo nunca engorda.
   El JS pone la geometría y el transform-origin de cada uno. */
.lp-hilo .sg {
  stroke: var(--accent); stroke-width: 1; stroke-linecap: butt;
  opacity: .9; transform-box: view-box; transform-origin: 0 0;
  transition: transform .26s var(--ease);
}
.lp-hilo .sg.s1, .lp-hilo .sg.s3 { transform: scaleX(0); }   /* horizontales */
.lp-hilo .sg.s2 { transform: scaleY(0); }                    /* vertical */
.lp-hero.sal-on .lp-hilo .sg.s1 { transform: scaleX(1); transition-delay: 0s; }
.lp-hero.sal-on .lp-hilo .sg.s2 { transform: scaleY(1); transition-delay: .2s; }
.lp-hero.sal-on .lp-hilo .sg.s3 { transform: scaleX(1); transition-delay: .37s; }
/* Se retrae en orden inverso: primero suelta la ficha, al final el nodo. */
.lp-hero.sal-out .lp-hilo .sg.s3 { transition-delay: .26s; }
.lp-hero.sal-out .lp-hilo .sg.s2 { transition-delay: .42s; }
.lp-hero.sal-out .lp-hilo .sg.s1 { transition-delay: .58s; }

/* La columna de salida: pegada al borde derecho de la columna de contenido,
   arriba del disco. Nunca cruza la caja del titular. */
.lp-salida {
  position: absolute; z-index: 3;
  top: clamp(88px, 12.5vh, 150px); right: 24px;
  width: clamp(268px, 26vw, 344px);
}
.lp-ficha {
  position: relative; display: grid; gap: 11px;
  padding: 13px 14px 11px;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  box-shadow: 0 18px 46px rgba(0, 0, 0, .40);
  transform-origin: 0 0;
}
/* Esquina de instrumento: una sola marca, arriba-izquierda. */
.lp-ficha::before {
  content: ""; position: absolute; top: -1px; left: -1px; width: 13px; height: 13px;
  border-top: 1px solid var(--accent); border-left: 1px solid var(--accent);
  opacity: .55;
}

/* Máscara de revelado, la misma del titular (clase propia: .ln ya es el
   enlace de acento de landing.css). En reposo NO transforma nada. */
.lp-ficha .mk { display: block; overflow-y: clip; overflow-x: visible; }
.lp-ficha .mk .i { display: block; }

.lp-ficha-top { display: grid; gap: 3px; }
.lp-ficha .rad {
  display: block; font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .01em; color: var(--brand-text); font-variant-numeric: tabular-nums;
}
.lp-ficha .act {
  display: block; font-size: 12.5px; line-height: 1.32; font-weight: 560;
  color: var(--text-strong);
}

.lp-ficha-cuerpo {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px;
  align-items: center;
  border-top: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  padding-top: 11px;
}
/* El escrito insinuado: 5 renglones hairline, ancho y opacidad escalonados.
   Cada uno vive en una caja de 8px para que la máscara tenga recorrido. */
.lp-ficha-esc { display: grid; gap: 1px; }
.lp-ficha-esc .mk { height: 8px; }
.lp-ficha-esc .mk .i { height: 8px; padding-top: 7px; }
.lp-ficha-esc .rg { display: block; height: 1px; background: var(--text-muted); }
.lp-ficha-esc .mk:nth-child(1) .rg { width: 100%; opacity: .62; }
.lp-ficha-esc .mk:nth-child(2) .rg { width: 93%;  opacity: .52; }
.lp-ficha-esc .mk:nth-child(3) .rg { width: 97%;  opacity: .44; }
.lp-ficha-esc .mk:nth-child(4) .rg { width: 88%;  opacity: .36; }
.lp-ficha-esc .mk:nth-child(5) .rg { width: 54%;  opacity: .28; }

/* La cita, anclada al margen del escrito por una llave de 1px. */
.lp-ficha-cita { position: relative; padding-left: 11px; }
.lp-ficha-cita .llave {
  position: absolute; left: 0; top: 3px; bottom: 3px; width: 5px;
  border: 1px solid color-mix(in srgb, var(--border-strong) 90%, transparent);
  border-right: 0;
}
.lp-ficha .chip {
  display: inline-block; font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .02em; padding: 3px 8px; border-radius: var(--r-full);
  background: var(--brand-tint); color: var(--brand-text);
  border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
  white-space: nowrap;
}

.lp-ficha-sello {
  border-top: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  padding-top: 9px;
  font-family: var(--font-mono); font-size: 10px; line-height: 1.5;
  letter-spacing: .015em; color: var(--text-subtle);
}
.lp-ficha-sello .vence { color: var(--warn-fg); font-weight: 500; }
.lp-ficha-sello .sep { opacity: .5; margin: 0 2px; }
.lp-ficha-sello .rev { color: var(--text-muted); }

/* ── Modo cine: la ficha nace vacía y se imprime al cruce ────────────────
   EL VACIADO CUELGA DE `html.lp-js`, NO SOLO DEL MEDIA QUERY. Antes bastaba
   con ser ancho y tener motion para que la ficha naciera vacía, y quien la
   imprimía era el JS: en escritorio ancho SIN JavaScript nadie la imprimía
   nunca y el hero se quedaba con el titular y un hueco. Se rompía la regla de
   la casa —la información no depende del movimiento— justo en la pieza que
   enseña lo que el producto entrega.

   Ahora el estado IMPRESO es el defecto puro (papel, sin JS, móvil, lite,
   reduced-motion) y el vacío solo existe si landing-boot.js dejó su marca en
   el <head>, síncrona y antes del primer paint: por eso sigue sin verse ni un
   frame de ficha impresa cuando sí hay película. Es el mismo patrón de
   .me-cine / .cz-cine / .mu-cine, con la clase una planta más arriba porque
   esta pieza tiene que estar resuelta ya en el primer pintado.

   El JS solo añade .sal-cine (que habilita las transiciones) y, si al final no
   hay película —sin WebGL, o lite—, .sal-impresa. Las dos clases van sobre
   .lp-hero (dos clases + una) y le ganan en especificidad a `html.lp-js`. */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  html.lp-js .lp-ficha { opacity: 0; transform: scaleY(.5); }
  html.lp-js .lp-ficha .mk .i { transform: translateY(118%); opacity: 0; }
  .lp-hero.sal-impresa .lp-ficha { opacity: 1; transform: none; }
  .lp-hero.sal-impresa .lp-ficha .mk .i { transform: none; opacity: 1; }
}
/* Las transiciones solo existen en cine: al encender el modo no se anima
   nada (no cambia ni opacidad ni transform, solo la transición disponible). */
.lp-hero.sal-cine .lp-ficha {
  transition: opacity .34s var(--ease), transform .34s var(--ease-emph);
  transition-delay: .22s;
}
.lp-hero.sal-cine .lp-ficha .mk .i {
  transition: transform .62s var(--ease-emph), opacity .4s var(--ease);
}
.lp-hero.sal-on .lp-ficha { opacity: 1; transform: none; }
.lp-hero.sal-on .lp-ficha .mk .i { transform: none; opacity: 1; }
.lp-hero.sal-on .lp-ficha-top .mk:nth-child(1) .i { transition-delay: .40s; }
.lp-hero.sal-on .lp-ficha-top .mk:nth-child(2) .i { transition-delay: .48s; }
.lp-hero.sal-on .lp-ficha-esc .mk:nth-child(1) .i { transition-delay: .58s; }
.lp-hero.sal-on .lp-ficha-esc .mk:nth-child(2) .i { transition-delay: .63s; }
.lp-hero.sal-on .lp-ficha-esc .mk:nth-child(3) .i { transition-delay: .68s; }
.lp-hero.sal-on .lp-ficha-esc .mk:nth-child(4) .i { transition-delay: .73s; }
.lp-hero.sal-on .lp-ficha-esc .mk:nth-child(5) .i { transition-delay: .78s; }
.lp-hero.sal-on .lp-ficha-cita .mk .i { transition-delay: .86s; }
.lp-hero.sal-on .lp-ficha-sello .mk .i { transition-delay: .96s; }
/* Se contrae: primero se despinta el contenido, luego colapsa el marco. */
.lp-hero.sal-out .lp-ficha { transition-delay: .24s; }
.lp-hero.sal-out .lp-ficha .mk .i { transition: transform .26s var(--ease), opacity .2s var(--ease); }

/* ══════════════════════════════════════════════════════════════════════════
   LA SEGUNDA PIEZA · la boleta de audiencia (pliego, obs. 1b)
   Cuelga de OTRO nodo, el de la parte de abajo del disco, y entra ~2,7 s
   después de la ficha: las dos conviven un rato en el hero y luego cada una se
   retira por su lado. Todo lo que aquí se mueve es transform/opacity.

   Es deliberadamente lo contrario de la ficha: ancha y baja donde aquella es
   alta y estrecha, con la esquina de instrumento abajo-derecha donde aquella la
   lleva arriba-izquierda, y con un gesto de LECTURA —el auto arriba, la casilla
   de la agenda abajo— donde aquella insinúa un escrito.
   ══════════════════════════════════════════════════════════════════════════ */

/* El segundo hilo: mismo lienzo y mismas coordenadas que el primero, pero el
   gesto es vertical · horizontal · vertical (cae, jala, cae). */
.lp-hilo2 .sg.sv1, .lp-hilo2 .sg.sv2 { transform: scaleY(0); }
.lp-hilo2 .sg.sh { transform: scaleX(0); }
.lp-hero.age-on .lp-hilo2 .sg.sv1 { transform: scaleY(1); transition-delay: 0s; }
.lp-hero.age-on .lp-hilo2 .sg.sh  { transform: scaleX(1); transition-delay: .2s; }
.lp-hero.age-on .lp-hilo2 .sg.sv2 { transform: scaleY(1); transition-delay: .37s; }
.lp-hero.age-out .lp-hilo2 .sg.sv2 { transition-delay: .26s; }
.lp-hero.age-out .lp-hilo2 .sg.sh  { transition-delay: .42s; }
.lp-hero.age-out .lp-hilo2 .sg.sv1 { transition-delay: .58s; }

/* Dónde se para. No es un porcentaje suelto: la boleta VA COLGADA DEL DISCO,
   porque de la distancia al disco depende que el hilo tenga caída. El centro
   del radar está en el 47 % del alto del hero (landing-scene.js, computeLayout)
   y el nodo de abajo cae unos 50-80 px por debajo; los 130 px de más dejan la
   boleta siempre por debajo del nodo, con recorrido de sobra para el trazo. La
   otra atadura es el pie: la regla del hero arranca a ~104 px del fondo, y la
   pieza completa mide ~163 px, así que por debajo de ~860 px de alto de ventana
   no caben las dos cosas y entra la versión corta (más abajo). Medido a
   1440×900, 1280×800, 1024×768 y 960×900. */
/* El tope de `right + width` (88 + 280 = 368) es la cuenta que impide que la
   boleta se le acerque al titular en pantallas anchas. Ahí la escala del
   display topa en 4,2 rem y su línea larga mide 740 px, más de los 720 px de su
   caja: el texto se sale por la derecha —el .ln lo permite a propósito, para no
   cortar la itálica— y llega hasta el centro del hero + 164 px. Con 368 quedan
   68 px de aire, exactamente los que ya se reservó la ficha (24 + 344). */
.lp-boleta-w {
  position: absolute; z-index: 3;
  top: clamp(420px, calc(47% + 130px), 1200px);
  right: clamp(52px, 6vw, 88px);
  width: clamp(240px, 24vw, 280px);
}
.lp-boleta {
  position: relative; display: grid; gap: 8px;
  padding: 10px 13px 9px;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  box-shadow: 0 18px 46px rgba(0, 0, 0, .40);
  /* Se despliega desde su canto superior, que es por donde entra el hilo. */
  transform-origin: 0 0;
}
/* Esquina de instrumento en el canto opuesto al de la ficha. */
.lp-boleta::after {
  content: ""; position: absolute; right: -1px; bottom: -1px; width: 13px; height: 13px;
  border-bottom: 1px solid var(--accent); border-right: 1px solid var(--accent);
  opacity: .55;
}
.lp-boleta .mk { display: block; overflow-y: clip; overflow-x: visible; }
.lp-boleta .mk .i { display: block; }

/* Alturas explícitas en toda la pieza: la boleta tiene que medir ~145 px sí o
   sí, porque de eso depende que su pie no alcance la regla del hero. */
.lp-boleta .bo-rot, .lp-boleta .bo-slot .rot {
  margin: 0; font-family: var(--font-mono); font-size: 9.5px; line-height: 1.2;
  letter-spacing: .14em; text-transform: uppercase; color: var(--text-subtle);
}
/* El auto, tal como lo escribió el despacho: llave de 1px al margen (la misma
   pieza que ancla la cita en la ficha) y los dos fragmentos que se leyeron
   subrayados con una hairline de acento — la lectura, hecha visible. */
.lp-boleta .bo-auto {
  position: relative; margin: 0; padding-left: 11px;
  font-size: 11.5px; line-height: 1.38; color: var(--text-muted);
}
.lp-boleta .bo-auto .llave {
  position: absolute; left: 0; top: 3px; bottom: 3px; width: 5px;
  border: 1px solid color-mix(in srgb, var(--border-strong) 90%, transparent);
  border-right: 0;
}
/* Los dos fragmentos leídos no se parten nunca: una fecha cortada por la mitad
   —«el 16-09-» / «2026 a las…»— deshace justo lo que la pieza está enseñando. */
.lp-boleta .bo-auto .lee {
  font-weight: 560; color: var(--text-strong); white-space: nowrap;
  box-shadow: inset 0 -1px 0 var(--accent);   /* igual que .ag-lee en #capacidades */
}
/* La casilla ya diligenciada: es la fecha lo que manda, en cifras tabulares. */
.lp-boleta .bo-slot {
  display: grid; gap: 2px;
  border-top: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  padding-top: 8px;
}
.lp-boleta .fch {
  font-family: var(--font-mono); font-size: 14px; line-height: 1.3; font-weight: 560;
  letter-spacing: -.005em; color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
.lp-boleta .bo-slot .sep { color: var(--text-subtle); margin: 0 7px; }
/* La marca de verificación va en ámbar, NO en cian, y con el mismo punto de
   5 px que la pieza de la agenda de #capacidades (.ag-ver): la página habla un
   solo idioma —el cian es lo que está vivo, el ámbar es lo que te espera a ti—
   y esta audiencia está esperando que su abogado le mire la hora. */
.lp-boleta .bo-ver {
  margin: 0; display: block;
  font-family: var(--font-mono); font-size: 10px; line-height: 1.3;
  letter-spacing: .015em; color: var(--warn-fg);
}
.lp-boleta .bo-ver .i { display: flex; align-items: center; gap: 7px; }
.lp-boleta .bo-ver .pt {
  width: 5px; height: 5px; border-radius: 50%; flex-shrink: 0;
  background: var(--warn-fg);
}

/* Ventana baja (un portátil de 13" con toda la barra del navegador, o media
   pantalla en vertical): no hay altura para dos piezas completas sin pisar la
   regla del hero. La boleta se queda con lo que no se puede resumir —la
   casilla y su marca de verificación— y suelta la cita del auto. Es el mismo
   recorte que en el teléfono, disparado por el otro eje. */
@media (min-width: 941px) and (max-height: 860px) {
  .lp-boleta-w { top: clamp(380px, calc(47% + 110px), 520px); }
  .lp-boleta .bo-rot, .lp-boleta .bo-auto { display: none; }
  .lp-boleta .bo-slot { border-top: 0; padding-top: 0; }
}

/* Mismo contrato que la ficha, y por la misma razón: impresa por defecto
   (papel, sin JS, móvil, lite), vacía solo bajo `html.lp-js` —o sea, solo
   cuando de verdad hay quien la imprima—, y las transiciones únicamente bajo
   .sal-cine. Esta pieza era el caso peor: nació después del <style> del
   <noscript>, nadie la añadió a aquella lista a mano, y en escritorio ancho
   sin JS quedaba invisible en los DOS caminos (scripting desactivado y
   scripts caídos). La clase de encendido es .age-on para que las dos piezas
   tengan ritmos independientes. */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  html.lp-js .lp-boleta { opacity: 0; transform: scaleY(.5); }
  html.lp-js .lp-boleta .mk .i { transform: translateY(118%); opacity: 0; }
  .lp-hero.sal-impresa .lp-boleta { opacity: 1; transform: none; }
  .lp-hero.sal-impresa .lp-boleta .mk .i { transform: none; opacity: 1; }
}
.lp-hero.sal-cine .lp-boleta {
  transition: opacity .34s var(--ease), transform .34s var(--ease-emph);
  transition-delay: .22s;
}
.lp-hero.sal-cine .lp-boleta .mk .i {
  transition: transform .62s var(--ease-emph), opacity .4s var(--ease);
}
.lp-hero.age-on .lp-boleta { opacity: 1; transform: none; }
.lp-hero.age-on .lp-boleta .mk .i { transform: none; opacity: 1; }
.lp-hero.age-on .lp-boleta .bo-rot .i { transition-delay: .40s; }
.lp-hero.age-on .lp-boleta .bo-auto .i { transition-delay: .50s; }
.lp-hero.age-on .lp-boleta .bo-slot .mk:nth-child(1) .i { transition-delay: .70s; }
.lp-hero.age-on .lp-boleta .bo-slot .mk:nth-child(2) .i { transition-delay: .78s; }
.lp-hero.age-on .lp-boleta .bo-ver .i { transition-delay: .90s; }
.lp-hero.age-out .lp-boleta { transition-delay: .24s; }
.lp-hero.age-out .lp-boleta .mk .i { transition: transform .26s var(--ease), opacity .2s var(--ease); }
/* Red de seguridad: hay película para la ficha pero el disco no dejó ningún
   nodo utilizable en su parte de abajo. La boleta se imprime quieta antes que
   dejar un hueco. Va DESPUÉS del media query a propósito: tiene que ganarle. */
.lp-hero.age-fija .lp-boleta { opacity: 1; transform: none; }
.lp-hero.age-fija .lp-boleta .mk .i { transform: none; opacity: 1; }
.lp-hero.age-fija .lp-hilo2 { display: none; }

/* Indicador scroll que respira */
.lp-scrollcue {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .22em;
  text-transform: uppercase; color: var(--text-subtle); flex-shrink: 0;
}
.lp-scrollcue .ln {
  width: 1px; height: 34px; position: relative; overflow: clip;
  background: color-mix(in srgb, var(--border-strong) 80%, transparent);
}
/* El destello viaja con transform, no con `top`: es una animación INFINITA
   que corre en el hero desde el primer paint —justo mientras se lee el H1, que
   es el LCP— y animar una propiedad de layout la saca del compositor. Misma
   trayectoria: la caja mide medio trazo, así que -110% de sí misma es el -55%
   del trazo de antes, y 210% es el 105%. */
.lp-scrollcue .ln::after {
  content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 50%;
  background: linear-gradient(var(--accent), transparent);
  transform: translateY(-110%); will-change: transform;
  animation: lp-cue 1.9s var(--ease) infinite;
}
@keyframes lp-cue {
  0%        { transform: translateY(-110%); }
  60%, 100% { transform: translateY(210%); }
}

/* ══════════════════════════════════════════════════════════════════════════
   ACTO 3 · LA VENTANA QUE CAMBIA DE PANTALLA (la interacción firma)
   Pista alta con sticky a viewport completo; la "ventana de myvigia" flota en
   un espacio 3D real, se inclina con el scroll y sus CUATRO PANTALLAS se cubren
   y se descubren dentro de ella. Se scrubbea con GSAP; sin JS/reduced-motion
   cae a deck editorial (más abajo).

   El rediseño (y el fotograma vacío que lo obligó) está documentado arriba de
   la sección en home.html. Lo que hay que saber para tocar este CSS:

     · en PELÍCULA la ventana es `.lp-device`: superficie, borde, radio, sombra
       y recorte. Las `.lp-face` son PANTALLAS: opacas, a sangre, sin borde ni
       sombra propios, recortadas por el chasis. Fuera de película (lite, papel,
       sin JS, ≤940px, reduced-motion) todo vuelve a lo de siempre: cada cara es
       una tarjeta con su barra y su borde en un deck vertical;
     · la CABECERA (`.lp-chrome`) es del chasis y no se va nunca;
     · las pantallas se CUBREN. Como son opacas y la que entra tapa a la que se
       va, no puede existir un hueco: la garantía es geométrica;
     · aquí no hay ni una transición ni una @keyframes para el cambio de
       pantalla. Todo lo escribe el scrub en línea, frame a frame, y solo
       transform y opacity (mismo contrato que .lp-fallo y el raíl del término).
   ══════════════════════════════════════════════════════════════════════════ */
.lp-flip {
  position: relative;
  /* Pista alta: cada ~100vh una pantalla. Reservada => CLS 0. */
  height: 460vh;
  background: var(--canvas);
  /* Alto EXACTO de la cabecera. Lo comparten la barra de cada cara (que en
     película se oculta conservando el hueco) y `.lp-chrome`, que se posa
     encima: si los dos números se separan, el contenido de las pantallas baila
     al entrar en película. Por eso la barra lleva `height` y no padding. */
  --lp-bar-h: 40px;
}
.lp-flip-sticky {
  position: sticky; top: 0; height: 100svh; height: 100vh;
  display: grid; place-items: center; overflow: clip;
  perspective: 1600px;
  /* Reserva una franja inferior para la leyenda: empuja el dispositivo hacia
     arriba para que su canto inferior NO pise el texto de la leyenda (el jurado
     veía la leyenda cruzada con el borde bajo de la ventana). */
  padding-bottom: clamp(96px, 18vh, 168px);
}
/* Atmósfera de fondo que hace rack-focus (blur) según la cara.
   ── EL CORTE DEL GLARE (pliego, obs. 5a) ──────────────────────────────────
   La franja pineada mide una pantalla y lleva overflow:clip. La atmósfera
   llegaba encendida hasta sus dos cantos, así que al bajar de página el
   resplandor se acababa en una RECTA de lado a lado del viewport: un campo
   luminoso amputado con tijera justo donde empieza la sección siguiente. No
   era un problema de color ni de z-index — era que la luz no tenía dónde
   apagarse.
   Se apaga sola. Las dos capas de atmósfera llevan una máscara vertical:
   nacen a nada en el canto de arriba, mandan en el tercio central y mueren
   antes de llegar al canto de abajo. La costura entre actos queda con lo
   único que la casa admite ahí, la hairline de la sección.
   Coste: la máscara es ESTÁTICA (se resuelve una vez, no se anima nada). */
.lp-flip-bg {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(900px 620px at 50% 30%, color-mix(in srgb, var(--brand) 12%, transparent), transparent 66%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 13%, #000 58%, transparent 94%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 13%, #000 58%, transparent 94%);
}
.lp-flip-aurora {
  position: absolute; inset: -20%; z-index: 0; pointer-events: none; opacity: 0;
  background:
    radial-gradient(50% 40% at 30% 30%, color-mix(in srgb, var(--iris-400) 24%, transparent), transparent 70%),
    radial-gradient(46% 42% at 72% 60%, color-mix(in srgb, var(--pulse-500) 18%, transparent), transparent 72%);
  filter: blur(30px);
  /* La aurora sangra un 20 % por cada lado (inset:-20%), así que sus topes de
     máscara están corridos: el 0 % de esta caja cae 20 % por encima del canto
     real de la franja. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 14%, #000 30%, #000 62%, transparent 82%);
  mask-image: linear-gradient(to bottom, transparent 14%, #000 30%, #000 62%, transparent 82%);
}
/* LA ATMÓSFERA TAMBIÉN LA ESCRIBE EL SCRUB. Antes eran dos clases (.face-b /
   .face-d) con transiciones CSS de 0,6 y 0,8 s: al conmutar en el perfil del
   volteo, el aire de la escena cambiaba con su propio reloj, desacoplado del
   dedo — y si el scroll se detenía a mitad, la transición se quedaba a medias.
   Ahora la aurora sube con el PESO de la pantalla B y el fondo se retira con el
   peso de la D, así que la atmósfera es función pura de la posición: rebobina
   exacta y se para cuando el dedo se para. Sin película nadie las toca y se
   quedan en su estado de reposo (aurora apagada, fondo entero). */
/* La PERSPECTIVA vive aquí y no solo en la franja pineada: el chasis ya no
   propaga 3D (perdió `preserve-3d` al perder el volteo, para poder recortar),
   así que sin esto su inclinación se aplanaría en un simple achatamiento
   horizontal. Puesta en el escenario, además, el punto de fuga cae en el centro
   del aparato y el ladeo sale simétrico. */
.lp-flip-stage { position: relative; z-index: 1; perspective: 1400px; }

.lp-flip-title {
  position: absolute; left: 50%; bottom: clamp(16px, 3.5vh, 40px); transform: translateX(-50%);
  z-index: 4; text-align: center; width: min(680px, 88vw);
  pointer-events: none;
}
.lp-flip-title .k {
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .18em;
  color: var(--brand-text); text-transform: uppercase; display: block; margin-bottom: 8px;
}
.lp-flip-title .t { font-size: clamp(1.1rem, 2.4vw, 1.6rem); font-weight: 600; color: var(--text-strong); letter-spacing: -.02em; margin: 0; }
/* Las 4 leyendas se apilan; SOLO la activa es visible. TOGGLE DURO de opacity,
   SIN transición: con Lenis conduciendo el rAF, al detenerse el scroll una
   transición CSS en curso se CONGELABA (la leyenda saliente quedaba a ~0.27 y
   la entrante a 0 → dos leyendas tenues a la vez, justo lo que el jurado veía).
   El cambio instantáneo coincide con el volteo de la cara y el light-streak que
   barre el canto, así que es imperceptible y NUNCA deja dos leyendas legibles.
   .lp-flip-title es aria-hidden + pointer-events:none, así que opacity basta. */
.lp-flip-title { display: grid; }
.lp-flip-cap { grid-area: 1 / 1; opacity: 0; transform: translateY(8px); }
.lp-flip-cap.is-on { opacity: 1; transform: none; }

/* La ventana (chasis). Tamaño fijo; se inclina en 3D con la perspectiva de la
   franja pineada. Ya NO lleva `preserve-3d`: no hay caras coplanares que
   orientar, y sin él el chasis puede RECORTAR (`overflow: clip` en película),
   que es lo que convierte a las caras en pantallas de una misma ventana. La
   profundidad de los satélites no depende de esto: .lp-sat-wrap monta su propia
   `perspective`. */
.lp-device {
  position: relative;
  width: min(760px, 90vw); aspect-ratio: 16 / 10;
  will-change: transform;
}
.lp-face {
  position: absolute; inset: 0; border-radius: var(--r-xl);
  /* ESTADO DE PARTIDA: la cara es una tarjeta del deck, entera y visible. El
     vaciado vive en el bloque de película (`html.lp-js:not(.lp-lite)` + gate),
     no aquí: la regla de la casa es que el CSS entregue todo impreso y solo se
     vacíe lo que va a animarse cuando hay quien lo deshaga. Antes nacían las
     cuatro con opacity:0 y el bloque de «sin JS» tenía que rescatarlas. */
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--brand) 22%, var(--border));
  box-shadow: var(--sh-lg), var(--card-highlight),
              0 0 0 1px color-mix(in srgb, var(--brand) 10%, transparent),
              0 0 80px -18px color-mix(in srgb, var(--brand) 55%, transparent);
  display: flex; flex-direction: column;
  will-change: transform;
}

/* El reflejo del cristal. Ya no tapa ningún fallo: su posición y su intensidad
   son función de la INCLINACIÓN del chasis (una especular que resbala cuando el
   panel se ladea), y las escribe el scrub. El barrido NO mueve
   background-position —eso repinta el degradado entero cada frame, fuera del
   compositor—: es una ventana que recorta y dentro un hijo tres veces más ancho
   que la cruza con translateX. Solo transform y opacity. */
.lp-device-sheen {
  position: absolute; inset: 0; z-index: 5; pointer-events: none;
  border-radius: var(--r-xl); overflow: clip; opacity: 0;
  mix-blend-mode: screen;
}
.lp-device-sheen > i {
  position: absolute; top: 0; bottom: 0; left: -100%; width: 300%;
  background: linear-gradient(105deg, transparent 42%, color-mix(in srgb, var(--accent) 34%, transparent) 50%, transparent 58%);
}

/* ── LA CABECERA QUE SE QUEDA ─────────────────────────────────────────────
   Vive en el chasis, por encima de las pantallas, y no participa de ninguna
   transición: es lo que hace que cuatro vistas se lean como UNA ventana. Solo
   existe en película (fuera de ella cada cara lleva la suya, que es lo correcto
   en un deck de cuatro tarjetas y en papel). */
.lp-chrome {
  display: none;
  position: absolute; top: 0; left: 0; right: 0; z-index: 4;
  height: var(--lp-bar-h); align-items: center; gap: 6px; padding: 0 16px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  pointer-events: none;
}
.lp-chrome > i { width: 9px; height: 9px; border-radius: 50%; background: var(--border-strong); flex-shrink: 0; }
/* La ruta es un ODÓMETRO: cuatro renglones apilados en un visor de uno solo. El
   scrub lo hace rodar mientras la pantalla cambia debajo — es el elemento
   compartido que viaja de una vista a la siguiente. */
.lp-url {
  /* display:block obligatorio: era un <span> y en un inline no se aplican ni
     `height` ni `overflow`, así que el odómetro no recortaba y se leían las dos
     rutas a la vez asomando por encima de la barra. */
  display: block; margin-left: 10px; min-width: 0; overflow: hidden;
  height: 1.45em; line-height: 1.45;
  font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle);
  /* La ranura mide 16 px y la ruta 11: a media vuelta se ven dos medias líneas.
     Cortadas a cuchillo eso parece un fallo de pintado; disueltas en el filo,
     es un odómetro. Máscara ESTÁTICA (se resuelve una vez, no se anima). */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 66%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 34%, #000 66%, transparent 100%);
}
.lp-url-roll { display: block; will-change: transform; }
.lp-url-roll b {
  display: block; height: 1.45em; font-weight: 400; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

/* sombra proyectada bajo la ventana */
.lp-device-shadow {
  position: absolute; left: 50%; bottom: -8%; width: 70%; height: 40px;
  transform: translateX(-50%); border-radius: 50%;
  background: radial-gradient(closest-side, rgba(0,0,0,.5), transparent 75%);
  filter: blur(14px); z-index: -1;
}

/* Barra de ventana común. Alto FIJO (no padding) porque en película `.lp-chrome`
   se posa exactamente encima y los dos números tienen que ser el mismo. */
.lp-face-bar {
  display: flex; align-items: center; gap: 6px;
  height: var(--lp-bar-h, 40px); padding: 0 16px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  flex-shrink: 0; border-radius: var(--r-xl) var(--r-xl) 0 0;
}
.lp-face-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--border-strong); }
.lp-face-bar span { margin-left: 10px; font-family: var(--font-mono); font-size: 11px; color: var(--text-subtle); }
.lp-face-body { padding: 18px 20px; display: grid; gap: 12px; align-content: start; overflow: hidden; flex: 1; }

/* Cara A — bandeja de vigilancia (radicado + despacho + hora relativa).
   El carril (.a-rows) nace subido 70px dentro de un clip (.a-clip): la fila de
   alerta queda escondida sobre el borde. En la meseta A el scrub pone .a-alerta
   en la sección y TODO se mueve por transform/opacity (compositor): el carril
   baja empujando la bandeja, la fila nueva aparece, el odómetro de novedades
   rueda 4→5 y el pill «En vivo» late una vez. Animaciones con forwards: al
   quitar la clase (scrub en reversa) el estado base vuelve de golpe —
   determinista y rebobinable, con toggle duro por umbral. Las filas
   llevan alto FIJO (60px) y texto con ellipsis para que el desplazamiento del
   carril sea exacto a cualquier ancho de película; en lite/print/sin JS el alto
   vuelve a auto y el texto envuelve. */
/* min-width:0 + minmax(0,1fr): sin ellos el texto nowrap del radicado fija el
   min-content de la pista y las filas REVIENTAN el ancho del cuerpo (visto a
   560px de dispositivo). Así la pista nunca crece más que el cuerpo y el
   ellipsis de .t/.d puede actuar. */
.lp-face-a .a-clip { overflow: hidden; min-width: 0; }
.lp-face-a .a-rows { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; transform: translateY(-70px); will-change: transform; }
.lp-face-a .row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 12px 14px; height: 60px; box-sizing: border-box;
}
.lp-face-a .row > div:first-child { min-width: 0; flex: 1; }
.lp-face-a .row .t { font-size: 13.5px; font-weight: 560; color: var(--text-strong); line-height: 1.25; }
.lp-face-a .row .d { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; line-height: 1.3; }
.lp-face-a .row .t, .lp-face-a .row .d { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lp-face-a .row .rad { font-family: var(--font-mono); font-size: 10.5px; color: var(--text); letter-spacing: .01em; }
.lp-face-a .row .meta { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
/* La antigüedad del renglón va en --text-muted, NO en --text-subtle: la fila
   de la bandeja se pinta sobre --surface-3, que es el único de los fondos
   donde el tercer nivel no llega al 4.5:1 de AA (medido: 4.28:1 a 10 px).
   Con --text-muted sube a 5.46:1 y sigue por debajo del radicado y del
   título de la fila, así que la jerarquía del mock no se toca. */
.lp-face-a .row .tw { font-family: var(--font-mono); font-size: 10px; line-height: 1; color: var(--text-muted); }
.lp-face-a .tw-static { display: none; }
.lp-face-a .kpis { display: grid; grid-template-columns: repeat(3,1fr); gap: 10px; }
.lp-face-a .kpi { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md); padding: 12px; }
.lp-face-a .kpi .n { font-size: 24px; font-weight: 700; color: var(--text-strong); letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1.35; }
.lp-face-a .kpi .l { font-size: 10px; color: var(--text-subtle); text-transform: uppercase; letter-spacing: .05em; margin-top: 3px; }
/* Odómetro de novedades: dos valores apilados en un visor de una línea;
   rodar +1 = translateY(-50%) del carril (patrón del playbook). */
.lp-face-a .a-odo { position: relative; overflow: hidden; height: 1.35em; }
.lp-face-a .a-odo-roll { display: block; will-change: transform; }
.lp-face-a .a-odo-roll span { display: block; height: 1.35em; line-height: 1.35; }
/* La fila nueva nace transparente (además de clipeada por .a-clip). */
.lp-face-a .row-alerta { opacity: 0; }
/* El momento vivo: .a-alerta la pone el scrub al pisar la meseta A. */
.lp-flip.a-alerta .lp-face-a .a-rows { animation: lp-a-rows .55s var(--ease-emph) forwards; }
.lp-flip.a-alerta .lp-face-a .row-alerta { animation: lp-a-alerta .45s var(--ease) .12s forwards; }
.lp-flip.a-alerta .lp-face-a .a-odo-roll { animation: lp-a-odo .5s var(--ease-emph) .25s forwards; }
.lp-flip.a-alerta .lp-face-a .lp-pill.live { animation: lp-a-pill .8s var(--ease) .3s 1; }
@keyframes lp-a-rows   { to { transform: translateY(0); } }
@keyframes lp-a-alerta { to { opacity: 1; } }
@keyframes lp-a-odo    { to { transform: translateY(-50%); } }
@keyframes lp-a-pill   { 0%, 100% { transform: scale(1); } 40% { transform: scale(1.14); } }

/* Cara B — la IA con jurisprudencia (atmósfera más oscura + aurora) */
.lp-face-b { background: var(--dusk-950); }
.lp-face-b .lp-face-bar { background: color-mix(in srgb, var(--dusk-950) 70%, var(--dusk-900)); }
.lp-face-b .ask {
  font-size: 12px; color: var(--text-subtle); font-family: var(--font-mono);
  border-left: 2px solid var(--brand); padding-left: 10px;
}
.lp-face-b .stream {
  font-size: 13.5px; line-height: 1.6; color: var(--text); min-height: 3.2em;
}
.lp-face-b .stream .cur { display: inline-block; width: 7px; height: 1.05em; vertical-align: -2px;
  background: var(--accent); margin-left: 1px; animation: lp-caret 1s steps(1) infinite; }
@keyframes lp-caret { 50% { opacity: 0; } }
.lp-cites { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.lp-cite {
  font-family: var(--font-mono); font-size: 11px; padding: 5px 10px; border-radius: var(--r-full);
  background: var(--brand-tint); color: var(--brand-text);
  border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
  opacity: 0; transform: translateY(6px) scale(.96);
}
.lp-cite.on { opacity: 1; transform: none; transition: opacity .4s var(--ease), transform .4s var(--ease-emph); }
.lp-cite .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--accent); display: inline-block; margin-right: 5px; vertical-align: 1px; }

/* Cara C — documentos. */
.lp-face-c .doc {
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-md);
  padding: 16px 18px; flex: 1; overflow: hidden;
}
.lp-face-c .doc .head {
  display: flex; align-items: center; gap: 10px; padding-bottom: 12px;
  border-bottom: 1px solid var(--border); margin-bottom: 12px;
}
.lp-face-c .doc .head .mk,
.lp-face-c .doc .head .mark { width: 22px; height: 22px; flex-shrink: 0; }
.lp-face-c .doc .head .ttl { font-size: 12.5px; font-weight: 600; color: var(--text-strong); }
.lp-face-c .doc .head .sub { font-size: 10.5px; color: var(--text-subtle); font-family: var(--font-mono); }
.lp-face-c .doc p { font-size: 12.5px; line-height: 1.55; color: var(--text); margin: 0 0 8px; }
.lp-face-c .doc .pend { color: var(--warn-fg); background: var(--warn-bg); padding: 1px 5px; border-radius: 4px; font-family: var(--font-mono); font-size: 11px; }
.lp-face-c .models {
  display: flex; gap: 8px; margin-top: 4px; overflow: hidden;
}
.lp-face-c .model {
  font-family: var(--font-mono); font-size: 11px; white-space: nowrap;
  padding: 5px 11px; border-radius: var(--r-full); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-muted);
}
.lp-face-c .model.on { border-color: var(--brand); color: var(--brand-text); background: var(--brand-tint); }

/* Cara D — el sistema completo (satélites). Fondo OPACO: es la pantalla que
   queda debajo cuando la C se retira, y tiene que tapar por completo. */
.lp-face-d {
  background: color-mix(in srgb, var(--canvas) 96%, var(--brand));
  border: 1px solid color-mix(in srgb, var(--brand) 14%, var(--border));
  box-shadow: var(--sh-lg), 0 0 90px -22px color-mix(in srgb, var(--brand) 55%, transparent);
}
.lp-face-d .lp-face-bar, .lp-face-d .lp-face-body { display: none; }
/* perspectiva propia para que el Z de cada satélite lea como profundidad real */
.lp-sat-wrap { position: absolute; inset: 0; transform-style: preserve-3d; perspective: 900px; }
.lp-sat {
  position: absolute; border-radius: var(--r-lg); background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--brand) 18%, var(--border));
  box-shadow: var(--sh-md), 0 0 40px -16px color-mix(in srgb, var(--brand) 50%, transparent);
  padding: 12px 14px; display: flex; flex-direction: column; gap: 8px;
  /* Sin `filter`: obligaba a reservar una superficie con pipeline de filtro
     por satélite durante toda la vida de la página, aunque estén a 6.000px. */
  will-change: transform, opacity;
}
/* los cercanos: borde e iluminación de marca más marcados (protagonistas) */
.lp-sat.is-near {
  border-color: color-mix(in srgb, var(--brand) 34%, var(--border));
  box-shadow: var(--sh-lg), 0 0 60px -14px color-mix(in srgb, var(--brand) 62%, transparent);
}
.lp-sat.is-far { background: color-mix(in srgb, var(--surface) 82%, var(--canvas)); }
.lp-sat .sh { font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em; color: var(--brand-text); text-transform: uppercase; }
.lp-sat .sl { height: 6px; border-radius: 4px; background: var(--surface-3); }
.lp-sat .sl.b { background: var(--brand-tint-strong); }

/* Mini-contenido con vida (no solo líneas grises): */
/* Kanban: 3 columnas de tarjetitas */
.lp-sat .cols { display: flex; gap: 6px; }
.lp-sat .cols .col { flex: 1; display: flex; flex-direction: column; gap: 4px; }
.lp-sat .cols .col i { height: 12px; border-radius: 3px; background: var(--surface-3); display: block; }
.lp-sat .cols .col i.b { background: var(--brand-tint-strong); }
/* Calendario: rejilla de días con algunos marcados */
.lp-sat .cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.lp-sat .cal i { aspect-ratio: 1; border-radius: 2px; background: var(--surface-3); }
.lp-sat .cal i.b { background: var(--brand); box-shadow: 0 0 6px -1px color-mix(in srgb, var(--brand) 70%, transparent); }
/* Analítica: barras verticales */
.lp-sat .bars { display: flex; align-items: flex-end; gap: 5px; height: 42px; }
.lp-sat .bars i { flex: 1; height: var(--h, 50%); border-radius: 3px 3px 0 0; background: var(--surface-3); }
.lp-sat .bars i.b { background: linear-gradient(180deg, var(--brand), color-mix(in srgb, var(--brand) 40%, transparent)); }

/* ══════════════════════════════════════════════════════════════════════════
   EN PELÍCULA: EL CHASIS ES LA VENTANA Y LAS CARAS SON PANTALLAS
   --------------------------------------------------------------------------
   Mismo gate que usa la lectura del fallo —hay película, hay sitio y nadie
   pidió menos movimiento—, y por eso todo esto es un bloque aparte en vez de
   excepciones sembradas por los cinco fallbacks: fuera de aquí, la sección
   sigue siendo exactamente el deck de cuatro tarjetas de siempre.

   LO QUE CAMBIA, Y POR QUÉ:
     · el material de la ventana (superficie, borde, radio, sombra) SUBE de la
       cara al chasis, y el chasis RECORTA. Así lo que se mueve por dentro no
       puede salirse: son pantallas dentro de un aparato, no naipes sueltos;
     · cada cara pierde su borde, su radio y su sombra de tarjeta y se queda
       con su FONDO OPACO. Ese fondo es la garantía del acto: la pantalla que
       entra tapa a la que se va, y la que se va nunca se aparta antes de estar
       tapada (la única que abandona el cuadro es la C, y debajo está la D ya
       pintada). Por construcción no hay un fotograma sin contenido;
     · la sombra de la cara deja de ser un halo de tarjeta y pasa a ser el
       CANTO de la hoja: un filete de 1px de marca (anillo de spread) y una
       sombra blanda, los dos POR FUERA de la caja, así que al reposo caen fuera
       del recorte y no se ven, y en cuanto la pantalla se desplaza dibujan su
       canto sobre la de debajo. Gratis, física, y necesaria: los fondos de las
       pantallas A y C son el mismo tono, de modo que sin filete la hoja que
       entra no tenía borde y el contenido de la que se iba parecía cortarse a
       media fila por un fallo de pintado en vez de por una hoja encima;
     · la barra de cada cara se oculta CONSERVANDO SU HUECO y encima se posa la
       cabecera del chasis, que no se va nunca.
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  html.lp-js:not(.lp-lite) .lp-device {
    border-radius: var(--r-xl); overflow: clip;
    background: var(--surface);
    border: 1px solid color-mix(in srgb, var(--brand) 22%, var(--border));
    box-shadow: var(--sh-lg), var(--card-highlight),
                0 0 0 1px color-mix(in srgb, var(--brand) 10%, transparent),
                0 0 90px -20px color-mix(in srgb, var(--brand) 55%, transparent);
  }
  html.lp-js:not(.lp-lite) .lp-chrome { display: flex; }
  /* LA LEYENDA TAMBIÉN ES UN ODÓMETRO. Antes las cuatro se cruzaban con
     opacidad en el mismo sitio y a mitad de relevo se leían DOS textos
     encabalgados sobre los mismos glifos — el borrón clásico del crossfade de
     plantilla. Aquí ruedan en un visor: las cuatro se apilan en columna virtual
     (cada una desplazada k·alto por el scrub) y solo asoma la que toca. La
     máscara vertical evita que el texto se corte a guillotina en el filo: se
     disuelve al entrar y al salir de la ranura. La máscara es ESTÁTICA — se
     resuelve una vez y no se anima nada. */
  html.lp-js:not(.lp-lite) .lp-flip-title {
    height: 78px; overflow: hidden;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 15%, #000 85%, transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0%, #000 15%, #000 85%, transparent 100%);
  }
  html.lp-js:not(.lp-lite) .lp-flip-cap {
    height: 78px; display: flex; flex-direction: column; justify-content: center;
  }
  html.lp-js:not(.lp-lite) .lp-flip-cap .t { white-space: nowrap; }
  html.lp-js:not(.lp-lite) .lp-face {
    border-radius: 0; border-color: transparent;
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--brand) 42%, transparent),
                0 0 46px -2px rgba(0, 0, 0, .72);
    will-change: transform, opacity;
    /* Estado de partida SOLO en película (contrato `html.lp-js`): las cuatro
       pantallas son absolutas y comparten hueco, así que sin esto se verían
       encabalgadas hasta que el primer frame del scrub decide cuál manda —los
       <script> de la película son `defer`—. Fuera de película el CSS entrega
       las cuatro enteras, que es la regla de la casa. */
    opacity: 0; visibility: hidden;
  }
  /* Y la primera se queda puesta: si landing-film.js no llegara (deploy a
     medias, bloqueador) la ventana enseña la bandeja en vez de un hueco. */
  html.lp-js:not(.lp-lite) .lp-face-a { opacity: 1; visibility: visible; }
  /* El hueco se conserva (la barra sigue ocupando su alto): sin esto el cuerpo
     de cada pantalla treparía debajo de la cabecera al entrar en película. */
  html.lp-js:not(.lp-lite) .lp-face-bar { visibility: hidden; }
  /* La cara D no tiene barra (los satélites la llenan a sangre): su
     constelación arranca por debajo de la cabecera del chasis. */
  html.lp-js:not(.lp-lite) .lp-face-d .lp-sat-wrap { top: var(--lp-bar-h); }
}

/* ══════════════════════════════════════════════════════════════════════════
   ACTO 4 · propose-confirm (la escena de la tesis)
   ══════════════════════════════════════════════════════════════════════════ */
.lp-thesis {
  position: relative; min-height: 150vh; background: var(--canvas);
}
.lp-thesis-sticky {
  position: sticky; top: 0; height: 100svh; height: 100vh;
  display: grid; place-items: center; overflow: clip; text-align: center;
}
.lp-thesis-ping {
  position: absolute; left: 50%; top: 42%; width: 10px; height: 10px;
  transform: translate(-50%,-50%); border-radius: 50%; pointer-events: none;
  border: 1.5px solid var(--accent); opacity: 0;
}
.lp-thesis-card {
  position: relative; z-index: 2; width: min(400px, 88vw);
  background: var(--surface); border: 1px solid color-mix(in srgb, var(--brand) 28%, var(--border));
  border-radius: var(--r-xl); padding: 22px; text-align: left;
  box-shadow: var(--sh-lg), 0 0 90px -22px color-mix(in srgb, var(--brand) 60%, transparent);
}
.lp-thesis-card .tag { font-family: var(--font-mono); font-size: 11px; color: var(--brand-text); letter-spacing: .08em; }
.lp-thesis-card h4 { font-size: 16px; font-weight: 620; color: var(--text-strong); margin: 8px 0 4px; letter-spacing: -.02em; }
/* El expediente de la propuesta: el mismo radicado que la bandeja (cara A) y
   el borrador (cara C) — un solo caso recorre la página. */
.lp-thesis-card .exp { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-subtle); letter-spacing: .01em; margin: 0 0 8px; }
.lp-thesis-card .exp b { color: var(--text); font-weight: 500; }
.lp-thesis-card .ev { font-size: 12.5px; color: var(--text-muted); margin: 0 0 16px; }
.lp-thesis-card .ev b { color: var(--text); font-weight: 600; }
.lp-thesis-actions { display: flex; gap: 10px; }
.lp-thesis-actions .btn { flex: 1; pointer-events: none; }
.lp-confirm-btn { position: relative; }
/* El check se TRAZA sin stroke-dashoffset (prohibido: repinta el trazo del SVG
   fuera del compositor). El glifo va entero dentro de una ventana de su tamaño
   y lo descubre una tapa opaca del color del botón sellado que se retira con
   translateX — la misma técnica de la tapa del radicado en #como. */
.lp-confirm-btn .chk {
  position: absolute; left: 50%; top: 50%; width: 20px; height: 20px;
  transform: translate(-50%, -50%); overflow: clip; opacity: 0;
}
.lp-confirm-btn .chk svg { position: absolute; inset: 0; width: 20px; height: 20px; }
.lp-confirm-btn .chk::after {
  content: ""; position: absolute; inset: 0;
  background: var(--brand); transform: translateX(0);
}
.lp-thesis-card.sealed .chk { opacity: 1; }
.lp-thesis-card.sealed .lbl { opacity: 0; }
.lp-thesis-card.sealed .lp-confirm-btn { background: var(--brand); }
.lp-thesis-card.sealed .chk::after { transform: translateX(101%); transition: transform .5s var(--ease-emph) .1s; }
/* EL SELLO TIENE RETROCESO. Sellar es un acto físico: la tarjeta encaja
   —cede un 1,4 % y vuelve— en vez de limitarse a cambiar de color. Va en
   `scale` para componerse con el latido de espera, que usa transform.
   Una sola pasada, 420 ms; nada queda corriendo después. */
.lp-thesis-card.sealed { animation: lp-sello-encaje 420ms var(--e-asienta) 1; }
@keyframes lp-sello-encaje {
  0%   { scale: 1; }
  26%  { scale: .986; }
  100% { scale: 1; }
}
.lp-ghost-cursor {
  position: absolute; z-index: 5; width: 22px; height: 22px; pointer-events: none; opacity: 0;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,.4));
}
.lp-thesis-line {
  position: absolute; left: 0; right: 0; bottom: clamp(40px, 10vh, 96px); z-index: 3;
  text-align: center; opacity: 0; padding: 0 24px;
}
.lp-thesis-line .big {
  font-size: clamp(1.8rem, 5.4vw, 4rem); font-weight: 300; letter-spacing: -.04em;
  color: var(--text-strong); line-height: 1.02; margin: 0;
}
.lp-thesis-line .big b { font-weight: 760; }
.lp-thesis-line .big em { font-style: italic; color: var(--brand-text); font-weight: 400; }

/* La decisión es del visitante: Confirmar es un <button> real que nace
   disabled (sin JS / lite se lee estático, sin dar clic a nada). initThesis
   lo arma añadiendo .is-armed a la sección y quitando el disabled. */
.lp-confirm-btn:disabled { cursor: default; }
/* LO QUE NO RESPONDE, SE VE QUE NO RESPONDE. El Confirmar solo se arma con la
   película: en lite, móvil, reduced-motion, sin JS y en papel quedaba un botón
   primario Iris con el mismo peso visual que los CTA vivos del hero, y su
   única señal de muerte era cursor:default —que en táctil no existe—. Lo mismo
   con «Descartar», que es ilustración del encuadre. Misma lengua para los dos:
   atenuados mientras no se pueden pulsar. */
.lp-thesis-actions .lp-inerte { cursor: default; opacity: .45; }
.lp-thesis:not(.is-armed) .lp-confirm-btn { opacity: .45; }
.lp-thesis.is-armed .lp-thesis-actions .lp-confirm-btn { pointer-events: auto; cursor: pointer; }
.lp-thesis.is-armed .lp-confirm-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* El fantasma dudó y se retiró: la tarjeta pulsa suave (transform/opacity,
   compositor) y espera la decisión. */
.lp-thesis-card.is-waiting { animation: lp-thesis-wait 2.2s var(--ease) infinite; }
.lp-thesis-card.is-waiting::after {
  content: ""; position: absolute; inset: -1px; border-radius: inherit;
  border: 1px solid color-mix(in srgb, var(--brand) 55%, transparent);
  pointer-events: none; opacity: 0;
  animation: lp-thesis-wait-ring 2.2s var(--ease) infinite;
}
@keyframes lp-thesis-wait {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.012); }
}
@keyframes lp-thesis-wait-ring {
  0%, 100% { opacity: 0; }
  50%      { opacity: .9; }
}

/* Toast mínimo abajo-izquierda de la escena: «Aplicado · Deshacer». Vive
   dentro del sticky (solo existe durante el acto) y la reversa es real. */
.lp-thesis-toast {
  position: absolute; left: clamp(16px, 3vw, 32px); bottom: clamp(64px, 9vh, 96px);
  z-index: 6; display: inline-flex; align-items: baseline; gap: 7px;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .04em;
  color: var(--text);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  padding: 9px 12px; box-shadow: var(--sh-md);
  opacity: 0; transform: translateY(8px); visibility: hidden;
  transition: opacity .3s var(--ease), transform .3s var(--ease-emph),
              visibility 0s linear .3s;
}
.lp-thesis-toast.on {
  opacity: 1; transform: none; visibility: visible;
  transition: opacity .3s var(--ease), transform .3s var(--ease-emph), visibility 0s;
}
.lp-thesis-toast .sep { color: var(--text-subtle); }
.lp-thesis-toast .undo {
  font: inherit; letter-spacing: inherit; color: var(--brand-text);
  background: none; border: 0; padding: 0; cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.lp-thesis-toast .undo:hover { color: var(--text-strong); }
.lp-thesis-toast .undo:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 4px; }

/* ══════════════════════════════════════════════════════════════════════════
   LA BITÁCORA — el deshacer también queda escrito
   --------------------------------------------------------------------------
   Al costado de la tarjeta, el libro de registro del expediente. Nace VACÍO
   («— sin decisiones registradas —») y eso solo ya prueba la doctrina: sin el
   humano no pasa nada. Después:
     · el clic REAL en Confirmar estampa el renglón de la decisión;
     · Deshacer NO lo borra — estampa un SEGUNDO renglón colgado del primero
       por una llave de 1px (la misma pieza que ancla la cita en la ficha del
       hero). El toast se queda: él es el mando, esto es la consecuencia.
   Los renglones se imprimen con la máscara .mk/.i del titular, y solo animan
   transform y opacity.

   La mesa es una rejilla de tres columnas con la tarjeta clavada en la del
   medio: el registro puede crecer sin mover el eje al que apunta el
   cursor-fantasma. A ≤940px se apila bajo la tarjeta.

   REGLA DE ORO DE ESTE BLOQUE: el estado por defecto es el registro IMPRESO
   con sus dos renglones ROTULADOS como ejemplo. Solo cuando initThesis arma
   la escena (.lp-thesis.is-armed, que exige JS + GSAP + no-lite + motion) el
   ejemplo se retira y el registro pasa a escribirlo el visitante. Así el
   papel, el sin-JS, el lite y el reduced-motion enseñan el formato sin fingir
   una decisión que nadie tomó.
   ══════════════════════════════════════════════════════════════════════════ */
.lp-thesis-mesa {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: min(400px, 88vw);
  justify-content: center; align-items: start;
  width: 100%; margin-inline: auto;
}
.lp-bit {
  text-align: left; margin-top: clamp(14px, 2.2vh, 20px);
  font-variant-numeric: tabular-nums;
  font-size: 10.5px; line-height: 1.5; letter-spacing: .01em;
  color: var(--text-muted);
}
/* tokens.css lleva un `* { font-family: var(--font-sans) }`: la mono NUNCA se
   hereda, hay que declararla en cada elemento (mismo motivo por el que la
   ficha del hero la repite en .rad y en el sello). El registro es instrumento
   → mono; el pie es prosa para el abogado → Inter, y se dice explícito. */
.lp-bit-head, .lp-bit-vacio, .lp-bit-mas, .lp-bit-rot,
.lp-bit-row, .lp-bit-row span { font-family: var(--font-mono); }
.lp-bit-pie { font-family: var(--font-sans); }
@media (min-width: 941px) {
  .lp-thesis-mesa {
    grid-template-columns: minmax(0, 1fr) min(400px, 88vw) minmax(0, 1fr);
    width: min(1180px, 96vw);
  }
  .lp-thesis-mesa > .lp-thesis-card { grid-column: 2; }
  .lp-thesis-mesa > .lp-bit {
    grid-column: 3; margin-top: 0;
    margin-left: clamp(18px, 2.2vw, 32px); max-width: 322px;
  }
}

.lp-bit-head {
  margin: 0 0 8px; padding-bottom: 7px;
  border-bottom: 1px solid var(--border);
  color: var(--text-subtle); letter-spacing: .05em;
}
.lp-bit-head .sep { opacity: .5; }

.lp-bitacora { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.lp-bit-vacio { color: var(--text-subtle); opacity: .78; }
.lp-bit-mas { color: var(--text-subtle); opacity: .7; }
.lp-bitacora.tiene-registro .lp-bit-vacio { display: none; }

.lp-bit-row { position: relative; color: var(--text-muted); }
/* Máscara de revelado, la misma del titular y de la ficha del hero. En reposo
   NO transforma nada: fuera de película el renglón nace impreso. */
.lp-bit-row .mk { display: block; overflow-y: clip; overflow-x: visible; }
.lp-bit-row .mk .i { display: block; }
.lp-bit-row .h { color: var(--brand-text); }
.lp-bit-row .vb { color: var(--text-strong); font-weight: 560; }
.lp-bit-row .ob { color: var(--text); }
.lp-bit-row .rd { color: var(--text-subtle); }
.lp-bit-row .sep { color: var(--text-subtle); opacity: .55; }

/* La reversa cuelga del renglón que revierte: la llave arranca dentro de la
   última línea del anterior y lo abraza. No lo reemplaza — lo continúa. */
.lp-bit-row.es-reversa { padding-left: 11px; }
.lp-bit-row.es-reversa .llave {
  position: absolute; left: 0; top: -11px; bottom: 3px; width: 5px;
  border: 1px solid color-mix(in srgb, var(--border-strong) 90%, transparent);
  border-right: 0;
}

/* El ejemplo rotulado: solo existe mientras la escena NO está armada. */
.lp-bit-ej {
  margin-top: 9px; padding-top: 8px;
  border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.lp-bit-rot {
  margin: 0 0 6px; font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-subtle); opacity: .72;
}
.lp-thesis.is-armed .lp-bit-ej { display: none; }

.lp-bit-pie {
  margin: 10px 0 0; padding-top: 8px;
  border-top: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  font-size: 10px; line-height: 1.55; color: var(--text-subtle);
}

/* ── Escena armada: el renglón se ESTAMPA (sube tras el filete) ──────────
   Las transiciones solo existen bajo .is-armed, que es exactamente cuando los
   renglones los crea el JS. Los del ejemplo nunca se enteran. */
.lp-thesis.is-armed .lp-bit-row .mk .i {
  transform: translateY(118%); opacity: 0;
  transition: transform .5s var(--ease-emph), opacity .34s var(--ease);
}
.lp-thesis.is-armed .lp-bit-row.on .mk .i { transform: none; opacity: 1; }
.lp-thesis.is-armed .lp-bit-row.es-reversa .llave {
  transform: scaleY(0); transform-origin: 50% 0;
  transition: transform .38s var(--ease-emph) .1s;
}
.lp-thesis.is-armed .lp-bit-row.es-reversa.on .llave { transform: none; }

/* ══════════════════════════════════════════════════════════════════════════
   Footer wordmark viewport-width en outline que se rellena al llegar
   ══════════════════════════════════════════════════════════════════════════ */
.lp-wordmark {
  text-align: center; padding: clamp(40px, 8vw, 90px) 0 20px; overflow: clip;
  line-height: 1;
}
.lp-wordmark .w {
  font-size: clamp(3.5rem, 22vw, 17rem); font-weight: 780; letter-spacing: -.04em;
  display: inline-block; position: relative;
}
/* Dos capas idénticas y registradas (misma caja, misma métrica): el relleno
   entra por OPACIDAD encima del contorno. Antes se barría background-position,
   que obliga a repintar el texto entero en cada frame. */
.lp-wordmark .wl { display: block; color: transparent; }
.lp-wordmark .wl.out {
  -webkit-text-stroke: 1.2px color-mix(in srgb, var(--brand) 42%, var(--border-strong));
  transition: opacity 1s var(--ease);
}
.lp-wordmark .wl.fill {
  position: absolute; inset: 0; opacity: 0;
  background: linear-gradient(90deg, var(--brand), var(--accent));
  -webkit-background-clip: text; background-clip: text;
  transition: opacity 1s var(--ease);
}
.lp-wordmark.on .wl.out { opacity: 0; }
.lp-wordmark.on .wl.fill { opacity: 1; }
.lp-wordmark .made { font-family: var(--font-mono); font-size: 11px; letter-spacing: .16em; color: var(--text-subtle); text-transform: uppercase; margin-top: 6px; }

/* ══════════════════════════════════════════════════════════════════════════
   RESPONSIVE / móvil-lite / reduced-motion
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 940px) {
  /* Móvil: la ficha se apila DEBAJO del titular y su llamado — nunca encima —
     y nace impresa. Sin hilo: no hay a dónde tirarlo. */
  .lp-salida { position: static; width: auto; max-width: 420px; margin-top: 26px; }
  .lp-hilo { display: none !important; }
  .lp-hero .lp-ficha { opacity: 1 !important; transform: none !important; }
  .lp-hero .lp-ficha .mk .i { transform: none !important; opacity: 1 !important; }
  /* La boleta también se apila, pegada a la ficha, y en VERSIÓN CORTA: en el
     teléfono se queda la casilla de la agenda con su marca de verificación y
     se retira la cita del auto, que es la línea larga. Dos piezas seguidas sin
     amontonar el hero (pliego, obs. 1b: «cuida que en móvil no amontone»). */
  .lp-boleta-w {
    position: static; width: auto; max-width: 420px; margin-top: 12px;
    top: auto; right: auto;
  }
  .lp-hero .lp-boleta { opacity: 1 !important; transform: none !important; }
  .lp-hero .lp-boleta .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-boleta .bo-rot, .lp-boleta .bo-auto { display: none; }
  .lp-boleta .bo-slot { border-top: 0; padding-top: 0; }
  .lp-device { width: min(560px, 92vw); }
  /* Bandeja A compacta: a 560px el alto 16/10 no da para filas de 60px.
     Mismas piezas, cuerpo más denso; el carril nace subido 52px (46 + gap 6).
     En lite/mobile las reglas html.lp-lite (más específicas) devuelven alto
     libre, texto que envuelve y carril quieto. */
  .lp-face-a .kpi { padding: 8px 10px; }
  .lp-face-a .kpi .n { font-size: 19px; }
  .lp-face-a .row { height: 46px; padding: 8px 12px; }
  .lp-face-a .row .t { font-size: 12px; line-height: 1.15; }
  .lp-face-a .row .d { font-size: 10px; line-height: 1.2; margin-top: 1px; }
  .lp-face-a .row .rad { font-size: 9.5px; }
  .lp-face-a .row .tw { font-size: 9px; }
  .lp-face-a .row .meta { gap: 3px; }
  .lp-face-a .a-rows { gap: 6px; transform: translateY(-52px); }
}
@media (max-width: 620px) {
  /* Con 4 líneas nowrap, en el móvil manda el ancho disponible: la línea
     larga mide 11,45 em y el canal es (100vw − 48px de gutter). La escala
     deja aire desde 320px y empalma con la del tramo de arriba en 621px. */
  .lp-display { font-size: min(calc(8.74vw - 5px), 2.35rem); }
  /* El sello se apila: así el radar-nav flotante (esquina inferior derecha)
     nunca se come el «pendiente de tu revisión». */
  .lp-ficha-sello .sep { display: none; }
  .lp-ficha-sello .vence, .lp-ficha-sello .rev { display: block; }
  .lp-hero-foot { flex-direction: column; align-items: flex-start; gap: 16px; }
  .lp-scrollcue { flex-direction: row; }
  .lp-scrollcue .ln { width: 30px; height: 1px; }
  /* Variante horizontal, con la misma traducción a transform. */
  .lp-scrollcue .ln::after { top: 0; left: 0; width: 50%; height: 100%;
    background: linear-gradient(90deg, var(--accent), transparent);
    transform: translateX(-110%); animation: lp-cue-h 1.9s var(--ease) infinite; }
  @keyframes lp-cue-h {
    0%        { transform: translateX(-110%); }
    60%, 100% { transform: translateX(210%); }
  }
}

/* Móvil-lite: los actos pineados se vuelven deck estático (crossfade simple).
   Se activa por .lp-lite en <html> (lo pone landing-film.js en touch/angosto). */
html.lp-lite .lp-flip,
html.lp-lite .lp-thesis { height: auto; min-height: 0; }
html.lp-lite .lp-flip-sticky,
html.lp-lite .lp-thesis-sticky { position: relative; height: auto; min-height: 0; display: block; perspective: none; padding: clamp(40px,10vw,80px) 0; }
html.lp-lite .lp-device { transform: none !important; width: min(560px, 92vw); margin: 0 auto; aspect-ratio: auto; }
html.lp-lite .lp-face {
  position: relative; inset: auto; transform: none !important; backface-visibility: visible;
  margin-bottom: 20px; opacity: 1 !important; visibility: visible !important;
}
/* Si alguien encoge la ventana con la película ya montada, initFlip suelta lo
   que escribió (mismo `soltar()` que la lectura del fallo). Esto es el
   cinturón: en editorial ni el chasis es ventana ni las piezas llevan turno. */
html.lp-lite .lp-chrome { display: none !important; }
html.lp-lite .lp-face [data-pz] { transform: none !important; opacity: 1 !important; }
html.lp-lite .lp-face-d { min-height: 320px; }
/* En editorial las 4 leyendas dejan de apilarse en el mismo grid-area y fluyen
   como bloques visibles (una lista legible), no una sola leyenda superpuesta. */
html.lp-lite .lp-flip-title { position: relative; transform: none; left: auto; bottom: auto; width: 100%; margin-bottom: 20px; display: block; }
html.lp-lite .lp-flip-cap { grid-area: auto; opacity: 1 !important; transform: none !important; margin-bottom: 14px; }
html.lp-lite .lp-thesis-line { position: relative; opacity: 1; bottom: auto; margin-top: 30px; }
html.lp-lite .lp-thesis-toast { display: none; }
html.lp-lite .lp-cite { opacity: 1; transform: none; }
html.lp-lite .lp-face-b .stream .cur { display: none; }
/* Bandeja A en editorial: la alerta ya visible («hace un momento»), el
   odómetro clavado en 5, filas de alto libre y texto que envuelve. */
html.lp-lite .lp-face-a .a-rows { transform: none; }
html.lp-lite .lp-face-a .row { height: auto; }
html.lp-lite .lp-face-a .row .t, html.lp-lite .lp-face-a .row .d { white-space: normal; }
html.lp-lite .lp-face-a .row-alerta { opacity: 1; }
html.lp-lite .lp-face-a .a-odo-roll { transform: translateY(-50%); }
html.lp-lite .lp-face-a .tw-live { display: none; }
html.lp-lite .lp-face-a .tw-static { display: inline; }
/* La salida, impresa: en lite no hay barrido que cruce nada. */
html.lp-lite .lp-hilo { display: none !important; }
html.lp-lite .lp-ficha { opacity: 1 !important; transform: none !important; }
html.lp-lite .lp-ficha .mk .i { transform: none !important; opacity: 1 !important; }
html.lp-lite .lp-boleta { opacity: 1 !important; transform: none !important; }
html.lp-lite .lp-boleta .mk .i { transform: none !important; opacity: 1 !important; }

/* Reduced-motion: versión EDITORIAL completa (misma que móvil-lite en estructura,
   pero además apaga las animaciones decorativas). */
@media (prefers-reduced-motion: reduce) {
  .lp-flip, .lp-thesis { height: auto; min-height: 0; }
  .lp-flip-sticky, .lp-thesis-sticky { position: relative; height: auto; min-height: 0; display: block; perspective: none; padding: clamp(40px,10vw,80px) 0; }
  .lp-device { transform: none !important; width: min(600px, 92vw); margin: 0 auto; aspect-ratio: auto; }
  .lp-face { position: relative; inset: auto; transform: none !important; backface-visibility: visible; margin-bottom: 20px; opacity: 1 !important; visibility: visible !important; }
  .lp-chrome { display: none !important; }
  .lp-face [data-pz] { transform: none !important; opacity: 1 !important; }
  .lp-face-d { min-height: 320px; }
  .lp-flip-title { position: relative; transform: none; left: auto; bottom: auto; width: 100%; margin-bottom: 20px; display: block; }
  .lp-flip-cap { grid-area: auto; opacity: 1 !important; transform: none !important; margin-bottom: 14px; }
  .lp-thesis-line { position: relative; opacity: 1; bottom: auto; margin-top: 30px; }
  .lp-thesis-toast { display: none; }
  .lp-thesis-card.is-waiting, .lp-thesis-card.is-waiting::after { animation: none; }
  /* El encaje del sello es un gesto: aquí no existe. (La levitación de la
     constelación no hace falta apagarla — la calcula el JS de la película, que
     con reduced-motion no llega a montarse.) */
  .lp-thesis-card.sealed { animation: none !important; }
  /* La bitácora: registro impreso con su ejemplo rotulado, sin un solo gesto. */
  .lp-bit-row .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-bit-row.es-reversa .llave { transform: none !important; }
  .lp-cite { opacity: 1; transform: none; }
  .lp-display .ln .i { transform: none !important; opacity: 1 !important; }
  /* La salida: ficha impresa junto al radar en frame estático, sin hilo. */
  .lp-hilo { display: none !important; }
  .lp-ficha { opacity: 1 !important; transform: none !important; }
  .lp-ficha .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-boleta { opacity: 1 !important; transform: none !important; }
  .lp-boleta .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-scrollcue .ln::after, .lp-face-b .stream .cur { animation: none; }
  /* Bandeja A: estado final quieto — alerta visible, odómetro en 5, sin rodar. */
  .lp-face-a .a-rows { transform: none; }
  .lp-face-a .row { height: auto; }
  .lp-face-a .row .t, .lp-face-a .row .d { white-space: normal; }
  .lp-face-a .row-alerta { opacity: 1; }
  .lp-face-a .a-odo-roll { transform: translateY(-50%); }
  .lp-face-a .tw-live { display: none; }
  .lp-face-a .tw-static { display: inline; }
  .lp-face-a .a-rows, .lp-face-a .row-alerta, .lp-face-a .a-odo-roll,
  .lp-face-a .lp-pill.live { animation: none; }
  .lp-grain { display: none; }
  .lp-wordmark .wl.out { opacity: 0; }
  .lp-wordmark .wl.fill { opacity: 1; }
}

/* En papel manda el contenido: fuera los artefactos efímeros de la escena
   (fantasma, ping, toast), el manifiesto siempre visible aunque el JS lo
   haya dejado con opacidad 0 inline, y la bandeja de la cara A completa
   (la fila de alerta nace oculta para la película: en papel se imprime). */
@media print {
  .lp-ghost-cursor, .lp-thesis-ping, .lp-thesis-toast { display: none !important; }
  /* En papel no hay nada que pulsar: los dos rótulos de la tarjeta van a
     tinta plena, el gris del estado inerte solo los haría ilegibles. */
  .lp-thesis-actions .lp-inerte, .lp-thesis .lp-confirm-btn { opacity: 1 !important; }
  /* En papel la ficha se imprime completa (el JS pudo dejarla en cine). */
  .lp-hilo { display: none !important; }
  .lp-salida { position: static !important; width: auto !important; max-width: 420px; margin-top: 22px; }
  .lp-ficha { opacity: 1 !important; transform: none !important; box-shadow: none !important; }
  .lp-ficha .mk .i { transform: none !important; opacity: 1 !important; }
  /* La boleta también, y en papel sí va COMPLETA: la cita del auto es lo que
     prueba la lectura, y en una hoja hay sitio de sobra para ella. */
  .lp-boleta-w {
    position: static !important; width: auto !important; max-width: 420px;
    top: auto !important; right: auto !important; margin-top: 14px;
  }
  .lp-boleta { opacity: 1 !important; transform: none !important; box-shadow: none !important; }
  .lp-boleta .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-boleta .bo-rot, .lp-boleta .bo-auto { display: block !important; }
  .lp-thesis-line {
    position: relative !important; opacity: 1 !important; transform: none !important;
    bottom: auto !important; margin-top: 30px;
  }
  /* La bitácora se imprime entera y sin máscaras. El ejemplo rotulado vuelve
     a aparecer SOLO si el visitante no registró nada: si sí decidió, en el
     papel quedan sus renglones y el ejemplo sobra. */
  .lp-bit, .lp-bit-ej { display: block !important; }
  .lp-bit-row .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-bit-row.es-reversa .llave { transform: none !important; }
  .lp-bitacora.tiene-registro ~ .lp-bit-ej { display: none !important; }
  .lp-face-a .a-rows { transform: none !important; animation: none !important; }
  .lp-face-a .row { height: auto !important; }
  .lp-face-a .row .t, .lp-face-a .row .d { white-space: normal !important; }
  .lp-face-a .row-alerta { opacity: 1 !important; animation: none !important; }
  .lp-face-a .a-odo-roll { transform: translateY(-50%) !important; animation: none !important; }
  .lp-face-a .tw-live { display: none !important; }
  .lp-face-a .tw-static { display: inline !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   EL MURO · el aislamiento demostrado   (#diferenciadores · tarjeta 03)
   --------------------------------------------------------------------------
   Dos paneles hairline lado a lado —«tu firma» y «otro cliente de myvigia»,
   las dos con sesión abierta— separados por UNA vertical de 1px que atraviesa
   el bloque: la frontera de la base de datos. En los dos se imprime la MISMA
   consulta con el MISMO radicado (el expediente que recorre toda la página).

   La fila entra al viewport → landing-muro.js pone .mu-on una sola vez:
     · panel izquierdo: la línea de 1px corre horizontal, muere en un quiebre
       que baja a la ficha, y la ficha se imprime con su «1 resultado»;
     · panel derecho: la misma línea, espejada, corre hasta la vertical del
       centro, CHOCA, la pared se enciende un instante y la línea rebota
       (~180 ms). Después imprime «sin resultados» y la nota en mono.
   Las dos líneas llegan a su destino en el mismo instante (1,07 s): mismo
   gesto, mismos datos, resultados opuestos. Ahí está la demostración.

   REGLA DE ORO (la misma de la salida del hero): el estado por defecto es el
   de los dos paneles con su resultado YA IMPRESO —sin líneas, sin rebote—.
   Así lo leen el papel, el sin-JS, el lite, el reduced-motion y el móvil (que
   además apila los paneles y pasa la vertical a horizontal). El vaciado
   cuelga de .mu-cine, clase que solo pone el JS, y encima va gateado por
   media query: encoger la ventana devuelve los paneles impresos aunque la
   película ya estuviera armada.

   Todo el movimiento son @keyframes de transform/opacity: encender el modo no
   puede animar nada hacia atrás (con transiciones, añadir .mu-cine habría
   sacado el contenido del panel a la vista del visitante).
   ══════════════════════════════════════════════════════════════════════════ */
.lp-muro { position: relative; margin-top: clamp(18px, 2.4vw, 26px); padding: 18px 0; }
.lp-muro .mu-panels {
  display: grid; grid-template-columns: minmax(0, 1fr) 1px minmax(0, 1fr);
  align-items: stretch;
}
/* La pared es una PISTA del grid: cae exacta en la costura de los dos paneles
   sin una sola coordenada, y en móvil se vuelve horizontal sola. Los márgenes
   negativos la sacan por arriba y por abajo — atraviesa el bloque entero. */
.lp-muro .mu-pared { display: block; background: var(--border-strong); margin: -18px 0; }

.lp-muro .mu-panel {
  display: grid; align-content: start; gap: 11px; min-width: 0;
  padding: 13px 14px 14px; border: 1px solid var(--border);
}
/* Los paneles se tocan: entre ellos no hay dos filetes, hay una sola pared. */
.lp-muro .mu-a { border-right: 0; border-radius: var(--r-sm) 0 0 var(--r-sm); }
.lp-muro .mu-b { border-left: 0; border-radius: 0 var(--r-sm) var(--r-sm) 0; }

.lp-muro .mu-cab {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .02em;
  line-height: 1.4; color: var(--text-subtle);
}
.lp-muro .mu-a .mu-cab b { font-weight: 500; color: var(--text); }
.lp-muro .sep { opacity: .5; margin: 0 5px; }

/* El campo de búsqueda: IDÉNTICO en los dos paneles. Misma caja, misma
   etiqueta, mismo radicado — la única variable del experimento es la sesión. */
.lp-muro .mu-campo {
  display: grid; gap: 5px; padding: 8px 10px;
  border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--surface-2) 55%, transparent);
}
.lp-muro .mu-campo .et {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-muro .mu-campo .mk .i {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .01em;
  font-variant-numeric: tabular-nums; color: var(--text-strong); white-space: nowrap;
}

/* Máscara de revelado del sistema (la misma de la ficha del hero). En reposo
   NO transforma nada: el papel imprime texto normal. */
.lp-muro .mk { display: block; overflow-y: clip; overflow-x: visible; }
.lp-muro .mk .i { display: block; }

/* La vía: por aquí viaja la consulta. Full-bleed hasta el borde del panel —
   así la línea del panel derecho llega a TOCAR la pared—. Solo existe en
   película: fuera de ella no hay líneas ni carril que ocupe alto. */
.lp-muro .mu-via { display: none; position: relative; height: 1px; margin: 3px -14px 0; }
.lp-muro .mu-linea { position: absolute; top: 0; height: 1px; background: var(--brand); }
.lp-muro .mu-a .mu-linea { left: 0;  width: 72%;  transform-origin: left center; }
.lp-muro .mu-b .mu-linea { right: 0; width: 100%; transform-origin: right center; }
/* Donde muere la línea de la izquierda, un quiebre de 1px baja a la ficha. */
.lp-muro .mu-tic {
  position: absolute; top: 0; left: calc(72% - 1px); width: 1px; height: 12px;
  background: var(--brand); transform-origin: top center;
}
/* El golpe: la pared se enciende 1px en el punto exacto del contacto. */
.lp-muro .mu-golpe {
  position: absolute; top: -9px; left: -1px; width: 1px; height: 19px;
  background: var(--brand); transform-origin: center center;
}

.lp-muro .mu-res { display: grid; gap: 9px; align-content: start; min-height: 66px; }
.lp-muro .mu-b .mu-res { gap: 6px; padding-top: 2px; }
.lp-muro .mu-ficha {
  display: grid; gap: 3px; padding: 9px 10px; transform-origin: 0 0;
  border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
  border-radius: var(--r-sm);
}
.lp-muro .mu-ficha .act { font-size: 12.5px; line-height: 1.3; font-weight: 560; color: var(--text-strong); }
.lp-muro .mu-ficha .det { font-size: 11px; line-height: 1.4; color: var(--text-muted); }
.lp-muro .cuenta .i {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .015em;
  font-variant-numeric: tabular-nums; color: var(--text-subtle);
}
.lp-muro .vacio .i { font-size: 12.5px; line-height: 1.3; font-weight: 560; color: var(--text-muted); }
.lp-muro .nota .i {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .015em;
  line-height: 1.5; color: var(--text-subtle);
}

/* ── Película: solo donde cabe ─────────────────────────────────────────────
   El gate va por media query ADEMÁS de por clase: si la ventana baja de 941px
   —o el visitante pide menos movimiento— manda el estado impreso aunque el JS
   ya hubiera armado la escena. */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  .lp-muro.mu-cine .mu-via { display: block; }
  .lp-muro.mu-cine .mk .i { transform: translateY(112%); opacity: 0; }
  .lp-muro.mu-cine .mu-ficha { opacity: 0; transform: scaleY(.55); }
  .lp-muro.mu-cine .mu-linea { transform: scaleX(0); }
  .lp-muro.mu-cine .mu-tic { transform: scaleY(0); }
  .lp-muro.mu-cine .mu-golpe { opacity: 0; }

  /* La consulta se imprime en los dos paneles A LA VEZ: mismo retardo. */
  .lp-muro.mu-on .mu-campo .mk .i { animation: mu-imprime .58s var(--ease-emph) .06s both; }

  /* Izquierda: corre, encuentra, imprime. */
  .lp-muro.mu-on .mu-a .mu-linea { animation: mu-corre .52s linear .55s both; }
  .lp-muro.mu-on .mu-a .mu-tic { animation: mu-cae .16s var(--ease) 1.07s both; }
  .lp-muro.mu-on .mu-a .mu-ficha { animation: mu-abre .34s var(--ease-emph) 1.12s both; }
  .lp-muro.mu-on .mu-a .mu-ficha .mk:nth-child(1) .i { animation: mu-imprime .58s var(--ease-emph) 1.26s both; }
  .lp-muro.mu-on .mu-a .mu-ficha .mk:nth-child(2) .i { animation: mu-imprime .58s var(--ease-emph) 1.33s both; }
  .lp-muro.mu-on .mu-a .cuenta .i { animation: mu-imprime .5s var(--ease-emph) 1.45s both; }

  /* Derecha: corre igual, choca contra la pared y rebota. */
  .lp-muro.mu-on .mu-b .mu-linea { animation: mu-choque .7s linear .55s both; }
  .lp-muro.mu-on .mu-b .mu-golpe { animation: mu-chispa .34s var(--ease) 1.06s both; }
  .lp-muro.mu-on .mu-b .vacio .i { animation: mu-imprime .5s var(--ease-emph) 1.3s both; }
  .lp-muro.mu-on .mu-b .nota .i { animation: mu-imprime .5s var(--ease-emph) 1.44s both; }
}
@keyframes mu-imprime { from { transform: translateY(112%); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes mu-abre { from { opacity: 0; transform: scaleY(.55); } to { opacity: 1; transform: none; } }
@keyframes mu-corre { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes mu-cae { from { transform: scaleY(0); } to { transform: scaleY(1); } }
/* El rebote: llega a la pared al 74% de los 700 ms (1,07 s de reloj, el mismo
   instante en que la izquierda llega a su ficha) y los ~180 ms que quedan son
   el retroceso y el asiento. Solo scaleX: ni width ni left. */
@keyframes mu-choque {
  0%   { transform: scaleX(0); }
  74%  { transform: scaleX(1); }
  84%  { transform: scaleX(.86); }
  93%  { transform: scaleX(.94); }
  100% { transform: scaleX(.9); }
}
@keyframes mu-chispa {
  0%   { opacity: 0; transform: scaleY(.25); }
  16%  { opacity: .95; transform: scaleY(1); }
  100% { opacity: 0; transform: scaleY(1); }
}

/* ── Móvil (≤940px): los paneles apilan y la pared pasa a horizontal ─────── */
@media (max-width: 940px) {
  .lp-muro { padding: 4px 0; }
  .lp-muro .mu-panels { grid-template-columns: minmax(0, 1fr); }
  .lp-muro .mu-pared { height: 1px; margin: 0; }
  .lp-muro .mu-a { border-right: 1px solid var(--border); border-bottom: 0; border-radius: var(--r-sm) var(--r-sm) 0 0; }
  .lp-muro .mu-b { border-left: 1px solid var(--border); border-top: 0; border-radius: 0 0 var(--r-sm) var(--r-sm); }
  .lp-muro .mu-res { min-height: 0; }
  /* El radicado son 29 caracteres en mono: en un teléfono angosto no cabe en
     una línea y aquí ya no hay línea con la que alinearlo — se le deja
     quebrar por los guiones antes que salirse del panel. */
  .lp-muro .mu-campo .mk .i { white-space: normal; }
}

/* ── Estado impreso, blindado (lite · reduced-motion · papel) ─────────────
   Redundante con el gate de arriba a propósito: pase lo que pase con las
   clases, aquí los dos paneles se leen quietos y completos. */
html.lp-lite .lp-muro .mu-via { display: none !important; }
html.lp-lite .lp-muro .mk .i { transform: none !important; opacity: 1 !important; }
html.lp-lite .lp-muro .mu-ficha { opacity: 1 !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
  .lp-muro .mu-via { display: none !important; }
  .lp-muro .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-muro .mu-ficha { opacity: 1 !important; transform: none !important; }
}
@media print {
  .lp-muro .mu-via { display: none !important; }
  .lp-muro .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-muro .mu-ficha { opacity: 1 !important; transform: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   EL PLIEGO — la cita que se abre                       (diferenciador 02)
   --------------------------------------------------------------------------
   UNA frase de una respuesta del asistente que cierra en el chip T-023/24 (un
   <button aria-expanded> real): al abrirlo BAJA una llave de 1px por el margen
   de las palabras exactas que esa cita sostiene, se traza su subrayado —un <i>
   escalado por scaleX, nunca text-decoration— y a la derecha se imprime el
   pliego con los identificadores verificables de la providencia. El chip no
   enlaza a la relatoría: nadie sale de la página, se le entregan los datos con
   los que puede ir a buscarla.

   14-ago-2026: se retiró la SEGUNDA frase («sin fuente») con su bloque de
   negativa, sus reglas .pr-abre-nada y el reparto de celda que las alternaba.
   Decía lo mismo que EL ANTÍDOTO de #capacidades —pantalla del asistente y
   compuerta del lookup—, que lo demuestra mucho mejor. Aquí la prohibición
   queda enunciada una vez, en el pie.

   ESTADO BASE = TODO ABIERTO E IMPRESO. Todo el colapso vive dentro del media
   query de abajo y colgado de .pr-vivo (la clase la pone landing-cita.js). Por
   construcción no puede aplicarse en móvil, con reduced-motion ni en lite: allí
   no hay nada que overridear con !important porque no hay nada que apagar. Sin
   JS el botón se queda disabled y la pieza se lee entera y quieta.

   Solo se animan transform y opacity.
   ══════════════════════════════════════════════════════════════════════════ */
.pr-cita .pr-demo {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 300px);
  gap: clamp(20px, 2.6vw, 38px); align-items: start;
  margin-top: 20px;
}
.pr-cita .pr-resp { min-width: 0; }
.pr-cita .pr-quien {
  display: block; margin-bottom: 11px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-subtle);
}
/* Las dos frases. El sangrado de 15px es el carril de la llave: lo llevan las
   dos para que el bloque tenga un solo margen izquierdo. */
.pr-cita .pr-fr {
  position: relative; margin: 0; padding-left: 15px; max-width: 60ch;
  font-size: 14.5px; line-height: 1.62; color: var(--text);
}
.pr-cita .pr-fr + .pr-fr { margin-top: 13px; }

/* La llave: la misma pieza de 1px de .lp-ficha-cita .llave. Aquí abraza las
   palabras exactas y por eso su caja la mide el JS sobre el span real
   (--k-top/--k-h); sin medida abraza la frase entera, que también es cierto. */
.pr-cita .pr-fr-a .llave {
  position: absolute; left: 0; width: 5px;
  top: var(--k-top, 2px); height: var(--k-h, calc(100% - 4px));
  border: 1px solid color-mix(in srgb, var(--border-strong) 90%, transparent);
  border-right: 0;
}
/* Las palabras que la cita sostiene.
   IMPRESAS (móvil, papel, lite, sin JS): inline puro, para que envuelvan como
   texto, y el subrayado va en un box-shadow clonado por fragmento — a prueba de
   saltos de línea, y tampoco es text-decoration. El <i> se queda fuera: con la
   frase partida en dos renglones dibujaría UNA barra al pie de la caja entera,
   que no subraya nada y parece un filete suelto.
   CON GESTO (abajo): inline-block, una sola caja medible que no se parte, y ahí
   sí manda el <i> escalado por scaleX. */
.pr-cita .pr-pal {
  position: relative; display: inline;
  color: var(--text-strong); font-weight: 560;
  box-shadow: inset 0 -1px 0 var(--brand);
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
.pr-cita .pr-pal .pr-sub {
  display: none;
  position: absolute; left: 0; right: 0; bottom: -3px; height: 1px;
  background: var(--brand);
}

/* El cierre de la frase: el chip que abre el pliego. */
.pr-cita .pr-chip {
  display: inline-block; vertical-align: baseline; margin: 0;
  padding: 3px 8px; border-radius: var(--r-full);
  font-family: var(--font-mono); font-size: 10.5px; line-height: 1.35;
  letter-spacing: .02em; font-variant-numeric: tabular-nums;
  white-space: nowrap; cursor: default;
}
.pr-cita .pr-chip {
  background: var(--brand-tint); color: var(--brand-text);
  border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
}

/* La columna del pliego, contra un filete permanente. */
.pr-cita .pr-lado {
  display: grid; gap: 18px; min-width: 0;
  padding-left: clamp(14px, 1.6vw, 20px);
  border-left: 1px solid var(--border);
}
.pr-cita .pr-tit {
  margin: 0 0 4px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-subtle);
}
.pr-cita .pr-pliego { display: grid; gap: 8px; align-content: start; }
/* Máscara de revelado, la misma del titular y de la ficha del hero. */
.pr-cita .pr-lado .mk { display: block; overflow-y: clip; overflow-x: visible; }
.pr-cita .pr-lado .mk .i { display: block; }
/* Solo los renglones del pliego son rejilla clave/valor: el rótulo comparte
   la máscara pero no la rejilla, o se le parte en tres líneas. */
.pr-cita .pr-pliego .pr-row .mk .i {
  display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: 10px;
  align-items: baseline;
}
.pr-cita .pr-pliego .k {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .06em;
  color: var(--text-subtle);
}
.pr-cita .pr-pliego .v {
  font-size: 12.5px; line-height: 1.38; color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}

/* ── El gesto: solo donde cabe ─────────────────────────────────────────────
   Todo lo que sigue colapsa la pieza, y vive dentro de este media query. En
   móvil, con reduced-motion o en lite ni siquiera se declara: allí la pieza es
   el HTML tal cual, abierta. La clase .pr-vivo la pone el JS; .pr-anim entra un
   frame después y es la ÚNICA que declara transiciones, para que el recogido
   inicial no se vea animarse. */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-pliego { opacity: 0; }
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-lado .mk .i { transform: translateY(118%); opacity: 0; }
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-fr-a .llave { transform: scaleY(0); transform-origin: 50% 0; }
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-pal { display: inline-block; box-shadow: none; }
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-pal .pr-sub {
    display: block; transform: scaleX(0); transform-origin: left center;
  }
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-chip { cursor: pointer; }

  /* Transiciones: solo con .pr-anim. */
  html:not(.lp-lite) .pr-cita.pr-anim .pr-pliego { transition: opacity .2s var(--ease); }
  html:not(.lp-lite) .pr-cita.pr-anim .pr-lado .mk .i {
    transition: transform .52s var(--ease-emph), opacity .3s var(--ease);
  }
  html:not(.lp-lite) .pr-cita.pr-anim .pr-fr-a .llave { transition: transform .4s var(--ease-emph); }
  html:not(.lp-lite) .pr-cita.pr-anim .pr-pal .pr-sub { transition: transform .5s var(--ease-emph) .08s; }
  /* El acuse del puntero es instantáneo y a pelo: solo se animan transform y
     opacity en toda la pieza, así que el filete del chip cambia sin transición. */
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-chip:hover,
  html:not(.lp-lite) .pr-cita.pr-vivo .pr-chip:focus-visible {
    border-color: color-mix(in srgb, var(--brand) 62%, transparent);
  }

  /* ABIERTA LA CITA — primero baja la llave, después se traza el subrayado y
     al final el pliego se imprime renglón por renglón. La causa antes que el
     efecto: nada de esto arranca si el visitante no toca el chip. */
  html:not(.lp-lite) .pr-cita.pr-vivo.pr-abre-cita .pr-pliego { opacity: 1; }
  html:not(.lp-lite) .pr-cita.pr-vivo.pr-abre-cita .pr-fr-a .llave { transform: scaleY(1); }
  html:not(.lp-lite) .pr-cita.pr-vivo.pr-abre-cita .pr-pal .pr-sub { transform: scaleX(1); }
  html:not(.lp-lite) .pr-cita.pr-vivo.pr-abre-cita .pr-pliego .mk .i { transform: none; opacity: 1; }
  html:not(.lp-lite) .pr-cita.pr-anim.pr-abre-cita .pr-pliego .pr-tit .i { transition-delay: .16s; }
  html:not(.lp-lite) .pr-cita.pr-anim.pr-abre-cita .pr-pliego .pr-row:nth-of-type(1) .i { transition-delay: .24s; }
  html:not(.lp-lite) .pr-cita.pr-anim.pr-abre-cita .pr-pliego .pr-row:nth-of-type(2) .i { transition-delay: .30s; }
  html:not(.lp-lite) .pr-cita.pr-anim.pr-abre-cita .pr-pliego .pr-row:nth-of-type(3) .i { transition-delay: .36s; }
  html:not(.lp-lite) .pr-cita.pr-anim.pr-abre-cita .pr-pliego .pr-row:nth-of-type(4) .i { transition-delay: .42s; }
  html:not(.lp-lite) .pr-cita.pr-anim.pr-abre-cita .pr-pliego .pr-row:nth-of-type(5) .i { transition-delay: .48s; }

}

/* Móvil: la columna del pliego pasa debajo y el filete se acuesta. */
@media (max-width: 940px) {
  .pr-cita .pr-demo { grid-template-columns: 1fr; gap: 18px; }
  .pr-cita .pr-lado {
    border-left: 0; padding-left: 0;
    border-top: 1px solid var(--border); padding-top: 15px;
  }
}

/* Papel: el JS pudo dejar .pr-vivo puesto al imprimir desde el escritorio.
   Aquí manda el pliego completo, los dos bloques uno bajo otro y nada movido. */
@media print {
  .pr-cita .pr-demo { grid-template-columns: 1fr !important; }
  .pr-cita .pr-lado {
    border-left: 0 !important; padding-left: 0 !important;
    border-top: 1px solid var(--border); padding-top: 12px;
  }
  .pr-cita .pr-lado > * { grid-area: auto !important; opacity: 1 !important; }
  .pr-cita .pr-lado .mk .i { transform: none !important; opacity: 1 !important; }
  .pr-cita .pr-fr-a .llave {
    transform: none !important; top: 2px !important; height: calc(100% - 4px) !important;
  }
  .pr-cita .pr-pal {
    display: inline !important;
    box-shadow: inset 0 -1px 0 var(--brand) !important;
  }
  .pr-cita .pr-pal .pr-sub { display: none !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   LA BIBLIOTECA — el corpus como interfaz      (diferenciador 02 · segundo acto)
   --------------------------------------------------------------------------
   (pliego, obs. 12: «hablemos mejor de lo que es el corpus… se ve muy simple,
   no tan interfaz».) La respuesta no es una cifra grande: es ENSEÑAR el
   mecanismo, que es lo único que la competencia no puede copiar en una frase.

   Un panel con el LOMO de una providencia partido en sus cuatro secciones
   reales (app/models/biblioteca.py:45-51). Dentro de cada una, sus fragmentos
   como bloques hairline. Los de CONSIDERACIONES y RESUELVE van a tinta de
   marca: son los únicos que pueden sostener la posición de la Corte
   (ui_asistente.py:404-412). Los de ANTECEDENTES quedan apagados y rotulados
   —argumentos de las partes—: ese es el error que comete un buscador por
   parecido, y aquí se ve por qué este no lo comete.

   Debajo, las dos ramas que corren A LA VEZ (densa por significado, sparse por
   palabra, fusionadas por RRF k=60 — busqueda.py:37,44) y lo que queda: ocho
   fragmentos, cada uno con su sección.

   Al costado, la COBERTURA DECLARADA: corporación, años y lo que queda FUERA.
   Ninguna cifra de providencias — el contenedor de producción no lleva el
   corpus y el número real hay que leerlo de `jur_fuentes.docs_indexados`
   (INVENTARIO_CAPACIDADES.md §8). Lo que sí es cierto: ese alcance y su fecha
   de corte viajan declarados en cada respuesta.

   La rejilla del corpus REPITE la del pliego de arriba (1fr / 300px con filete
   en la costura): las dos mitades de la tarjeta se leen como una sola pieza.

   ESTADO BASE = TODO IMPRESO. La coreografía cuelga de .lp-shown (que pone el
   IntersectionObserver de landing.js) y encima va gateada por media query: en
   móvil, en lite, con reduced-motion, sin JS y en papel no hay nada que
   encender. Solo se animan transform y opacity.
   ══════════════════════════════════════════════════════════════════════════ */
.lp-corpus {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 300px);
  gap: clamp(20px, 2.6vw, 38px); align-items: start;
  margin-top: clamp(20px, 2.6vw, 30px);
  padding-top: clamp(16px, 2vw, 22px);
  border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
/* El panel: la misma materia del Contador y de la ventana del clasificador. */
.lp-corpus .co-panel {
  min-width: 0; overflow: clip;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  border: 1px solid var(--border); border-radius: var(--r-sm);
}
.lp-corpus .co-top {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 50%, transparent);
}
.lp-corpus .co-path {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-corpus .co-est {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--brand-text);
  padding: 2px 8px; border-radius: var(--r-full);
  border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
}

/* El lomo. Carril de 104 px para el rótulo de la sección: «consideraciones»
   son 15 signos en mono a 9,5 px con .1em y piden 98. */
.lp-corpus .co-doc { display: grid; gap: 9px; padding: 12px 12px 4px; }
.lp-corpus .co-sec {
  display: grid; grid-template-columns: 104px minmax(0, 1fr);
  gap: 3px 10px; align-items: center;
}
.lp-corpus .co-sec .et {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-subtle);
}
/* Los fragmentos. Bloques de 7 px que se reparten el ancho de la sección: se
   ve de un golpe dónde hay materia citable y dónde no.
   La media tinta vive en el COLOR, no en `opacity`: el keyframe de entrada
   termina en opacity 1 con fill `both`, así que una opacidad en el elemento
   quedaría pisada para siempre al acabar la animación y los fragmentos de
   antecedentes se leerían tan fuertes como los citables. */
.lp-corpus .chs { display: flex; gap: 3px; min-width: 0; }
.lp-corpus .chs i {
  display: block; flex: 1 1 0; height: 7px; border-radius: 1px;
  background: color-mix(in srgb, var(--text-muted) 34%, transparent);
  transform-origin: left center;
}
.lp-corpus .es-ratio .chs i { background: color-mix(in srgb, var(--brand) 62%, transparent); }
.lp-corpus .co-sec .ad {
  grid-column: 2; font-family: var(--font-mono); font-size: 9.5px;
  letter-spacing: .015em; color: var(--text-subtle);
}
.lp-corpus .es-ratio .ad { color: var(--brand-text); }

.lp-corpus .co-cap {
  margin: 0; padding: 8px 12px 10px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .015em;
  color: var(--text-subtle); font-variant-numeric: tabular-nums;
}

/* Las dos ramas y su fusión. Cada hijo va COLOCADO: con auto-placement la
   segunda rama caía en la pista de 1 px de la junta. */
.lp-corpus .co-via {
  display: grid; grid-template-columns: 104px minmax(0, 1fr) 1px minmax(0, auto);
  gap: 5px 12px; align-items: center;
  padding: 10px 12px 11px; border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 32%, transparent);
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .04em;
  color: var(--text-muted);
}
.lp-corpus .co-via .vrot {
  grid-area: 1 / 1 / 3 / 2; align-self: center;
  font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-subtle);
}
/* Colocación por hermandad, NUNCA por :nth-of-type: los hermanos <span> de la
   fila son cuatro (vrot, rama, rama, out), así que `.ram:nth-of-type(1)` no
   casaba con ninguna rama y la segunda se auto-colocaba encima de la primera. */
.lp-corpus .co-via .ram {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  grid-area: 1 / 2 / 2 / 3;
}
.lp-corpus .co-via .ram + .ram { grid-area: 2 / 2 / 3 / 3; }
.lp-corpus .co-via .ram .l {
  display: block; width: 30px; height: 1px; flex-shrink: 0;
  background: var(--brand); opacity: .8; transform-origin: left center;
}
/* La junta: donde las dos ramas se funden en una sola lista. */
.lp-corpus .co-via .j {
  grid-area: 1 / 3 / 3 / 4; align-self: stretch;
  background: var(--border-strong); transform-origin: 50% 50%;
}
.lp-corpus .co-via .out {
  grid-area: 1 / 4 / 3 / 5; align-self: center;
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}

/* La cobertura, contra el mismo filete permanente del pliego de arriba. */
.lp-corpus .co-lado {
  min-width: 0; padding-left: clamp(14px, 1.6vw, 20px);
  border-left: 1px solid var(--border);
}
.lp-corpus .co-rot {
  margin: 0 0 6px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-corpus .co-tab { margin: 0; }
.lp-corpus .co-tab .f {
  display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 10px;
  align-items: baseline; padding: 7px 0 8px;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.lp-corpus .co-tab .f:last-child { border-bottom: 0; }
.lp-corpus .co-tab dt {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-corpus .co-tab dd {
  margin: 0; font-size: 12.5px; line-height: 1.35; color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
/* Lo que queda FUERA se lee como lo que es: un límite declarado, no un fallo. */
.lp-corpus .co-tab .es-fuera dd { color: var(--text-muted); }

/* ── La coreografía: solo donde cabe ──────────────────────────────────────
   Se indexa a la vista: entran los fragmentos sección por sección, corren las
   dos ramas a la vez, se cierra la junta y sale el resultado. Con .lp-shown y
   `both`, igual que la bandeja del acto del problema. */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  html:not(.lp-lite) .lp-corpus.lp-shown .chs i { animation: co-frag .42s var(--ease-emph) both; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(1) .chs i { animation-delay: .10s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(2) .chs i { animation-delay: .20s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(3) .chs i { animation-delay: .30s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(4) .chs i { animation-delay: .40s; }
  /* Dentro de la sección, uno tras otro: el índice se escribe, no aparece. */
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(1) .chs i:nth-child(2) { animation-delay: .14s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(2) .chs i:nth-child(2) { animation-delay: .24s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(2) .chs i:nth-child(3) { animation-delay: .28s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(2) .chs i:nth-child(4) { animation-delay: .32s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(2) .chs i:nth-child(5) { animation-delay: .36s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(3) .chs i:nth-child(2) { animation-delay: .34s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(3) .chs i:nth-child(3) { animation-delay: .38s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(3) .chs i:nth-child(4) { animation-delay: .42s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(3) .chs i:nth-child(5) { animation-delay: .46s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(3) .chs i:nth-child(6) { animation-delay: .50s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(3) .chs i:nth-child(7) { animation-delay: .54s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-sec:nth-child(4) .chs i:nth-child(2) { animation-delay: .44s; }

  html:not(.lp-lite) .lp-corpus.lp-shown .co-via .ram .l { animation: co-rama .5s var(--ease-emph) .62s both; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-via .j { animation: co-junta .3s var(--ease-emph) 1.06s both; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-via .out { animation: co-sale .38s var(--ease) 1.2s both; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-tab .f { animation: co-sale .42s var(--ease) both; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-tab .f:nth-child(1) { animation-delay: .18s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-tab .f:nth-child(2) { animation-delay: .26s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-tab .f:nth-child(3) { animation-delay: .34s; }
  html:not(.lp-lite) .lp-corpus.lp-shown .co-tab .f:nth-child(4) { animation-delay: .42s; }
}
@keyframes co-frag { from { opacity: 0; transform: scaleX(.12); } to { opacity: 1; transform: none; } }
@keyframes co-rama { from { transform: scaleX(0); } to { transform: none; } }
@keyframes co-junta { from { opacity: 0; transform: scaleY(.2); } to { opacity: 1; transform: none; } }
@keyframes co-sale { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

/* ── Móvil (≤940px): la cobertura se acuesta bajo el panel ──────────────── */
@media (max-width: 940px) {
  .lp-corpus { grid-template-columns: minmax(0, 1fr); gap: 18px; }
  .lp-corpus .co-lado {
    border-left: 0; padding-left: 0;
    border-top: 1px solid var(--border); padding-top: 15px;
  }
  /* El rótulo de la sección se acuesta encima de sus fragmentos: a 104 px de
     carril, en un teléfono no quedaba ancho para ver la tira. */
  .lp-corpus .co-sec { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .lp-corpus .co-sec .ad { grid-column: 1; }
  .lp-corpus .co-via { grid-template-columns: minmax(0, 1fr) 1px minmax(0, auto); }
  .lp-corpus .co-via .vrot { grid-area: auto; grid-column: 1 / -1; }
  .lp-corpus .co-via .ram { grid-area: 2 / 1 / 3 / 2; }
  .lp-corpus .co-via .ram + .ram { grid-area: 3 / 1 / 4 / 2; }
  .lp-corpus .co-via .j { grid-area: 2 / 2 / 4 / 3; }
  .lp-corpus .co-via .out { grid-area: 2 / 3 / 4 / 4; }
}

/* ── Estado impreso, blindado (lite · reduced-motion · papel) ───────────── */
html.lp-lite .lp-corpus .chs i, html.lp-lite .lp-corpus .co-via .ram .l,
html.lp-lite .lp-corpus .co-via .j, html.lp-lite .lp-corpus .co-via .out,
html.lp-lite .lp-corpus .co-tab .f {
  animation: none !important; transform: none !important;
}
@media (prefers-reduced-motion: reduce) {
  .lp-corpus .chs i, .lp-corpus .co-via .ram .l, .lp-corpus .co-via .j,
  .lp-corpus .co-via .out, .lp-corpus .co-tab .f {
    animation: none !important; transform: none !important;
  }
}
@media print {
  .lp-corpus { break-inside: avoid; page-break-inside: avoid; border-top-color: #999; }
  .lp-corpus .chs i, .lp-corpus .co-via .ram .l, .lp-corpus .co-via .j,
  .lp-corpus .co-via .out, .lp-corpus .co-tab .f {
    animation: none !important; opacity: 1 !important; transform: none !important;
  }
  .lp-corpus .co-panel { background: #fff; border-color: #000; }
  .lp-corpus .co-top, .lp-corpus .co-via { background: #fff; border-color: #999; }
  .lp-corpus .co-path, .lp-corpus .co-rot, .lp-corpus .co-cap,
  .lp-corpus .co-sec .et, .lp-corpus .co-tab dt { color: #555; }
  .lp-corpus .co-est, .lp-corpus .co-tab dd, .lp-corpus .co-via .out { color: #000; }
  .lp-corpus .co-est { border-color: #999; }
  .lp-corpus .chs i { background: #bbb; opacity: 1 !important; }
  .lp-corpus .es-ratio .chs i { background: #000; }
  .lp-corpus .es-ratio .ad { color: #000; }
  .lp-corpus .co-sec .ad { color: #333; }
  .lp-corpus .co-lado { border-left-color: #999; }
  .lp-corpus .co-tab .f { border-bottom-color: #ccc; }
}

/* ── La custodia, en una tira ─────────────────────────────────────────────
   Reemplaza las 52 palabras de prosa de la antigua tarjeta 04. Mismo renglón
   hairline de .an-mas: cada hecho cuesta dos palabras y se escanea. */
.cu-tira {
  list-style: none; margin: clamp(14px, 1.8vw, 20px) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 8px clamp(14px, 2.4vw, 28px);
}
.cu-tira li {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .01em;
  color: var(--text-muted);
}
.cu-tira .bt { width: 10px; height: 1px; background: var(--border-strong); flex-shrink: 0; }
@media print {
  .cu-tira li { color: #333; }
  .cu-tira .bt { background: #999; }
}

/* ══════════════════════════════════════════════════════════════════════════
   EL BORRADOR QUE SE ARMA — la hoja de memorial      (#capacidades · pieza B)
   --------------------------------------------------------------------------
   Una hoja con su margen y sus cinco rótulos —I. Referencia · II. Oportunidad ·
   III. Fundamentos · IV. Petición · V. Notificaciones—. LA HOJA EXISTE DESDE EL
   PRIMER PINTADO: el marco, el carril del margen y la esquina de instrumento no
   se animan nunca. Lo que llega con el scroll es el ESCRITO: cada bloque se
   sella con la máscara .mk/.i del titular cuando cruza su umbral
   (landing-memorial.js, ScrollTrigger con toggles, sin pin). Por eso el estado
   vacío no puede dar un salto de alto: la máscara clipea, no colapsa.

   Solo dos bloques llevan texto: la oportunidad (con el vencimiento contado en
   vivo) y el fundamento con su cita. La petición se INSINÚA con renglones
   hairline, los mismos de .lp-ficha-esc en el hero, y las notificaciones
   llevan el marcador [PENDIENTE: …] con el que el generador declara el dato
   que el expediente no trae en vez de inventarlo. No hay texto falso que leer
   — hay un borrador a medio armar.

   ESTADO BASE = HOJA ESCRITA. Todo el vaciado cuelga de .me-cine (clase que
   solo pone el JS) y encima va dentro del media query de película: en móvil,
   con reduced-motion, en lite, sin JS y en papel no hay nada que apagar.
   Solo se animan transform y opacity.
   ══════════════════════════════════════════════════════════════════════════ */
.lp-memorial { margin-top: clamp(22px, 3vw, 30px); }
.lp-memorial .me-rot {
  margin: 0 0 10px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-memorial .me-hoja {
  position: relative;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 14px 16px 13px;
}
/* La misma esquina de instrumento de la ficha del radar: una sola marca. */
.lp-memorial .me-hoja::before {
  content: ""; position: absolute; top: -1px; left: -1px; width: 13px; height: 13px;
  border-top: 1px solid var(--accent); border-left: 1px solid var(--accent);
  opacity: .55;
}

/* Máscara de revelado, la misma del titular y de la ficha del hero. */
.lp-memorial .mk { display: block; overflow-y: clip; overflow-x: visible; }
.lp-memorial .mk .i { display: block; }

/* El bloque: rótulo al margen, cuerpo contra el carril. Los tramos de carril de
   los cuerpos se tocan (no hay separación entre bloques) y forman UNA sola
   línea continua: el margen de la hoja. */
.lp-memorial .me-sec {
  display: grid; grid-template-columns: 100px minmax(0, 1fr); gap: 12px;
  align-items: start;
}
/* El carril mide 100px porque el rótulo más largo —NOTIFICACIONES, 14 signos
   en mono a 9,5px con .1em— pide 93px: con menos, se montaba sobre la línea
   del margen. Si algún rótulo crece, crece el carril, no el atropello. */
.lp-memorial .me-sec .rt {
  padding-top: 11px;
  font-family: var(--font-mono); font-size: 9.5px; line-height: 1.5;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-subtle);
}
/* El ordinal SIEMPRE en su propio renglón: si se deja fluir, «IV. Petición»
   cabe en una línea y «I. Referencia» no, y la columna del margen queda
   desalineada bloque a bloque. Numeración de documento, no texto corrido. */
.lp-memorial .me-sec .rt .num { display: block; color: var(--brand-text); }
.lp-memorial .me-sec .cp {
  min-width: 0; padding: 10px 0 11px 13px;
  border-left: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
}

/* I · Referencia — identificación del expediente hilo de toda la página. */
.lp-memorial .rad {
  display: block; font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .01em; color: var(--brand-text); font-variant-numeric: tabular-nums;
}
.lp-memorial .desp {
  display: block; margin-top: 3px;
  font-size: 12.5px; line-height: 1.32; font-weight: 560; color: var(--text-strong);
}

/* II y III · las dos líneas de texto real. */
.lp-memorial .tx { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--text); }
.lp-memorial .me-plazo {
  margin: 8px 0 0;
  font-family: var(--font-mono); font-size: 10px; line-height: 1.5;
  letter-spacing: .015em; color: var(--text-subtle);
}
.lp-memorial .me-plazo .vence { display: block; color: var(--warn-fg); font-weight: 500; }

/* V · el dato que el expediente no trae. El generador NO lo inventa: deja el
   marcador entre corchetes (app/services/ai/borradores.py:215-221). Es la
   misma disciplina del antídoto de la pieza A, esta vez redactando, y por eso
   se lee como hueco declarado —filete discontinuo— y no como error. */
.lp-memorial .me-falta {
  margin: 0; padding: 6px 8px;
  border: 1px dashed color-mix(in srgb, var(--warn-fg) 45%, transparent);
  border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: 10.5px; line-height: 1.45;
  color: var(--warn-fg);
}

/* La cita, anclada al margen por la misma llave de 1px de la ficha del hero. */
.lp-memorial .me-cita { position: relative; margin: 9px 0 0; padding-left: 11px; }
.lp-memorial .me-cita .llave {
  position: absolute; left: 0; top: 3px; bottom: 3px; width: 5px;
  border: 1px solid color-mix(in srgb, var(--border-strong) 90%, transparent);
  border-right: 0;
}
.lp-memorial .chip {
  display: inline-block; font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .02em; padding: 3px 8px; border-radius: var(--r-full);
  background: var(--brand-tint); color: var(--brand-text);
  border: 1px solid color-mix(in srgb, var(--brand) 32%, transparent);
  white-space: nowrap;
}

/* IV y V · lo que NO se escribe: renglones hairline, como el escrito de la
   ficha del radar. Cada uno en su caja de 8px para que la máscara recorra. */
.lp-memorial .me-rgs { display: grid; gap: 1px; }
.lp-memorial .me-rgs .mk { height: 8px; }
.lp-memorial .me-rgs .mk .i { height: 8px; padding-top: 7px; }
.lp-memorial .me-rgs .rg { display: block; height: 1px; background: var(--text-muted); }
.lp-memorial .me-rgs .mk:nth-child(1) .rg { width: 100%; opacity: .5; }
.lp-memorial .me-rgs .mk:nth-child(2) .rg { width: 92%;  opacity: .4; }
.lp-memorial .me-rgs .mk:nth-child(3) .rg { width: 61%;  opacity: .3; }

/* El sello, alineado con la columna del cuerpo (100px de carril + 12 de gap). */
.lp-memorial .me-sec.me-sello {
  display: block; margin: 0 0 0 112px; padding: 10px 0 0 13px;
  border-top: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  font-family: var(--font-mono); font-size: 10px; line-height: 1.5;
  letter-spacing: .015em; color: var(--text-subtle);
}
.lp-memorial .me-sello .est { color: var(--text-muted); font-weight: 500; }
.lp-memorial .me-sello .sep { opacity: .5; margin: 0 2px; }

/* ── El sellado: solo donde cabe ───────────────────────────────────────────
   El gate va por media query ADEMÁS de por clase: si la ventana baja de 941px
   —o el visitante pide menos movimiento— manda la hoja escrita aunque el JS ya
   hubiera armado la escena. .me-cine vacía; .me-anim (un frame después) es la
   única que declara transiciones, para que el vaciado inicial no se vea. */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  html:not(.lp-lite) .lp-memorial.me-cine .mk .i { transform: translateY(118%); opacity: 0; }
  html:not(.lp-lite) .lp-memorial.me-cine .me-cita .llave { transform: scaleY(0); transform-origin: 50% 0; }

  html:not(.lp-lite) .lp-memorial.me-anim .mk .i {
    transition: transform .58s var(--ease-emph), opacity .34s var(--ease);
  }
  html:not(.lp-lite) .lp-memorial.me-anim .me-cita .llave { transition: transform .42s var(--ease-emph) .1s; }

  /* Sellado del bloque que cruzó su umbral: primero el rótulo del margen,
     después el cuerpo, y los renglones sin redactar uno tras otro. */
  html:not(.lp-lite) .lp-memorial.me-cine .me-sec.me-on .mk .i { transform: none; opacity: 1; }
  html:not(.lp-lite) .lp-memorial.me-cine .me-sec.me-on .me-cita .llave { transform: scaleY(1); }
  html:not(.lp-lite) .lp-memorial.me-anim .me-sec.me-on .cp .mk .i { transition-delay: .09s; }
  /* Dentro del cuerpo, el orden de lectura: primero la línea que manda, después
     lo que la sostiene (el despacho, el vencimiento, la cita). Misma
     especificidad que la regla de arriba — mandan por orden de aparición. */
  html:not(.lp-lite) .lp-memorial.me-anim .me-sec.me-on .cp > .mk + .mk .i { transition-delay: .16s; }
  html:not(.lp-lite) .lp-memorial.me-anim .me-sec.me-on .me-plazo .mk .i { transition-delay: .18s; }
  html:not(.lp-lite) .lp-memorial.me-anim .me-sec.me-on .me-cita .mk .i { transition-delay: .18s; }
  html:not(.lp-lite) .lp-memorial.me-anim .me-sec.me-on .me-rgs .mk:nth-child(1) .i { transition-delay: .12s; }
  html:not(.lp-lite) .lp-memorial.me-anim .me-sec.me-on .me-rgs .mk:nth-child(2) .i { transition-delay: .18s; }
  html:not(.lp-lite) .lp-memorial.me-anim .me-sec.me-on .me-rgs .mk:nth-child(3) .i { transition-delay: .24s; }
}

/* ── Móvil (≤940px): el rótulo se acuesta encima de su bloque ───────────── */
@media (max-width: 940px) {
  .lp-memorial .me-sec { grid-template-columns: minmax(0, 1fr); gap: 3px; }
  .lp-memorial .me-sec .rt { padding-top: 12px; }
  .lp-memorial .me-sec .cp { padding-top: 0; }
  .lp-memorial .me-sec.me-sello { margin-left: 0; padding-left: 0; }
}

/* ── Estado escrito, blindado (lite · reduced-motion) ─────────────────────
   Redundante con el gate de arriba a propósito: pase lo que pase con las
   clases, aquí la hoja se lee quieta y completa. */
html.lp-lite .lp-memorial .mk .i { transform: none !important; opacity: 1 !important; }
html.lp-lite .lp-memorial .me-cita .llave { transform: none !important; }
@media (prefers-reduced-motion: reduce) {
  .lp-memorial .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-memorial .me-cita .llave { transform: none !important; }
}

/* ── Papel: se imprime literalmente como el borrador que es ───────────────
   Tinta negra sobre blanco (mismo criterio que la constancia de radicación:
   los abogados imprimen documentos, no pantallas), la hoja entera en una
   página, y los renglones sin redactar estirados a RENGLONES DE ESCRIBIR: el
   escrito sale con su referencia, su término, su fundamento citado — y el
   cuerpo en blanco, listo para la mano del abogado. Los renglones pasan de
   background a border-bottom porque los navegadores no imprimen fondos. */
@media print {
  /* Los reveals los levanta la regla global de landing.css (antes se rescataba
     #capacidades por su cuenta y el resto de la página salía en blanco). */
  .lp-memorial { break-inside: avoid; page-break-inside: avoid; }
  .lp-memorial .mk .i { transform: none !important; opacity: 1 !important; }
  .lp-memorial .me-cita .llave { transform: none !important; border-color: #999; }
  .lp-memorial .me-hoja {
    background: #fff; border: 1px solid #000; box-shadow: none;
    padding: 18px 20px 16px;
  }
  .lp-memorial .me-hoja::before { display: none; }
  .lp-memorial .me-rot, .lp-memorial .me-sec .rt { color: #555; }
  .lp-memorial .me-sec .rt .num { color: #000; }
  .lp-memorial .me-sec .cp { border-left-color: #999; }
  .lp-memorial .rad, .lp-memorial .desp, .lp-memorial .tx { color: #000; }
  .lp-memorial .chip { background: none; border: 1px solid #000; color: #000; }
  .lp-memorial .me-plazo { color: #333; }
  .lp-memorial .me-plazo .vence { color: #000; }
  .lp-memorial .me-rgs { gap: 0; }
  .lp-memorial .me-rgs .mk { height: 17px; }
  .lp-memorial .me-rgs .mk .i { height: 17px; padding-top: 16px; }
  .lp-memorial .me-rgs .rg {
    width: 100% !important; opacity: 1 !important;
    height: 0; background: none; border-bottom: 1px solid #999;
  }
  .lp-memorial .me-sec.me-sello { color: #333; border-top-color: #999; }
  .lp-memorial .me-sello .est { color: #000; }
  .lp-memorial .me-falta { color: #333; border-color: #999; }
}

/* ══════════════════════════════════════════════════════════════════════════
   EL CABEZAL — el banco del clasificador           (#como · cierre de sección)
   --------------------------------------------------------------------------
   Tres renglones con el texto LITERAL de una actuación, en mono de 12px, y un
   cabezal de 1px cian que los recorre con el scroll (landing-cabezal.js: un
   solo ScrollTrigger con scrub, sin pin). Tres cosas cuelgan de dónde va el
   cabezal, y nada más:

     · el renglón que ya pasó por debajo se lee a tinta plena; el que no, en
       gris. Se ve QUÉ lleva leído — la causa física es el dedo, no un reloj;
     · al cruzar «admite la demanda» —la única frase del texto que casa una
       regla del catálogo— crece el corchete de 1px que la subraya (scaleX
       desde la izquierda: el corchete se dibuja hacia donde avanza la lectura);
     · y con él se imprime la lectura del motor al margen derecho.

   LA CINTA NO SE MUEVE. El marco, los ordinales del carril y las hairlines
   entre renglones existen desde el primer pintado y no se animan nunca: lo
   único que viaja es el cabezal. Por eso el estado vacío no puede dar salto de
   alto — no hay nada colapsado, solo tinta a media opacidad.

   ESTADO BASE = TODO TRAZADO: renglones a tinta plena, corchete dibujado y
   lectura del margen visible. El vaciado cuelga de .cz-cine (clase que solo
   pone el JS) y encima va dentro del media query de película: en móvil, con
   reduced-motion, en lite, sin JS y en papel no hay nada que apagar ni que
   rescatar. Solo se animan transform y opacity.
   ══════════════════════════════════════════════════════════════════════════ */
.lp-cabezal {
  margin-top: clamp(30px, 4.2vw, 52px);
  padding-top: clamp(22px, 3vw, 32px);
  border-top: 1px solid var(--border);
}
.lp-cabezal .cz-cab { max-width: 74ch; margin-bottom: clamp(16px, 2vw, 24px); }
.lp-cabezal .cz-rot {
  margin: 0 0 7px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-cabezal .cz-lead { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--text); }

/* El banco: la cinta a la izquierda, la lectura al margen derecho. */
.lp-cabezal .cz-banco {
  display: grid; grid-template-columns: minmax(0, 1fr) 268px;
  gap: clamp(18px, 2.4vw, 32px); align-items: start;
}
.lp-cabezal .cz-izq { min-width: 0; }

/* La cinta. position:relative la vuelve bloque contenedor Y offsetParent del
   cabezal, de los renglones y de la frase: el JS mide todos los cortes con
   offsetTop contra esta misma caja, así que la geometría no puede desfasarse.
   overflow:clip (NUNCA hidden: rompe sticky en los ancestros) recorta las
   orejas del cabezal cuando llega a los bordes. */
.lp-cabezal .cz-texto {
  position: relative; overflow: clip;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--surface-2) 72%, transparent);
}
/* z-index 2: los renglones van POR ENCIMA del cabezal. Un filete cian que
   pasa por delante de una línea de texto se lee como tachado; pasando por
   detrás, los trazos de las letras lo interrumpen y se lee como luz. */
.lp-cabezal .cz-rg {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 20px minmax(0, 1fr); gap: 10px;
  margin: 0; padding: 8px 0;
  font-family: var(--font-mono); font-size: 12px; line-height: 1.5;
  letter-spacing: .005em; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.lp-cabezal .cz-rg + .cz-rg {
  border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.lp-cabezal .cz-rg .n { font-size: 9.5px; line-height: 1.9; color: var(--text-subtle); letter-spacing: .06em; }
.lp-cabezal .cz-rg .tx { min-width: 0; }
.lp-cabezal .cz-rg .sep { margin: 0 7px; color: var(--text-subtle); }
.lp-cabezal .cz-rg .fe { color: var(--text-muted); }
.lp-cabezal .cz-rg .rad { color: var(--brand-text); }

/* El cabezal: 1px cian con dos orejas de 7px, como la cabeza de un banco de
   lectura. Nace oculto y solo lo enciende .cz-cine — sin JS no hay cabezal
   parado a medio camino de un texto que ya está entero. */
.lp-cabezal .cz-head {
  display: none; position: absolute; left: 0; right: 0; top: 0; height: 1px;
  z-index: 1; pointer-events: none;
  /* El filete central va a media tinta y las orejas a tinta plena: la opacidad
     vive en el COLOR, no en el elemento —con opacity en el host las orejas no
     podrían ser más opacas que la línea que sostienen—. A plena tinta, el
     filete cruzando un renglón se leía como tachado. */
  background: color-mix(in srgb, var(--accent) 55%, transparent);
  box-shadow: 0 0 16px 0 color-mix(in srgb, var(--accent) 34%, transparent);
}
/* El haz: sin él, un filete cian cruzando una línea de texto se lee como
   TACHADO. Con la banda difusa alrededor, el mismo filete se lee como luz que
   pasa por encima. No se anima: viaja con el transform del cabezal. */
.lp-cabezal .cz-head::before {
  content: ""; position: absolute; left: 0; right: 0; top: -12px; height: 25px;
  background: linear-gradient(to bottom,
    transparent, color-mix(in srgb, var(--accent) 34%, transparent), transparent);
}
/* Las dos orejas del cabezal, en un solo pseudo: caja transparente de 7px con
   filete a izquierda y derecha. */
.lp-cabezal .cz-head::after {
  content: ""; position: absolute; left: 0; right: 0; top: -4px; height: 9px;
  border-left: 1px solid var(--accent); border-right: 1px solid var(--accent);
}

/* La frase que dispara la regla. nowrap: el corchete se posiciona contra el
   primer fragmento de la línea, así que la frase no puede partirse en dos
   —el texto de alrededor sí puede, y en móvil lo hace—. */
.lp-cabezal .cz-fr {
  position: relative; white-space: nowrap;
  color: var(--text-strong); font-weight: 500;
}
/* El corchete: filete de 1px con dos retornos hacia arriba. Es borde, no
   fondo, para que también salga impreso. */
.lp-cabezal .cz-fr .br {
  position: absolute; left: -2px; right: -2px; bottom: -5px; height: 4px;
  border: 1px solid var(--accent); border-top: 0;
  transform: scaleX(1); transform-origin: 0 50%;
}

/* La lectura del motor: ya no es una tabla suelta sobre el fondo (obs. 10) —es
   una VENTANA de la plataforma, con la misma materia del Contador y de la
   ficha del hero. Aquí NO hay cian —el cian es del cabezal y del punto de «en
   vivo»—: la lectura es tinta, y lo único que viene del instrumento es la
   corriente de 1 px del costado. */
.lp-cabezal .cz-lec { padding-top: 2px; min-width: 0; }
.lp-cabezal .cz-lt {
  margin: 0 0 8px; display: flex; align-items: center; gap: 7px;
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--text-muted);
}
.lp-cabezal .cz-lt .d {
  width: 4px; height: 4px; border-radius: var(--r-full); background: var(--accent);
}

/* EL MARCO EXISTE DESDE EL PRIMER PINTADO y no se anima nunca: lo que llega
   con la lectura es el CONTENIDO. Por eso la ventana no puede dar un salto de
   alto — no hay nada colapsado, solo renglones sin imprimir. */
.lp-cabezal .cz-win {
  position: relative; overflow: clip;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .26);
}
/* La corriente: el filete que baja por el costado cuando el cabezal termina de
   leer la frase. Es la causa a la vista — lo de la izquierda produce esto. */
.lp-cabezal .cz-corr {
  position: absolute; left: 0; top: 0; bottom: 0; width: 1px; z-index: 1;
  background: var(--brand); transform-origin: 50% 0;
}
.lp-cabezal .cz-wtop {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 50%, transparent);
}
.lp-cabezal .cz-wpath {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-cabezal .cz-wbody { padding: 11px 12px 12px; }
.lp-cabezal .cz-wrad {
  margin: 0; font-family: var(--font-mono); font-size: 10.5px;
  letter-spacing: .01em; color: var(--brand-text); font-variant-numeric: tabular-nums;
}
.lp-cabezal .cz-wtit {
  margin: 3px 0 0; font-size: 13px; line-height: 1.3;
  font-weight: 560; color: var(--text-strong);
}
.lp-cabezal .cz-tab { margin: 10px 0 0; border-top: 1px solid var(--border); }
.lp-cabezal .cz-tab .f {
  display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: 10px;
  align-items: baseline; padding: 7px 0 8px;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.lp-cabezal .cz-tab .f:last-child { border-bottom: 0; padding-bottom: 1px; }
.lp-cabezal .cz-tab dt {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-subtle);
}
.lp-cabezal .cz-tab dd {
  margin: 0; font-size: 12.5px; line-height: 1.35; color: var(--text-strong);
}
.lp-cabezal .cz-tab dd .slug {
  display: block; font-family: var(--font-mono); font-size: 11.5px;
  letter-spacing: .01em; color: var(--brand-text);
}
.lp-cabezal .cz-tab dd .sub {
  display: block; margin-top: 2px; font-size: 11.5px; line-height: 1.4;
  color: var(--text-muted);
}
/* El plazo es el RESULTADO: cifra de instrumento, no una línea más de tabla. */
.lp-cabezal .cz-tab .es-plazo dd { display: flex; align-items: baseline; gap: 7px; }
.lp-cabezal .cz-tab .es-plazo .q {
  font-family: var(--font-mono); font-size: 20px; font-weight: 600; line-height: 1;
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}
.lp-cabezal .cz-tab .es-plazo .um { font-size: 11.5px; color: var(--text-muted); }

/* La fila de acciones: es la doctrina del producto en tres palabras. NO son
   <button> ni llevan :hover — en esta página no hay nada que confirmar, y un
   control que no responde es una mentira de interfaz. */
.lp-cabezal .cz-wact {
  display: flex; flex-wrap: wrap; gap: 7px; padding: 10px 12px 11px;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 32%, transparent);
}
.lp-cabezal .cz-btn {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .06em;
  padding: 5px 10px; border-radius: var(--r-sm);
  background: var(--brand); color: var(--on-brand);
  border: 1px solid color-mix(in srgb, var(--brand) 55%, transparent);
}
.lp-cabezal .cz-btn.ghost {
  background: transparent; color: var(--text-muted); border-color: var(--border-strong);
}

/* El pie: la regla de la pieza, permanente y en filete. Es lo que lee quien no
   ve el gesto — y lo que impide que la pieza prometa magia. */
.lp-cabezal .cz-pie {
  max-width: 96ch;
  margin: clamp(13px, 1.8vw, 18px) 0 0; padding-top: 11px;
  border-top: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 11px; line-height: 1.6;
  letter-spacing: .01em; color: var(--text-subtle);
}
.lp-cabezal .cz-pie .k {
  margin-right: 9px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-muted);
}

/* ── La lectura: solo donde cabe ───────────────────────────────────────────
   Gate por media query ADEMÁS de por clase: si la ventana baja de 941px —o el
   visitante pide menos movimiento— manda el estado trazado aunque el JS ya
   hubiera armado la escena. .cz-cine vacía; .cz-anim (un frame después) es la
   única que declara transiciones, para que el vaciado inicial no se vea
   animar hacia atrás cuando se llega con la sección ya pasada. */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  /* El cabezal se ENCIENDE aquí dentro, no fuera: estaba fuera del gate y al
     estrechar la ventana con la escena ya armada quedaba una barra cian de 1px
     y 850 de ancho flotando sobre la maqueta apilada, con los renglones ya a
     tinta plena. Ahora encoger la ventana devuelve el banco entero, que es la
     regla de oro que el módulo promete. */
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-head { display: block; }
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-rg { opacity: .5; }
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-fr .br { transform: scaleX(0); }
  /* La ventana nace ABIERTA Y VACÍA: marco, barra y fila de acciones existen
     desde el primer pintado; lo que falta es lo que el motor todavía no leyó. */
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-corr { transform: scaleY(0); }
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-wtop .lp-pill,
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-wrad,
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-wtit,
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-tab .f,
  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-btn { opacity: 0; transform: translateY(5px); }

  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-rg { transition: opacity .38s var(--ease); }
  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-fr .br { transition: transform .5s var(--ease-emph); }
  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-corr { transition: transform .55s var(--ease-emph); }
  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-wtop .lp-pill,
  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-wrad,
  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-wtit,
  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-tab .f,
  html:not(.lp-lite) .lp-cabezal.cz-anim .cz-btn {
    transition: opacity .42s var(--ease), transform .42s var(--ease-emph);
  }

  html:not(.lp-lite) .lp-cabezal.cz-cine .cz-rg.is-read { opacity: 1; }
  html:not(.lp-lite) .lp-cabezal.cz-cine.is-leido .cz-fr .br { transform: scaleX(1); }
  html:not(.lp-lite) .lp-cabezal.cz-cine.is-leido .cz-corr { transform: scaleY(1); }
  html:not(.lp-lite) .lp-cabezal.cz-cine.is-leido .cz-wtop .lp-pill,
  html:not(.lp-lite) .lp-cabezal.cz-cine.is-leido .cz-wrad,
  html:not(.lp-lite) .lp-cabezal.cz-cine.is-leido .cz-wtit,
  html:not(.lp-lite) .lp-cabezal.cz-cine.is-leido .cz-tab .f,
  html:not(.lp-lite) .lp-cabezal.cz-cine.is-leido .cz-btn { opacity: 1; transform: none; }

  /* La ventana se llena en el orden en que el motor produce la lectura: baja la
     corriente, entra el expediente, después la regla, el plazo y su respaldo, y
     al final lo único que queda pendiente — la decisión. */
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-wrad { transition-delay: .10s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-wtit { transition-delay: .15s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-tab .f:nth-child(1) { transition-delay: .22s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-tab .f:nth-child(2) { transition-delay: .29s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-tab .f:nth-child(3) { transition-delay: .36s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-tab .f:nth-child(4) { transition-delay: .43s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-wtop .lp-pill { transition-delay: .50s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-btn { transition-delay: .56s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-btn:nth-child(2) { transition-delay: .60s; }
  html:not(.lp-lite) .lp-cabezal.cz-anim.is-leido .cz-btn:nth-child(3) { transition-delay: .64s; }
}

/* ── Móvil (≤940px): la lectura se acuesta debajo de la cinta ───────────── */
@media (max-width: 940px) {
  .lp-cabezal .cz-banco { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .lp-cabezal .cz-rg { font-size: 11px; grid-template-columns: 18px minmax(0, 1fr); gap: 8px; }
  .lp-cabezal .cz-lec { padding-top: 0; }
  .lp-cabezal .cz-pie { max-width: none; }
}

/* ── Estado trazado, blindado (lite · reduced-motion) ─────────────────────
   Redundante con el gate de arriba a propósito: pase lo que pase con las
   clases, aquí el banco se lee quieto y completo. */
html.lp-lite .lp-cabezal .cz-head { display: none !important; }
html.lp-lite .lp-cabezal .cz-rg { opacity: 1 !important; }
html.lp-lite .lp-cabezal .cz-fr .br { transform: none !important; }
html.lp-lite .lp-cabezal .cz-corr { transform: none !important; }
html.lp-lite .lp-cabezal .cz-tab .f, html.lp-lite .lp-cabezal .cz-wrad,
html.lp-lite .lp-cabezal .cz-wtit, html.lp-lite .lp-cabezal .cz-btn,
html.lp-lite .lp-cabezal .cz-wtop .lp-pill { opacity: 1 !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
  .lp-cabezal .cz-head { display: none !important; }
  .lp-cabezal .cz-rg { opacity: 1 !important; }
  .lp-cabezal .cz-fr .br { transform: none !important; }
  .lp-cabezal .cz-corr { transform: none !important; }
  .lp-cabezal .cz-tab .f, .lp-cabezal .cz-wrad, .lp-cabezal .cz-wtit,
  .lp-cabezal .cz-btn, .lp-cabezal .cz-wtop .lp-pill {
    opacity: 1 !important; transform: none !important;
  }
}

/* ── Papel: los tres renglones con el subrayado ya trazado ────────────────
   Tinta negra sobre blanco (mismo criterio que la constancia de radicación) y
   la lectura del margen entera. El corchete es borde, así que se imprime; el
   cabezal no —una cabeza de lectura congelada a media página no significa nada
   en papel—. La pieza no se parte entre dos hojas. */
@media print {
  .lp-cabezal { break-inside: avoid; page-break-inside: avoid; border-top-color: #999; }
  .lp-cabezal .cz-head { display: none !important; }
  .lp-cabezal .cz-rg { opacity: 1 !important; color: #000; border-top-color: #ccc; }
  .lp-cabezal .cz-rg .n, .lp-cabezal .cz-rg .sep { color: #777; }
  .lp-cabezal .cz-rg .fe, .lp-cabezal .cz-rg .rad { color: #000; }
  .lp-cabezal .cz-texto { background: #fff; border-color: #000; }
  .lp-cabezal .cz-fr .br { transform: none !important; border-color: #000; }
  .lp-cabezal .cz-rot, .lp-cabezal .cz-lt { color: #555; }
  .lp-cabezal .cz-lt .d { display: none; }
  .lp-cabezal .cz-lead { color: #000; }
  /* La ventana se imprime como la ficha que es: marco negro, sin sombra y sin
     fondo (los navegadores no imprimen fondos), con su contenido completo. */
  .lp-cabezal .cz-win { border-color: #000; box-shadow: none; background: #fff; }
  .lp-cabezal .cz-corr { transform: none !important; background: #000; }
  .lp-cabezal .cz-wtop, .lp-cabezal .cz-wact { background: #fff; border-color: #999; }
  .lp-cabezal .cz-wpath { color: #555; }
  .lp-cabezal .cz-wrad, .lp-cabezal .cz-wtit { color: #000; }
  .lp-cabezal .cz-btn { background: #fff; color: #000; border-color: #000; }
  .lp-cabezal .cz-btn.ghost { color: #333; border-color: #999; }
  .lp-cabezal .cz-wtop .lp-pill, .lp-cabezal .cz-wrad, .lp-cabezal .cz-wtit,
  .lp-cabezal .cz-btn { opacity: 1 !important; transform: none !important; }
  .lp-cabezal .cz-tab { border-top-color: #999; }
  .lp-cabezal .cz-tab .f {
    opacity: 1 !important; transform: none !important; border-bottom-color: #ccc;
  }
  .lp-cabezal .cz-tab dt { color: #555; }
  .lp-cabezal .cz-tab dd, .lp-cabezal .cz-tab dd .slug { color: #000; }
  .lp-cabezal .cz-tab dd .sub { color: #333; }
  .lp-cabezal .cz-tab .es-plazo .q { color: #000; }
  .lp-cabezal .cz-tab .es-plazo .um { color: #333; }
  .lp-cabezal .cz-pie { color: #333; border-top-color: #999; }
  .lp-cabezal .cz-pie .k { color: #000; }
}

/* ══════════════════════════════════════════════════════════════════════════
   LA LECTURA DEL FALLO — el piso de la cara D        (acto 3 · meseta de D)
   --------------------------------------------------------------------------
   La leyenda de la cara D promete módulos «orbitando el mismo expediente» y
   hasta aquí el centro estaba vacío: no había expediente a la vista. Este es
   el expediente — y no como membrete, sino LEÍDO. Tres ordinales del RESUELVE
   del fallo de tutela que la bandeja de la cara A detecta («Fallo de tutela
   notificado», rad. …00154-00) y que el memorial de la cara C impugna: un
   solo caso recorre el acto entero.

   Dentro de la meseta de la cara —donde el dispositivo ya está plano y
   frontal— el scrub hace tres cosas por ordinal, y nada más:

     · subraya con scaleX el VERBO OPERATIVO (TUTELAR · ORDENAR · NOTIFICAR).
       Es el análisis ocurriendo: el trazo va de izquierda a derecha, hacia
       donde avanza la lectura;
     · del final del renglón sale una LLAVE de 1px que cruza al margen;
     · y con ella se imprime lo que el motor extrajo: el sentido del fallo,
       contra quién obra y el término que nace.

   EL PISO NO TAPA EL SISTEMA. Se apoya en el filo inferior de la ventana, por
   debajo del satélite más bajo, y hereda el fondo de la cara: no es una
   tarjeta flotante, es el borde de abajo del aparato. Un velo de 26px funde
   la constelación con él —profundidad de campo, no recorte—. Ni un satélite
   se movió de su sitio: esta pieza es un añadido puro sobre la maquinaria
   pineada.

   AQUÍ NO HAY TRANSICIONES CSS. La pieza vive dentro de .lp-device, que rota
   en preserve-3d en cada frame: ahí una transición en curso se CONGELA en
   Chrome (es la razón por la que las caras conmutan con toggle duro). Todo lo
   que se mueve lo escribe el scrub en línea, frame a frame, y solo transform
   y opacity.

   ESTADO BASE = TODO TRAZADO: subrayados hechos, llaves dibujadas y lecturas
   impresas. El vaciado cuelga de .fa-cine (clase que solo pone el JS) y
   encima va dentro del media query de película: en móvil, en lite, con
   reduced-motion, sin JS y en papel no hay nada que apagar ni que rescatar.
   ══════════════════════════════════════════════════════════════════════════ */
.lp-fallo {
  /* El mismo cuerpo de la cara D: el piso se anuncia con una hairline, no con
     una caja. Va en variable porque el velo tiene que degradar a este color
     exacto. */
  --fa-piso: color-mix(in srgb, var(--canvas) 96%, var(--brand));
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: 9px 18px 8px;
  border-top: 1px solid color-mix(in srgb, var(--brand) 26%, var(--border));
  border-radius: 0 0 var(--r-xl) var(--r-xl);
  background: var(--fa-piso);
}
/* El velo: los satélites no se cortan contra el filo del piso, se disuelven
   en él. No se anima nunca. */
.lp-fallo::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 26px;
  background: linear-gradient(to top, var(--fa-piso), transparent);
  pointer-events: none;
}

/* La cabecera: qué documento es, de qué expediente, y el rótulo de la columna
   del margen (lo que el motor leyó, que no es lo mismo que lo que dice el
   texto). Una sola línea: el piso no tiene alto que gastar. */
.lp-fallo .fa-cab {
  display: flex; align-items: baseline; gap: 10px;
  font-family: var(--font-mono); font-size: 9.5px; line-height: 1.3;
  letter-spacing: .04em; color: var(--text-subtle);
}
.lp-fallo .fa-k {
  flex-shrink: 0; text-transform: uppercase; letter-spacing: .18em;
  color: var(--brand-text);
}
.lp-fallo .fa-exp {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lp-fallo .fa-exp b { font-weight: 500; color: var(--text-muted); }
.lp-fallo .fa-lee {
  margin-left: auto; flex-shrink: 0;
  text-transform: uppercase; letter-spacing: .12em;
}

/* Una fila = ordinal · llave · lectura. El ancho del margen es fijo (como el
   banco del cabezal): la lectura tiene que caer siempre en la misma columna,
   pase lo que pase con el largo del ordinal. */
.lp-fallo .fa-lista {
  list-style: none; margin: 5px 0 0; padding: 0; display: grid; gap: 3px;
}
.lp-fallo .fa-o {
  display: grid; grid-template-columns: minmax(0, 1fr) 30px 232px;
  align-items: center; min-width: 0;
}
.lp-fallo .fa-t {
  margin: 0; min-width: 0; font-size: 11px; line-height: 1.45; color: var(--text);
}
.lp-fallo .fa-t .or {
  font-weight: 700; letter-spacing: .06em; color: var(--text-muted);
}
/* El verbo operativo: lo único que el subrayado toca. */
.lp-fallo .fa-t .vb {
  position: relative; font-weight: 640; letter-spacing: .02em; color: var(--text-strong);
}
/* El subrayado es BORDE, no fondo: así también sale impreso. scaleX desde la
   izquierda — el trazo va hacia donde avanza la lectura. */
.lp-fallo .fa-t .ul {
  position: absolute; left: 0; right: 0; bottom: -3px; height: 0;
  border-bottom: 1px solid var(--brand);
  transform-origin: 0 50%;
}
/* La llave: un solo elemento con dos filetes —el que cruza y el retorno que
   baja al margen—. También borde, por lo mismo. */
.lp-fallo .fa-llave {
  height: 6px; margin: 1px 7px 0; align-self: center;
  border-top: 1px solid color-mix(in srgb, var(--brand) 55%, transparent);
  border-right: 1px solid color-mix(in srgb, var(--brand) 55%, transparent);
  transform-origin: 0 50%;
}
/* La lectura del motor. Aquí NO hay cian: el cian de la página es del punto de
   «en vivo». Lo que el motor entiende es tinta. */
.lp-fallo .fa-r {
  margin: 0; display: flex; align-items: baseline; gap: 7px; min-width: 0;
}
.lp-fallo .fa-r .l {
  flex-shrink: 0; font-family: var(--font-mono); font-size: 9px;
  text-transform: uppercase; letter-spacing: .12em; color: var(--text-subtle);
}
.lp-fallo .fa-r .v {
  min-width: 0; font-size: 11px; line-height: 1.4; color: var(--text-strong);
}
/* La base normativa cuelga del valor, en renglón propio: el motor entrega el
   plazo Y de dónde sale. En papel es lo único que hace verificable la lectura. */
.lp-fallo .fa-r .nb { display: block; color: var(--text-subtle); }

/* ── La lectura se lee sola: solo donde hay sitio y hay película ──────────
   Gate por media query ADEMÁS de por clase: si la ventana baja de 941px —o el
   visitante pide menos movimiento— manda el estado trazado aunque el JS ya
   hubiera armado la escena. Sin transiciones a propósito (ver cabecera). */
@media (min-width: 941px) and (prefers-reduced-motion: no-preference) {
  html:not(.lp-lite) .lp-fallo.fa-cine .fa-t .ul,
  html:not(.lp-lite) .lp-fallo.fa-cine .fa-llave { transform: scaleX(0); }
  html:not(.lp-lite) .lp-fallo.fa-cine .fa-r { opacity: 0; }
}

/* ── Desktop angosto (821-940px): la ventana no tiene piso ────────────────
   Ahí la película SIGUE corriendo, pero el dispositivo baja a 560px: la cara
   queda en ~526x329 y un documento con margen no cabe sin comerse media
   constelación (medido: el piso ocupaba 129 de 329 y tapaba «Reportes»
   entero). Antes que servir la lectura apretada o pisar el sistema, en esa
   franja la ventana se queda como estaba y la lectura no se ofrece: por
   debajo de 821px el acto se aplana y vuelve entera, en el flujo. El
   `:not(.lp-lite)` deja fuera al deck editorial —y el <noscript> y el papel
   la devuelven con display explícito—. */
@media (max-width: 940px) {
  html:not(.lp-lite) .lp-fallo { display: none; }
}

/* ── El deck editorial (lite): la lectura se acuesta bajo la constelación ──
   Al aplanarse el acto, la ventana deja de tener «piso»: el bloque entra en
   el flujo, la constelación se queda con su caja de 320px —la misma que
   tenía— y cada lectura se recuesta debajo de su ordinal, colgada de un
   filete. Nada se mueve: todo nace trazado. */
html.lp-lite .lp-face-d .lp-sat-wrap { position: relative; height: 320px; }
html.lp-lite .lp-fallo {
  position: relative; left: auto; right: auto; bottom: auto;
  border-radius: 0; background: none;
}
html.lp-lite .lp-fallo::before { display: none; }
/* La cabecera envuelve en dos renglones: con el recorte de una sola línea, a
   390px se leía «Fallo de tutela de pri…» y desaparecía el <b> con el radicado
   —el hilo que ata las cuatro caras, el memorial, el muro, el contador y la
   bitácora—. Medido: 113px de caja para 578px de texto. */
html.lp-lite .lp-fallo .fa-cab { flex-wrap: wrap; }
html.lp-lite .lp-fallo .fa-exp {
  white-space: normal; overflow: visible; text-overflow: clip;
}
html.lp-lite .lp-fallo .fa-o { grid-template-columns: minmax(0, 1fr); gap: 5px; }
html.lp-lite .lp-fallo .fa-llave { display: none; }
html.lp-lite .lp-fallo .fa-r {
  padding-left: 11px; border-left: 1px solid var(--border);
}
html.lp-lite .lp-fallo .fa-t .ul { transform: none !important; }
html.lp-lite .lp-fallo .fa-r { opacity: 1 !important; }

/* ── Reduced-motion: el mismo deck, y ni un gesto ─────────────────────────
   Redundante con el gate de arriba a propósito: pase lo que pase con las
   clases, aquí la lectura se lee quieta y completa. */
@media (prefers-reduced-motion: reduce) {
  .lp-face-d .lp-sat-wrap { position: relative; height: 320px; }
  .lp-fallo {
    position: relative; left: auto; right: auto; bottom: auto;
    border-radius: 0; background: none;
  }
  .lp-fallo::before { display: none; }
  .lp-fallo .fa-o { grid-template-columns: minmax(0, 1fr); gap: 5px; }
  .lp-fallo .fa-llave { display: none; }
  .lp-fallo .fa-r { padding-left: 11px; border-left: 1px solid var(--border); }
  .lp-fallo .fa-t .ul { transform: none !important; }
  .lp-fallo .fa-r { opacity: 1 !important; }
}

/* ── Papel ────────────────────────────────────────────────────────────────
   El acto pineado no se puede imprimir como pantalla congelada: la ventana
   mide 460vh y en papel solo salía la cara que estuviera activa —con lo cual
   esta lectura podía no imprimirse nunca—. Aquí el acto se acuesta (las
   mismas reglas que ya usan lite y reduced-motion) y la lectura del fallo
   sale en tinta negra sobre blanco, con los subrayados y las llaves ya
   trazados. Es solo papel: en pantalla no cambia una coma del acto. */
@media print {
  .lp-flip { height: auto !important; min-height: 0 !important; }
  .lp-flip .pin-spacer {
    height: auto !important; min-height: 0 !important; padding: 0 !important;
  }
  /* El pin deja escrito en línea el alto, el ancho y el recorte de la franja
     pineada: sin soltarlos, en papel la ventana seguiría midiendo una pantalla
     y las caras apiladas se cortarían dentro de ella. */
  .lp-flip-sticky {
    position: relative !important; height: auto !important; min-height: 0 !important;
    max-height: none !important; width: auto !important; max-width: none !important;
    inset: auto !important; transform: none !important; overflow: visible !important;
    display: block !important; perspective: none !important; padding: 0 !important;
  }
  .lp-flip-bg, .lp-flip-aurora, .lp-chrome,
  .lp-device-shadow, .lp-device-sheen { display: none !important; }
  .lp-flip-stage { transform: none !important; }
  .lp-device {
    transform: none !important; width: auto !important; aspect-ratio: auto !important;
    overflow: visible !important; background: none !important;
    border: 0 !important; box-shadow: none !important;
  }
  .lp-face {
    position: relative !important; inset: auto !important; transform: none !important;
    opacity: 1 !important; visibility: visible !important;
    margin-bottom: 14px; box-shadow: none !important;
    break-inside: avoid; page-break-inside: avoid;
  }
  /* Las piezas de cada pantalla llevan turno escrito en línea por el scrub: en
     papel no hay turno que valga. */
  .lp-face [data-pz] { transform: none !important; opacity: 1 !important; }
  .lp-face-bar { visibility: visible !important; }
  .lp-flip-title {
    position: relative !important; transform: none !important;
    left: auto !important; bottom: auto !important; width: auto !important;
    display: block !important;
    /* El visor de la leyenda es cosa de la película: en papel las cuatro se
       imprimen una debajo de otra, sin ranura ni máscara que las recorte. */
    height: auto !important; overflow: visible !important;
    -webkit-mask-image: none !important; mask-image: none !important;
  }
  .lp-flip-cap {
    grid-area: auto !important; opacity: 1 !important; transform: none !important;
    height: auto !important; margin-bottom: 8px;
  }
  /* Tinta: la ventana en papel es blanca y su texto negro. Sin esto, aplanar
     el acto habría sacado tres pantallas de UI oscura impresas en gris claro
     sobre blanco (los navegadores no imprimen fondos). */
  .lp-face, .lp-face .lp-face-bar { background: #fff !important; }
  .lp-face { border-color: #999 !important; }
  .lp-face .lp-face-bar { border-bottom-color: #ccc !important; }
  .lp-face .lp-face-bar i { background: #ccc !important; }
  .lp-face .t, .lp-face .n, .lp-face .ttl, .lp-face .ask, .lp-face .stream,
  .lp-face .doc p { color: #000 !important; }
  .lp-face .d, .lp-face .l, .lp-face .sub, .lp-face .tw, .lp-face .rad,
  .lp-face .model, .lp-face .lp-cite, .lp-face .lp-face-bar span { color: #444 !important; }
  /* Las dos citas verificables nacen en opacity 0 —las levanta el scrub al
     pisar la meseta de la cara B—: sin esto, la cara que vende «IA que cita la
     fuente» se imprimía sin una sola cita, aunque el bloque de arriba ya se
     tomaba el trabajo de entintarlas. El cuerpo de la respuesta lo vuelca
     landing-film.js en beforeprint; el caret que parpadea no va a papel. */
  .lp-cite {
    opacity: 1 !important; transform: none !important;
    background: none !important; border-color: #999 !important;
  }
  .lp-face .stream .cur, .lp-face .doc .cur { display: none !important; }
  .lp-face .lp-pill {
    background: none !important; border: 1px solid #999 !important; color: #000 !important;
  }
  .lp-face .doc { background: #fff !important; border-color: #999 !important; }
  /* La constelación conserva su caja (los satélites son absolutos) y deja de
     depender de lo que el scrub hubiera dejado escrito en línea. */
  .lp-face-d {
    min-height: 0 !important; background: #fff !important; border-color: #999 !important;
  }
  .lp-face-d .lp-sat-wrap {
    /* `top: auto` porque en película la constelación arranca por debajo de la
       cabecera del chasis, y una hoja de papel ancha puede satisfacer el gate
       de esa regla: sin esto la constelación se imprimiría 40 px más abajo. */
    position: relative !important; top: auto !important;
    height: 300px; perspective: none !important;
  }
  .lp-sat {
    opacity: 1 !important; visibility: visible !important; transform: none !important;
    background: #fff !important; border-color: #bbb !important; box-shadow: none !important;
  }
  .lp-sat .sh { color: #555 !important; }
  /* La lectura, en tinta. */
  .lp-fallo {
    /* display explícito: la hoja mide menos de 940px CSS y sin esto caería en
       la franja donde la lectura no se ofrece. En papel siempre se imprime. */
    display: block !important;
    position: relative !important; left: auto !important; right: auto !important;
    bottom: auto !important; border-radius: 0; background: none !important;
    border-top-color: #999;
    break-inside: avoid; page-break-inside: avoid;
  }
  .lp-fallo::before { display: none !important; }
  .lp-fallo .fa-o { grid-template-columns: minmax(0, 1fr); gap: 5px; }
  .lp-fallo .fa-llave { display: none !important; }
  .lp-fallo .fa-r {
    opacity: 1 !important; transform: none !important;
    padding-left: 11px; border-left: 1px solid #ccc;
  }
  .lp-fallo .fa-cab, .lp-fallo .fa-r .l { color: #555; }
  .lp-fallo .fa-k { color: #000; }
  .lp-fallo .fa-exp b, .lp-fallo .fa-t, .lp-fallo .fa-t .or,
  .lp-fallo .fa-t .vb, .lp-fallo .fa-r .v { color: #000; }
  .lp-fallo .fa-r .nb { color: #555; }
  .lp-fallo .fa-t .ul {
    transform: none !important; border-bottom-color: #000;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   SIN JS · EL ESTADO LEGIBLE ES EL DEFECTO
   --------------------------------------------------------------------------
   REGLA DE LA CASA: la información nunca depende del movimiento.

   Toda la coreografía de esta página nace de estados VACÍOS —opacidad 0,
   escalas a cero, actos pineados a 460vh, caras del dispositivo con
   visibility:hidden— que solo el JavaScript deshace. Si el JS no corre, esos
   estados se quedan puestos y el visitante no lee NADA: se midió, y en
   1440×900 con los scripts fuera quedaban invisibles 68 bloques con texto,
   entre ellos el hero entero, los tres planes y las ocho preguntas.

   ESTO LO TAPABA UN <style> DENTRO DE <noscript>, y tenía dos agujeros:

     1. <noscript> SOLO se renderiza cuando el navegador tiene el scripting
        DESACTIVADO. Si los scripts están activos pero no llegan —404 tras un
        deploy a medias, red caída, un bloqueador, una CSP de más— el navegador
        no lo mira y la página se queda en blanco igual. Ese es el caso normal
        en producción, no el exótico;
     2. era una lista escrita a mano que había que acordarse de ampliar cada
        vez que nacía una pieza. La boleta de audiencia del hero se añadió el
        14-ago y nadie la añadió allí: nacía invisible en escritorio ancho por
        los dos caminos.

   EL CONTRATO NUEVO, en una sola pieza y sin lista paralela: landing-boot.js
   marca `html.lp-js` en el <head>, síncrono y antes del primer paint, y
   landing.js confirma con `html.lp-vivo` que el motor de verdad llegó (si no,
   boot retira la marca en DOMContentLoaded). Todo lo que sigue solo se aplica
   cuando esa marca NO está — es decir, cuando no hay quien deshaga nada.

   POR ESO ESTO NO ES «CSS PARA NOSCRIPT»: cubre el scripting desactivado, el
   script que no cargó y el script que reventó, y no hay un segundo sitio que
   mantener. Las piezas con película propia (.sal-cine, .me-cine, .cz-cine,
   .mu-cine, .fa-cine, .pr-vivo) no necesitan una línea aquí: su vaciado ya
   cuelga de una clase que pone su propio módulo, así que sin JS nacen enteras.

   `!important` en todo el bloque a propósito: le tiene que ganar a estados de
   partida que viven dentro de media queries y con especificidades muy altas.
   Va al final del archivo para no depender del orden de nada.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── La coreografía de entrada: todo aterrizado ───────────────────────────── */
html:not(.lp-js) .lp-reveal { opacity: 1 !important; transform: none !important; }
/* Las piezas que entran POR DENTRO del reveal (cabecera de sección, renglones
   de los planes, ordinal de los diferenciadores, respuesta de la FAQ) llevan su
   propio estado de partida: sin JS nadie les pone .lp-shown. */
html:not(.lp-js) .lp-head.lp-reveal > *,
html:not(.lp-js) .lp-plans .lp-plan li,
html:not(.lp-js) .lp-diffs .lp-diff .n,
html:not(.lp-js) .lp-faq-a-txt {
  opacity: 1 !important; transform: none !important; transition: none !important;
}
html:not(.lp-js) .lp-halves .lp-half.whole::after { transform: scaleX(1) !important; }
html:not(.lp-js) .lp-how-step::before { display: none !important; }
html:not(.lp-js) .lp-display .ln .i { transform: none !important; opacity: 1 !important; }

/* ── El hero: las DOS piezas impresas, sin hilos ──────────────────────────
   La ficha y la boleta ya nacen impresas por defecto (su vaciado cuelga de
   `html.lp-js`, más arriba en este archivo). Aquí solo se retiran los hilos,
   que sin motor no tienen de dónde salir, y se refuerzan los contenidos
   enmascarados por si alguna regla futura los vuelve a vaciar. */
html:not(.lp-js) .lp-hilo { display: none !important; }
html:not(.lp-js) .lp-ficha,
html:not(.lp-js) .lp-boleta { opacity: 1 !important; transform: none !important; }
html:not(.lp-js) .lp-salida .mk .i,
html:not(.lp-js) .lp-boleta .mk .i { transform: none !important; opacity: 1 !important; }

/* ── Los actos pineados se aplanan y vuelven al flujo ─────────────────────── */
html:not(.lp-js) .lp-flip,
html:not(.lp-js) .lp-thesis { height: auto !important; min-height: 0 !important; }
html:not(.lp-js) .lp-flip-sticky,
html:not(.lp-js) .lp-thesis-sticky {
  position: relative !important; height: auto !important; min-height: 0 !important;
  display: block !important; perspective: none !important; padding: 60px 0 !important;
}
html:not(.lp-js) .lp-device {
  transform: none !important; width: min(600px, 92vw) !important;
  margin: 0 auto !important; aspect-ratio: auto !important;
}
html:not(.lp-js) .lp-chrome { display: none !important; }
html:not(.lp-js) .lp-face {
  position: relative !important; inset: auto !important; transform: none !important;
  backface-visibility: visible !important; margin-bottom: 20px !important;
  opacity: 1 !important; visibility: visible !important;
}
/* El turno de cada pieza dentro de la pantalla lo escribe el scrub en línea:
   sin motor no hay turno, hay tarjeta entera. */
html:not(.lp-js) .lp-face [data-pz] { transform: none !important; opacity: 1 !important; }
html:not(.lp-js) .lp-face-d { min-height: 320px !important; }
/* La lectura del fallo deja de ser el piso de una ventana y pasa al flujo: la
   constelación conserva su caja y cada lectura se recuesta debajo de su
   ordinal. Nace trazada — sin JS no hay nada que apagar. */
html:not(.lp-js) .lp-face-d .lp-sat-wrap { position: relative !important; height: 320px !important; }
html:not(.lp-js) .lp-fallo {
  display: block !important; position: relative !important; left: auto !important;
  right: auto !important; bottom: auto !important; border-radius: 0 !important;
  background: none !important;
}
html:not(.lp-js) .lp-fallo .fa-o { grid-template-columns: minmax(0, 1fr) !important; gap: 5px !important; }
html:not(.lp-js) .lp-fallo .fa-llave { display: none !important; }
html:not(.lp-js) .lp-fallo .fa-r {
  opacity: 1 !important; transform: none !important;
  padding-left: 11px !important; border-left: 1px solid var(--border) !important;
}
html:not(.lp-js) .lp-fallo .fa-t .ul { transform: none !important; }
html:not(.lp-js) .lp-flip-title {
  position: relative !important; transform: none !important; left: auto !important;
  bottom: auto !important; width: 100% !important; margin-bottom: 20px !important;
  display: block !important;
}
html:not(.lp-js) .lp-flip-cap {
  grid-area: auto !important; opacity: 1 !important; transform: none !important;
  margin-bottom: 14px !important;
}
html:not(.lp-js) .lp-thesis-line {
  position: relative !important; opacity: 1 !important; bottom: auto !important;
  margin-top: 30px !important;
}
html:not(.lp-js) .lp-cite { opacity: 1 !important; transform: none !important; }
html:not(.lp-js) .lp-face-a .a-rows { transform: none !important; }
html:not(.lp-js) .lp-face-a .row { height: auto !important; }
html:not(.lp-js) .lp-face-a .row .t,
html:not(.lp-js) .lp-face-a .row .d { white-space: normal !important; }
html:not(.lp-js) .lp-face-a .row-alerta { opacity: 1 !important; }
html:not(.lp-js) .lp-face-a .a-odo-roll { transform: translateY(-50%) !important; }
/* «hace N min» lo escribe el reloj del cliente: sin él manda el texto fijo. */
html:not(.lp-js) .lp-face-a .tw-live { display: none !important; }
html:not(.lp-js) .lp-face-a .tw-static { display: inline !important; }
html:not(.lp-js) .lp-how-figure { aspect-ratio: auto !important; }
html:not(.lp-js) .lp-how-scene {
  position: static !important; opacity: 1 !important; transform: none !important;
  animation: none !important;
}
html:not(.lp-js) .lp-wordmark .wl.out { opacity: 0 !important; }
html:not(.lp-js) .lp-wordmark .wl.fill { opacity: 1 !important; }
/* El subrayado del veredicto es un HIJO REAL (.nv .ul), no un ::after: lo
   dibuja el raíl del término con un scaleX. Sin JS no hay raíl ni .lp-shown,
   así que aquí se entrega ya trazado — si no, «no se subsana» se quedaba sin
   su única señal semántica. */
html:not(.lp-js) .lp-pain-close .nv .ul { transform: scaleX(1) !important; transition: none !important; }
/* La FAQ sin JS: el acordeón no puede abrir, así que las respuestas se
   entregan desplegadas y el control deja de ofrecerse como tal (no se ofrece
   lo que no responde). Antes quedaban ocho preguntas mudas. */
html:not(.lp-js) .lp-faq-a {
  grid-template-rows: 1fr !important; visibility: visible !important; transition: none !important;
}
html:not(.lp-js) .lp-faq-q { cursor: default !important; }
html:not(.lp-js) .lp-faq-q .chev { display: none !important; }
/* Expediente BSC: con la película aplanada, la escena anterior termina en
   contenido apilado — el 112.768 no debe treparse encima. */
html:not(.lp-js) .lp-exp-monu .v { margin-top: 0 !important; }

/* La constelación de la cara D la coloca GSAP con estilos EN LÍNEA
   (opacity/transform), y un estilo en línea solo lo derrota un !important: si
   landing-film.js llegó pero landing.js no, los cinco paneles se quedaban
   invisibles con la escena ya aplanada. */
html:not(.lp-js) .lp-sat {
  opacity: 1 !important; visibility: visible !important; transform: none !important;
}
