/* ============================================================
   SPEACH — COMPONENTES. Secciones nuevas y piezas jugables.
   Dueño: A-COMP (§2.1 del contrato).
   · No declara tokens: el :root de §1 vive en speach.css.
   · No toca header, footer, botones ni campos.
   · Cero hex, cero duraciones y cero curvas a mano (§10.1).
   · Cero blanco literal y cero tinta literal: sólo tokens semánticos,
     para que [data-mode="ink"] invierta sin tocar un componente.
   · Todo marco de imagen lleva fondo de marca debajo: si el
     raster no existe todavía, el hueco se ve terminado (§7.3).
   ============================================================ */


/* ---------- 0. Lenguaje gráfico compartido ---------- */

/* Marco-burbuja: tres esquinas suaves y la cola abajo-izquierda, la misma
   geometría del icono de globo de diálogo. El fondo (gradiente de marca +
   halftone) es el fallback obligatorio de cada raster. */
.hero-media, .quienes-media, .svc-preview, .fam-media, .team-ph, .ba-stage, .work .frame {
  position: relative; overflow: hidden; border-radius: var(--r-bubble);
  background-color: var(--pk-100);
  background-image: radial-gradient(var(--pk-300) 1px, transparent 1.3px),
                    linear-gradient(160deg, var(--pk-200) 0%, var(--pk-50) 58%, var(--surface) 100%);
  background-size: 8px 8px, auto;
  color: var(--fg); font-size: var(--t-caption); /* el alt de una imagen que falta se lee */
}
[data-mode="ink"] :is(.hero-media,.quienes-media,.svc-preview,.fam-media,.team-ph,.ba-stage,.work .frame) {
  background-color: var(--surface);
  background-image: radial-gradient(var(--pk-800) 1px, transparent 1.3px),
                    linear-gradient(160deg, var(--pk-900) 0%, var(--surface) 70%);
}
:is(.hero-media,.quienes-media,.svc-preview,.fam-media,.team-ph,.ba-stage,.work .frame) > :is(img,video) {
  width: 100%; height: 100%; object-fit: cover; filter: brightness(var(--img-bright));
}

/* Las cifras grandes van LIMPIAS: serif sobre papel, sin tramas detrás. La
   trama de puntos abarataba el numeral; el aire alrededor es el lujo. */

/* El punto fucsia es el motor: crece cuando su fila despierta. */
:is(.svc-row,.work .work-card,.fam-head,.cifra) .dot { display: inline-block; transform-origin: 50% 85%; transition: transform var(--t-3) var(--e-back); }
:is(.svc-row,.work .work-card,.fam-head,.cifra):is(:hover,:focus-within) .dot { transform: scale(1.35); }

/* Numeración de capítulos: serif itálica gigante a baja opacidad. Nunca se lee
   como dato, se lee como textura ordenada (§5.9). */
.cap-n, .rail-n {
  position: absolute; z-index: 0; font-family: var(--serif); font-style: italic;
  line-height: var(--lh-display); color: var(--pk-100); pointer-events: none; user-select: none;
}
.cap-n { inset: -.12em auto auto -.06em; font-size: clamp(6rem, 14vw, 14rem); }
[data-mode="ink"] :is(.cap-n,.rail-n) { color: var(--pk-900); }

/* Botón compacto: dots del riel, cambio de vista, pasos del brief. Área
   táctil de 44px y estado activo que no depende sólo del color. */
.rail-dots button, .work-view button, .brief-steps button {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
  min-height: 44px; min-width: 44px; padding-inline: var(--s-4);
  border: 1px solid var(--line-strong); border-radius: var(--r-full);
  background: transparent; color: var(--fg-2); font: inherit; font-size: var(--t-caption);
  font-weight: var(--wght-ui); cursor: pointer;
  transition: border-color var(--t-2) var(--e-out), color var(--t-2) var(--e-out);
}
:is(.rail-dots,.work-view,.brief-steps) button i { font-style: normal; font-variant-numeric: tabular-nums; color: var(--fg-muted); }
:is(.rail-dots,.work-view,.brief-steps) button:hover { border-color: var(--fg); color: var(--fg); }
:is(.rail-dots,.work-view,.brief-steps) button:is([aria-current="true"],[aria-pressed="true"],[aria-current="step"]) {
  border-color: var(--accent); color: var(--fg); background: color-mix(in srgb, var(--accent) 12%, transparent);
}
:is(.rail-dots,.work-view,.brief-steps) button[aria-current] i { color: var(--accent-fg); }
:is(.rail-dots,.work-view,.brief-steps) button[disabled] { background: var(--disabled-bg); border-color: var(--disabled-bg); color: var(--disabled-fg); cursor: not-allowed; }

/* Piezas: contención de layout, y ningún control muerto si la pieza falla. */
.toy-ba, .toy-perf, .toy-tokens, .toy-brief { contain: layout style; min-width: 0; }
:is(.toy-ba,.toy-perf,.toy-tokens,.toy-brief)[data-state="error"] .js-only { display: none; }

/* Aviso ámbar reutilizado por tres piezas. */
.tk-warn, .brief-hint, .brief-warn { color: var(--wa); font-size: var(--t-body-s); }
[data-mode="ink"] :is(.tk-warn,.brief-hint,.brief-warn) { color: var(--wa-ink); }


/* ---------- 1. Hero ---------- */

.hero { position: relative; overflow: clip; padding-block: clamp(var(--s-6), 7vw, var(--s-9)) var(--sec-y-tight); }
/* Burbuja de trama al fondo. Decorativa, sin puntero, nunca encima del H1. */
.hero::before {
  content: ''; position: absolute; z-index: 0; inset: calc(var(--s-6) * -1) calc(var(--pad) * -.4) auto auto;
  width: min(42vw, 460px); aspect-ratio: 1; border-radius: var(--r-bubble-lg);
  background-image: radial-gradient(var(--pk-200) 1px, transparent 1.4px); background-size: 14px 14px;
  mask-image: radial-gradient(70% 70% at 70% 30%, currentColor, transparent); pointer-events: none;
}
[data-mode="ink"] .hero::before { background-image: radial-gradient(var(--pk-800) 1px, transparent 1.4px); }
.hero-in { position: relative; z-index: var(--z-raised); display: grid; gap: var(--s-5); align-items: end; }
.hero-in > * { min-width: 0; }
.hero-t { max-width: var(--maxw-disp); }
.hero-lead { max-width: var(--maxw-lead); }
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-4); align-items: center; margin-block-start: var(--s-2); }
.hero-scroll { display: flex; align-items: center; gap: var(--s-2); margin-block-start: var(--s-7); color: var(--fg-muted); font-size: var(--t-caption); font-weight: var(--wght-ui); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; }
.hero-media { aspect-ratio: 4 / 3; }
@media (min-width: 900px) {
  /* Con media, el hero pasa a dos columnas. Sin ella no cambia nada. */
  .hero-in:has(.hero-media) { grid-template-columns: minmax(0,1.15fr) minmax(0,.85fr); gap: var(--s-7); align-items: center; }
  .hero-in:has(.hero-media) .hero-media { grid-column: 2; grid-row: 1 / span 4; }
}


/* ---------- 2. Quiénes somos ---------- */

.quienes { position: relative; }
.quienes-in { display: grid; gap: var(--s-6); align-items: start; }
.quienes-in > * { min-width: 0; }
.quienes-media { aspect-ratio: 1; }
@media (min-width: 900px) { .quienes-in { grid-template-columns: minmax(0,1.35fr) minmax(0,.65fr); gap: var(--s-8); } }
.qs-nums { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(180px,100%), 1fr)); gap: var(--s-5) var(--s-6); margin-block-start: var(--s-7); }
.qs-num { position: relative; overflow: clip; padding-block-start: var(--s-3); border-block-start: 1px solid var(--line); }
.qs-num b { position: relative; z-index: var(--z-raised); display: block; font-family: var(--serif); font-size: var(--t-num); font-weight: 400; line-height: var(--lh-display); letter-spacing: -.01em; font-synthesis: none; }
/* Hijo directo: la etiqueta. El descendiente universal alcanzaba a los spans
   del marcador data-ph DENTRO de la cifra y la encogía a cuerpo de nota.      */
.qs-num > span { display: block; max-width: 30ch; margin-block-start: var(--s-2); color: var(--fg-muted); font-size: var(--t-body-s); }
/* Al pasar el puntero, el filete gris se reescribe en acento de izquierda a
   derecha y la cifra se asoma. Sólo scale y translate: nada de layout.        */
.qs-num::after {
  content: ''; position: absolute; inset: 0 0 auto; height: 2px;
  background: var(--accent); transform-origin: 0 50%; scale: 0 1;
  transition: scale var(--t-4) var(--e-expo);
}
.qs-num:hover::after { scale: 1 1; }
.qs-num b { transition: translate var(--t-3) var(--e-out); }
.qs-num:hover b { translate: 0 calc(var(--m-0) * -1); }


/* ---------- 3. Lista de servicios ---------- */

/* Dos columnas cuando la sección trae slot de preview. Se detecta con :has()
   para no obligar al HTML a inventar una clase de maquetación. */
@media (min-width: 1024px) {
  :is(div,section,article):has(> .svc-list):has(> .svc-preview) {
    display: grid; grid-template-columns: minmax(0,1fr) clamp(240px, 24vw, 340px);
    gap: var(--s-7); align-items: start;
  }
}
.svc-list { min-width: 0; border-block-end: 1px solid var(--line); }
.svc-row {
  position: relative; display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center;
  gap: var(--s-3) var(--s-4); min-height: clamp(4rem, 7vw, 6.5rem); padding-block: var(--s-5);
  border-block-start: 1px solid var(--line); color: inherit;
  transition: opacity var(--t-3) var(--e-out), transform var(--t-4) var(--e-out), border-color var(--t-3) var(--e-out);
}
/* Atenuación de hermanos. Piso duro .72: por debajo se cae de 1.4.3 (§8.4·15). */
.svc-list[data-active] .svc-row { opacity: .72; }
.svc-list[data-active] .svc-row:is(:hover,:focus-within), .svc-list .svc-row[data-active] { opacity: 1; }
.svc-row:is(:hover,:focus-within) { border-color: var(--accent); }
.svc-t { font-family: var(--serif); font-size: calc(var(--t-h2)*1.1); font-weight: 400; font-synthesis: none; line-height: var(--lh-tight); letter-spacing: -.008em; }
/* La línea de apoyo está SIEMPRE en el DOM y siempre visible, en todos los
   anchos. §8.4·15 lo prefiere así: en reposo todo se lee, y lo que cambia al
   hover es el punto, el desplazamiento y la preview. */
.svc-d { grid-column: 1; max-width: 52ch; color: var(--fg-muted); font-size: var(--t-body-s); }
/* Cuando la fila es un <details> (ficha de servicio), el reparto en dos
   columnas se aplica al <summary>: la ficha ocupa el ancho completo debajo. */
details.svc-row { display: block; }
details.svc-row > summary { display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: var(--s-4); min-height: clamp(3rem, 5vw, 4.5rem); list-style: none; cursor: pointer; }
details.svc-row > summary::-webkit-details-marker { display: none; }
details.svc-row > summary::after { content: ''; inline-size: 20px; block-size: 20px; color: var(--accent); background: linear-gradient(currentColor, currentColor) center / 100% 1.75px no-repeat, linear-gradient(currentColor, currentColor) center / 1.75px 100% no-repeat; transition: rotate var(--t-3) var(--e-out); }
details.svc-row[open] > summary::after { rotate: 45deg; }
.svc-i { grid-column: 2; grid-row: 1; align-self: center; color: var(--accent-fg); transition: transform var(--t-3) var(--e-out); }
.svc-row:is(:hover,:focus-within) .svc-i { transform: translate(3px, -3px); }
.svc-row:is(:hover,:focus-within) .svc-d { color: var(--fg-2); }
@media (min-width: 1024px) { .svc-row:is(:hover,:focus-within) { transform: translateX(var(--m-2)); } }
/* Preview anclada a un slot fijo. No sigue al cursor: así :focus-within da
   exactamente el mismo estado que :hover (§8.4·16). */
.svc-preview { display: none; }
@media (min-width: 1024px) {
  .svc-preview { display: block; position: sticky; inset-block-start: calc(var(--hd-h) + var(--s-6)); aspect-ratio: 4 / 5; }
  .svc-preview img { transition: opacity var(--t-3) var(--e-out); }
}
/* motion.js escribe background-image por CSSOM y eso REEMPLAZA las dos capas
   del marco-burbuja. Sin esto la imagen heredaba el background-size 8px 8px
   del halftone y se veía en mosaico. Va fuera del @media: el atributo puede
   llegar antes de que la consulta aplique.                                    */
.svc-preview[data-active] { background-size: cover; background-repeat: no-repeat; background-position: center; }
/* El arte de reposo cede el sitio al de la fila activa. :not([data-active=""])
   es obligatorio: en /servicios/ las filas no traen data-svc, el slug llega
   vacío y sin la guarda el hover blanquearía la preview de cada familia.      */
.svc-preview[data-active]:not([data-active=""]) > img { opacity: 0; }

/* -- El índice del home (.svc-index). Las fichas de /servicios/ no cambian:
   todo lo de aquí abajo cuelga del modificador. Cada fila lleva folio serif
   y, al despertar, una cortina fucsia entra por la izquierda —el mismo gesto
   del telón— mientras el texto pasa a tinta sobre acento (5.94:1 ✓AA).        */
.svc-index .svc-row { grid-template-columns: auto minmax(0,1fr) auto; }
.svc-index .svc-d { grid-column: 2; }
.svc-index .svc-i { grid-column: 3; }
.svc-index .svc-row > * { position: relative; z-index: var(--z-raised); }
.svc-n {
  grid-row: 1; align-self: center; min-width: 2.4ch;
  color: var(--accent-fg); font-family: var(--serif); font-style: italic;
  font-size: var(--t-h4); line-height: 1;
  transition: color var(--t-2) var(--e-out);
}
.svc-index .svc-row::before {
  content: ''; position: absolute; z-index: var(--z-base); inset: 0 calc(var(--s-4) * -1);
  border-radius: var(--r-bubble); background: var(--accent);
  clip-path: inset(0 100% 0 0 round var(--r-bubble));
  transition: clip-path var(--t-3) var(--e-snap);
}
.svc-index .svc-row:is(:hover,:focus-within)::before { clip-path: inset(0 0 0 0 round var(--r-bubble)); }
.svc-index :is(.svc-t,.svc-d,.svc-i) { transition: color var(--t-2) var(--e-out); }
.svc-index .svc-row:is(:hover,:focus-within) :is(.svc-t,.svc-d,.svc-i,.svc-n,.svc-t .dot) { color: var(--on-accent); }

/* La regla de cada fila se DIBUJA al pasar: sólo scale, sólo con timelines de
   scroll y nunca con movimiento reducido. Sin soporte queda el borde normal:
   una línea que miente es peor que ninguna (§6 de motion.css).                */
@supports (animation-timeline: view()) {
  html.js:not(.rm) .svc-index .svc-row { border-block-start-color: transparent; }
  html.js:not(.rm) .svc-index .svc-row::after {
    content: ''; position: absolute; inset: -1px 0 auto; height: 1px;
    background: var(--line); transform-origin: 0 50%;
    animation: svc-linea var(--e-lin) both; animation-timeline: view();
    animation-range: entry 0% cover 30%;
  }
}
@keyframes svc-linea { from { scale: 0 1; } to { scale: 1 1; } }


/* ---------- 4. Lo construimos nosotros (.dev-band, en tinta) ---------- */

.dev-band { position: relative; overflow: clip; }
.dev-band-in { display: grid; gap: var(--s-6); align-items: start; }
.dev-band-in > * { min-width: 0; }
@media (min-width: 900px) { .dev-band-in { grid-template-columns: minmax(0,.9fr) minmax(0,1.1fr); gap: var(--s-8); } }
.dev-band-note { max-width: 46ch; margin-block-start: var(--s-5); color: var(--fg-muted); font-size: var(--t-body-s); }
/* Variante mini de La Báscula: sin anillos, sólo cifras vivas. */
.dev-band .perf-grid { grid-template-columns: repeat(auto-fit, minmax(min(150px,100%), 1fr)); gap: var(--s-5); }
.dev-band .gauge { display: block; padding: 0; border: 0; background: none; }
.dev-band .gauge-svg { display: none; }
.dev-band .gauge-num { font-size: var(--t-h1); }


/* ---------- 5. El Riel ---------- */

.rail { position: relative; }
/* Carrusel nativo: contenedor real con scroll y snap. Sin pin, sin hijack (D3).
   Scrollea dentro de sí mismo: el body nunca se mueve en horizontal. */
.rail-track {
  display: flex; gap: var(--gutter); max-inline-size: 100%;
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
  padding-block-end: var(--s-4);
}
/* Sólo Firefox: la píldora global vive en speach.css §SCROLLBAR. Declarar
   scrollbar-width fuera de este @supports la anularía en Chrome ≥121; el
   color llega heredado del [data-mode] más cercano (misma sección).          */
@supports not selector(::-webkit-scrollbar){
  .rail-track{ scrollbar-width: thin }
}
.rail-panel {
  position: relative; flex: 0 0 clamp(258px, 76vw, 420px); scroll-snap-align: center;
  display: flex; flex-direction: column; gap: var(--s-3); overflow: hidden;
  padding: var(--s-6) var(--s-5) var(--s-5); border: 1px solid var(--line);
  border-radius: var(--r-md); background: var(--surface);
  transition: border-color var(--t-3) var(--e-out), box-shadow var(--t-3) var(--e-out);
}
.rail-panel:hover { border-color: var(--line-strong); box-shadow: var(--sh-2); }
.rail-panel > :not(.rail-n) { position: relative; z-index: var(--z-raised); }
/* El índice de fase dejó de ser un fantasma gigante recortado: es una cifra
   serif itálica en fucsia, pequeña y a plomo con el título — se lee como
   folio de capítulo, no como marca de agua a medio imprimir. */
.rail-n { position: static; font-size: var(--t-h3); font-style: italic;
  color: var(--accent-fg); line-height: 1; }
.rail-panel h3 { font-family: var(--serif); font-weight: 400; font-synthesis: none;
  font-size: calc(var(--t-h3)*1.15); letter-spacing: -.006em; }
.rail-panel p:not(.rail-n) { color: var(--fg-2); font-size: var(--t-body-s); line-height: var(--lh-body); }
.rail-meta { display: grid; gap: var(--s-2); margin-block-start: auto; padding-block-start: var(--s-4); border-block-start: 1px solid var(--line); }
.rail-meta > div { display: grid; grid-template-columns: 9ch minmax(0,1fr); gap: var(--s-3); }
.rail-meta dt { color: var(--fg-muted); font-size: var(--t-caption); }
.rail-meta dd { font-size: var(--t-caption); font-weight: var(--wght-ui); }
.rail-dots { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-block-end: var(--s-5); }
/* "03 / 06" es texto real, no un adorno: lo anuncia SP.say(). */
.rail-count { color: var(--fg-muted); font-size: var(--t-caption); font-variant-numeric: tabular-nums; letter-spacing: var(--ls-eyebrow); }


/* ---------- 6. Las cifras ---------- */

.cifras { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px,100%), 1fr)); gap: var(--s-6) var(--s-7); max-inline-size: 100%; }
.cifra { min-width: 0; overflow: clip; padding-block-start: var(--s-4); border-block-start: 1px solid var(--line); }
.cifra-d summary { display: grid; gap: var(--s-2); padding-block-end: var(--s-3); list-style: none; cursor: pointer; }
.cifra-d summary::-webkit-details-marker { display: none; }
.cifra-n { position: relative; display: block; font-family: var(--serif); font-size: var(--t-num); font-weight: 400; line-height: var(--lh-display); letter-spacing: -.01em; font-synthesis: none; }
/* :not(.sr-only) es obligatorio: position:relative le ganaba al absolute de
   .sr-only, el span volvía a ocupar sitio y estiraba la cifra a 1200 px.      */
.cifra-n > *:not(.sr-only) { position: relative; z-index: var(--z-raised); }
.cifra-l { display: block; max-width: min(26ch, 100%); color: var(--fg-2); font-size: var(--t-h4); font-weight: var(--wght-ui); }
/* El indicador es el mismo + que gira 45° hasta ser × (§6.6). El texto que lo
   acompaña vive en el HTML, nunca en un ::after. */
.cifra-mas { display: inline-flex; align-items: center; gap: var(--s-2); color: var(--accent-fg); font-size: var(--t-caption); font-weight: var(--wght-ui); }
.cifra-mas::after, .faq summary::after {
  content: ''; inline-size: 14px; block-size: 14px;
  background: linear-gradient(currentColor, currentColor) center / 100% 1.75px no-repeat,
              linear-gradient(currentColor, currentColor) center / 1.75px 100% no-repeat;
  transition: rotate var(--t-3) var(--e-out);
}
.cifra-d[open] .cifra-mas::after { rotate: 45deg; }
.cifra-nota { max-width: 46ch; padding-block-end: var(--s-4); color: var(--fg-muted); font-size: var(--t-body-s); line-height: var(--lh-body); }


/* ---------- 7. El trabajo ---------- */

.work { min-width: 0; max-inline-size: 100%; }
.work-bar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--s-3) var(--s-5); margin-block-end: var(--s-6); }
.work-view { display: flex; gap: var(--s-1); }
.work-view button { padding-inline: 0; }
.work .work-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px,100%), 1fr)); gap: var(--s-7) var(--gutter); }
.work .frame { aspect-ratio: 16 / 11; }
.work .work-card { min-width: 0; }
.work .work-card .meta-x { display: block; margin-block-start: var(--s-2); color: var(--fg-muted); font-size: var(--t-caption); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; }
/* Vista de lista: la misma tarjeta, otro reparto. Sin duplicar markup. */
.work .work-grid[data-view="list"] { grid-template-columns: minmax(0,1fr); gap: 0; }
.work .work-grid[data-view="list"] .work-card { display: grid; grid-template-columns: clamp(96px, 22vw, 190px) minmax(0,1fr); gap: var(--s-4) var(--s-5); align-items: center; padding-block: var(--s-4); border-block-start: 1px solid var(--line); }
.work .work-grid[data-view="list"] .frame { aspect-ratio: 4 / 3; }
.work .work-grid[data-view="list"] .meta { padding-block-start: 0; }
/* En lista la miniatura baja a 96 px y el chip absoluto se cortaba a media
   palabra. La categoría ya se lee en .meta-x, así que aquí sobra.             */
@media (max-width: 620px) { .work .work-grid[data-view="list"] .chip { display: none; } }
.work-empty { padding-block: var(--s-7); color: var(--fg-muted); text-align: center; }


/* ---------- 8. Quiénes lo hacen ---------- */

.team-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(210px,100%), 1fr)); gap: var(--s-6) var(--gutter); }
.team-card { min-width: 0; }
/* Los retratos son CÍRCULOS: los assets ya traen la foto circunscrita (anillo
   sobre negro) y el clip circular + el zoom del 9% dejan sólo la cara. El
   círculo además rima con el punto de la marca. */
.team-ph { aspect-ratio: 1; margin-block-end: var(--s-4); border-radius: 50%; }
.team-ph.duo img { transform: scale(1.09); }
.team-ph.duo:hover img, .team-ph.duo:focus-within img { transform: scale(1.13); }
.team-card h3 { font-family: var(--serif); font-weight: 400; font-synthesis: none; font-size: calc(var(--t-h3)*1.12); letter-spacing: -.006em; }
.team-role { display: block; margin-block-start: var(--s-1); color: var(--accent-fg); font-size: var(--t-caption); font-weight: var(--wght-ui); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; }
.team-bio { max-width: 34ch; margin-block-start: var(--s-3); color: var(--fg-muted); font-size: var(--t-body-s); line-height: var(--lh-body); }



/* ---------- 9. Encabezado de página, familias y fichas ---------- */

.page-head { position: relative; overflow: clip; padding-block: clamp(var(--s-7), 8vw, var(--s-9)) var(--sec-y-tight); }
.page-head-in { position: relative; z-index: var(--z-raised); display: grid; gap: var(--s-5); }
.page-head h1 { max-width: var(--maxw-disp); }
.page-head .lead { max-width: var(--maxw-lead); }
/* Borde vivo: la línea de gradiente que cierra el encabezado. */
.page-head::after { content: ''; position: absolute; inset: auto var(--pad) 0; height: 1px; background: var(--grad-borde); }

.fam { position: relative; }
.fam-head { position: relative; display: grid; gap: var(--s-3); max-width: var(--maxw-lead); margin-block-end: var(--s-6); }
.fam-n { font-family: var(--serif); font-style: italic; font-size: var(--t-h1); line-height: 1; color: var(--accent-fg); }
.fam-media { aspect-ratio: 4 / 5; }
/* Ficha de servicio. "Se mide" es el campo dominante, no la última línea:
   ninguna ficha entra al sitio sin ese campo lleno (§5.2). */
.ficha { display: grid; gap: var(--s-4); max-width: 64ch; padding-block: var(--s-2) var(--s-6); }
.ficha > div { display: grid; gap: var(--s-1); }
.ficha dt { color: var(--fg-muted); font-size: var(--t-eyebrow); font-weight: var(--wght-ui); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; }
.ficha dd { color: var(--fg-2); font-size: var(--t-body-s); line-height: var(--lh-body); }
.ficha-mide { padding: var(--s-4) var(--s-5); border-radius: var(--r-md); border-inline-start: 3px solid var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.ficha-mide dt { color: var(--accent-fg); }
.ficha-mide dd { color: var(--fg); font-size: var(--t-h4); font-weight: var(--wght-ui); line-height: var(--lh-lead); }


/* ---------- 10. FAQ (details nativos) ---------- */

.faq { min-width: 0; }
.faq-list { max-width: 78ch; margin-inline: auto; }
.faq details { border-block-start: 1px solid var(--line); interpolate-size: allow-keywords; }
.faq details:last-of-type { border-block-end: 1px solid var(--line); }
.faq summary {
  display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: center; gap: var(--s-4);
  padding-block: var(--s-5); padding-inline: var(--s-3); margin-inline: calc(var(--s-3) * -1);
  border-radius: var(--r-md); list-style: none; cursor: pointer;
  font-size: var(--t-h4); font-weight: var(--wght-h3); letter-spacing: var(--ls-ui);
  transition: background-color var(--t-2) var(--e-out);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.faq summary::after { color: var(--accent); inline-size: 20px; block-size: 20px; }
.faq details[open] summary::after { rotate: 45deg; }
.faq details > :not(summary) { max-width: 60ch; padding-inline: var(--s-3); padding-block-end: var(--s-6); color: var(--fg-2); line-height: var(--lh-body); }
@supports (interpolate-size: allow-keywords) {
  .faq details::details-content { block-size: 0; overflow: hidden; transition: block-size var(--t-4) var(--e-out), content-visibility var(--t-4) allow-discrete; }
  .faq details[open]::details-content { block-size: auto; }
}


/* ---------- 11. Stack ---------- */

.stack-table, .stack { min-width: 0; max-inline-size: 100%; }
/* Interruptor humanos/técnicos SIN JS: dos radios reales y :has(). */
.stack-switch { display: inline-flex; gap: var(--s-1); padding: var(--s-1); margin-block-end: var(--s-6); border: 1px solid var(--line-strong); border-radius: var(--r-full); }
.stack-switch label { display: inline-flex; align-items: center; gap: var(--s-2); min-height: 44px; padding-inline: var(--s-4); border-radius: var(--r-full); color: var(--fg-muted); font-size: var(--t-ui); font-weight: var(--wght-ui); cursor: pointer; transition: background-color var(--t-2) var(--e-out), color var(--t-2) var(--e-out); }
.stack-switch label:hover { color: var(--fg); }
.stack-switch input { margin: 0; accent-color: var(--accent); }
.stack-switch label:has(input:checked) { background: var(--accent); color: var(--on-accent); }
/* Dos lecturas del mismo contenido. Manda :has() (funciona sin JS); el atributo
   data-read existe para que el JS persista la preferencia en sp:read. */
.stack[data-read="human"] .s-tech, .stack[data-read="tech"] .s-human,
.stack:has(#r-human:checked) .s-tech, .stack:has(#r-tech:checked) .s-human { display: none; }
.stack-list { border-block-end: 1px solid var(--line); }
.stack-row { display: grid; grid-template-columns: minmax(0,1fr); gap: var(--s-2) var(--s-5); min-width: 0; padding-block: var(--s-5); border-block-start: 1px solid var(--line); }
.stack-row h3 { font-size: var(--t-h4); letter-spacing: var(--ls-ui); }
.stack-row p { max-width: 62ch; color: var(--fg-2); font-size: var(--t-body-s); line-height: var(--lh-body); }
.stack-capa { color: var(--fg-muted); font-size: var(--t-eyebrow); font-weight: var(--wght-ui); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; }
/* La línea "Por qué" nunca cambia entre lecturas. Es la que vende. */
.s-why { display: block; max-width: 62ch; padding-inline-start: var(--s-4); border-inline-start: 2px solid var(--accent); color: var(--fg-muted); font-size: var(--t-caption); line-height: var(--lh-body); }
@media (min-width: 860px) {
  .stack-row { grid-template-columns: 12ch minmax(0,1.1fr) minmax(0,1fr); align-items: start; }
  .stack-capa { grid-row: 1 / span 3; }
  .s-why { grid-column: 3; grid-row: 1 / span 3; }
}
.stack-cierre { max-width: 72ch; margin-block-start: var(--s-7); padding: var(--s-6); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }


/* ---------- 12. Estándares ---------- */

.std-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(272px,100%), 1fr)); gap: var(--gutter); }
.std-card { display: grid; gap: var(--s-3); align-content: start; min-width: 0; padding: var(--s-5); border: 1px solid var(--line-strong); border-radius: var(--r-md); background: var(--surface); transition: border-color var(--t-2) var(--e-out); }
.std-card:is(:hover,:focus-within) { border-color: var(--accent); }
.std-code { color: var(--accent-fg); font-family: var(--mono); font-size: var(--t-mono-s); font-variant-numeric: tabular-nums; letter-spacing: var(--ls-ui); }
.std-card h3 { font-size: var(--t-h4); letter-spacing: var(--ls-ui); }
.std-card .std-meta { font-size: var(--t-h3); font-weight: var(--wght-h); letter-spacing: var(--ls-h3); font-variant-numeric: tabular-nums; }
.std-card p { color: var(--fg-muted); font-size: var(--t-body-s); line-height: var(--lh-body); }
.std-card .std-how { padding-block-start: var(--s-3); border-block-start: 1px solid var(--line); color: var(--fg-muted); font-size: var(--t-caption); }
/* El carve-out encabeza la cláusula: se lee antes que los números. */
.std-carve { max-width: 72ch; margin-block-end: var(--s-7); padding: var(--s-5) var(--s-6); border-radius: var(--r-md); border-inline-start: 3px solid var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); color: var(--fg-2); line-height: var(--lh-body); }


/* ---------- 13. El Interruptor ---------- */

/* --p y --pn están registradas con inherits:false (§1). Sin este puente el
   valor que el JS escribe en la raíz de la pieza no llega a los hijos que lo
   consumen y el comparador se queda congelado en 50%. */
.toy-ba * { --p: inherit; --pn: inherit; }
.toy-ba { display: grid; gap: var(--s-4); margin: 0; }
/* El range vive DENTRO del stage (position:relative): como hermano, inset:0 se
   estiraría contra el bloque contenedor inicial y taparía el viewport (§6.2). */
.ba-stage { aspect-ratio: 16 / 10; isolation: isolate; touch-action: pan-y; }
.ba-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ba-b { clip-path: inset(0 0 0 var(--p)); }
.ba-tag { position: absolute; z-index: var(--z-raised); inset-block-start: var(--s-4); padding: var(--s-1) var(--s-3); border-radius: var(--r-full); background: var(--bg); color: var(--fg); font-size: var(--t-eyebrow); font-weight: var(--wght-ui); letter-spacing: var(--ls-eyebrow); text-transform: uppercase; }
/* Cristal de la casa sobre las fotos del comparador; el reposo sólido manda
   donde no hay backdrop-filter. */
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .ba-tag { background: var(--glass-bg); -webkit-backdrop-filter: var(--fx-glass); backdrop-filter: var(--fx-glass); }
}
/* Los rótulos se retiran cuando el divisor se les acerca. --pn es numérica:
   dividir entre un porcentaje no es CSS válido. */
.ba-tag-a { inset-inline-start: var(--s-4); opacity: clamp(0, calc((var(--pn) - .12) * 10), 1); }
.ba-tag-b { inset-inline-end: var(--s-4); opacity: clamp(0, calc((.88 - var(--pn)) * 10), 1); }
.ba-divider { position: absolute; z-index: var(--z-raised); inset-block: 0; inset-inline-start: var(--p); width: 2px; margin-inline-start: -1px; background: var(--accent); pointer-events: none; }
.ba-divider i { position: absolute; inset: 50% auto auto 50%; translate: -50% -50%; width: 52px; height: 52px; border-radius: var(--r-full); background: var(--accent); box-shadow: var(--sh-pk); }
/* Dos cuñas que dicen "esto se arrastra". Sin emoji y sin icono externo. */
.ba-divider i::before, .ba-divider i::after { content: ''; position: absolute; inset-block-start: 50%; width: 9px; height: 9px; border-block-start: 2px solid var(--on-accent); border-inline-start: 2px solid var(--on-accent); translate: 0 -50%; }
.ba-divider i::before { inset-inline-start: 14px; rotate: -45deg; }
.ba-divider i::after { inset-inline-end: 14px; rotate: 135deg; }
/* El control real es un range nativo: arrastre, teclado y touch salen gratis.
   touch-action: pan-y o la pieza secuestra el scroll vertical en móvil. */
.ba-range { position: absolute; z-index: var(--z-nav-local); inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; cursor: ew-resize; touch-action: pan-y; appearance: none; background: transparent; }
/* El foco del range es invisible por definición: lo dibuja el escenario. */
.ba-stage:has(.ba-range:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
.toy-ba figcaption { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-4); color: var(--fg-muted); font-size: var(--t-body-s); }
.toy-ba[data-state="error"] :is(.ba-divider,.ba-range,.ba-tag) { display: none; }
.toy-ba[data-state="error"] .ba-b { clip-path: none; }
@media (max-width: 640px) { .ba-stage { aspect-ratio: 4 / 5; } .ba-divider i { width: 64px; height: 64px; } }
/* Sin JS las dos imágenes se apilan con sus rótulos: se pierde la comparación,
   no la información. El convenio es html:not(.js); la clase .no-js no existe. */
html:not(.js) .ba-stage { display: grid; gap: var(--s-3); aspect-ratio: auto; overflow: visible; background: none; }
html:not(.js) .ba-img { position: static; height: auto; clip-path: none; border-radius: var(--r-bubble); }
html:not(.js) .ba-tag { position: static; justify-self: start; opacity: 1; }
html:not(.js) .ba-a { order: 1; } html:not(.js) .ba-tag-a { order: 2; }
html:not(.js) .ba-b { order: 3; } html:not(.js) .ba-tag-b { order: 4; }
html:not(.js) :is(.ba-divider,.ba-range) { display: none; }


/* ---------- 14. La Báscula ---------- */

/* 228px daba cinco columnas a 1440 y el figcaption se quedaba con ~64 px:
   "0.000" salía cortado y "JavaScript de terceros" se desbordaba.             */
.perf-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(310px,100%), 1fr)); gap: var(--gutter); margin-block: var(--s-6); }
.gauge { display: grid; grid-template-columns: auto minmax(0,1fr); align-items: center; gap: var(--s-4); min-width: 0; margin: 0; padding: var(--s-5); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.gauge-svg { width: 92px; height: 92px; flex: none; }
.gauge-bg, .gauge-arc { fill: none; stroke-width: 8; stroke-linecap: round; }
.gauge-bg { stroke: var(--line-strong); }
.gauge-arc { stroke: var(--accent); transform: rotate(-90deg); transform-origin: 50% 50%; transition: stroke-dashoffset var(--t-7) var(--e-out), stroke var(--t-3) var(--e-out); }
/* El veredicto tiñe arco y palabra a la vez, y en reposo es neutro: nunca se
   pinta de verde un dato que todavía no se midió. */
.gauge[data-verdict="ok"] .gauge-arc { stroke: var(--ok); }
.gauge[data-verdict="wa"] .gauge-arc { stroke: var(--wa); }
.gauge[data-verdict="er"] .gauge-arc { stroke: var(--er); }
.gauge[data-verdict="na"] .gauge-arc { stroke: var(--line-ctl); }
.gauge figcaption { display: grid; gap: var(--s-1); min-width: 0; }
.gauge-num { font-family: var(--serif); font-size: var(--t-h2); font-weight: 400; font-synthesis: none; line-height: var(--lh-tight); letter-spacing: -.008em; }
.gauge-unit { color: var(--fg-muted); font-size: var(--t-body-s); font-weight: var(--wght-ui); }
.gauge-lbl { font-size: var(--t-body-s); font-weight: var(--wght-ui); }
.gauge-why { color: var(--fg-muted); font-size: var(--t-caption); line-height: var(--lh-body); }
.gauge-verdict { justify-self: start; padding: 3px var(--s-2); border-radius: var(--r-sm); background: var(--surface-2); color: var(--fg-muted); font-size: var(--t-caption); font-weight: var(--wght-ui); }
.gauge[data-verdict="ok"] .gauge-verdict { background: var(--ok-bg); color: var(--ok); }
.gauge[data-verdict="wa"] .gauge-verdict { background: var(--wa-bg); color: var(--wa); }
.gauge[data-verdict="er"] .gauge-verdict { background: var(--er-bg); color: var(--er); }
[data-mode="ink"] .gauge[data-verdict="ok"] :is(.gauge-arc) { stroke: var(--ok-ink); }
[data-mode="ink"] .gauge[data-verdict="wa"] :is(.gauge-arc) { stroke: var(--wa-ink); }
[data-mode="ink"] .gauge[data-verdict="er"] :is(.gauge-arc) { stroke: var(--er-ink); }
[data-mode="ink"] .gauge[data-verdict="ok"] .gauge-verdict { background: var(--ok-bg-ink); color: var(--ok-ink); }
[data-mode="ink"] .gauge[data-verdict="wa"] .gauge-verdict { background: var(--wa-bg-ink); color: var(--wa-ink); }
[data-mode="ink"] .gauge[data-verdict="er"] .gauge-verdict { background: var(--er-bg-ink); color: var(--er-ink); }
.perf-note, .perf-method { max-width: 72ch; color: var(--fg-muted); font-size: var(--t-body-s); }
.perf-method summary { padding-block: var(--s-3); color: var(--accent-fg); font-weight: var(--wght-ui); cursor: pointer; }
.perf-method code { font-family: var(--mono); font-size: var(--t-mono-s); }
/* La consola de red scrollea dentro de su propio contenedor. */
.perf-net { max-height: 46vh; max-inline-size: 100%; overflow: auto; overscroll-behavior: contain; border: 1px solid var(--line); border-radius: var(--r-md); }
.perf-net table { width: 100%; border-collapse: collapse; font-size: var(--t-caption); }
.perf-net :is(th,td) { padding: var(--s-2) var(--s-3); text-align: start; white-space: nowrap; border-block-start: 1px solid var(--line); font-variant-numeric: tabular-nums; }
.perf-net th { color: var(--fg-muted); font-weight: var(--wght-ui); }
@media (min-width: 1024px) { .gauge-svg { width: 120px; height: 120px; } }


/* ---------- 15. La Mesa de Tokens ---------- */

.tokens-grid { display: grid; gap: var(--s-6); align-items: start; }
.tokens-grid > * { min-width: 0; }
.tokens-ctl { display: grid; gap: var(--s-5); }
.tk-field { display: grid; gap: var(--s-2); }
.tk-field > label { font-size: var(--t-ui); font-weight: var(--wght-ui); }
.tk-field output { color: var(--accent-fg); font-variant-numeric: tabular-nums; }
.tk-color { display: flex; gap: var(--s-3); align-items: center; }
.tk-color input[type="color"] { inline-size: 56px; block-size: 44px; padding: 0; border: 1px solid var(--line-ctl); border-radius: var(--r-sm); background: transparent; cursor: pointer; }
.tk-color input[type="text"] { inline-size: 12ch; min-block-size: 44px; padding-inline: var(--s-3); border: 1px solid var(--line-ctl); border-radius: var(--r-sm); background: transparent; color: var(--fg); font-family: var(--mono); font-size: var(--t-mono-s); text-transform: uppercase; }
.tk-swatches { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.tk-swatches button { inline-size: 44px; block-size: 44px; border: 1px solid var(--line-ctl); border-radius: var(--r-full); background: var(--sw, var(--accent)); cursor: pointer; }
/* Los sliders de la mesa son controles nativos: accent-color los pinta con
   el acento de marca sin reimplementar la pista ni el pulgar. */
.toy-tokens input[type="range"] { inline-size: 100%; min-block-size: 44px; margin: 0; accent-color: var(--accent); cursor: pointer; }
.tk-row { display: flex; flex-wrap: wrap; gap: var(--s-4); }
.toy-tokens .switch { display: inline-flex; align-items: center; gap: var(--s-2); min-height: 44px; font-size: var(--t-ui); font-weight: var(--wght-ui); cursor: pointer; }
.toy-tokens .switch input { inline-size: 20px; block-size: 20px; accent-color: var(--accent); }
.tk-actions { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-4); align-items: center; }
.tk-warn { padding: var(--s-3) var(--s-4); border-radius: var(--r-sm); background: var(--wa-bg); }
[data-mode="ink"] .tk-warn { background: var(--wa-bg-ink); }
.tk-fallback { inline-size: 100%; padding: var(--s-3); border: 1px solid var(--line-ctl); border-radius: var(--r-sm); background: var(--surface-2); color: var(--fg); font-family: var(--mono); font-size: var(--t-mono-s); }
/* Chip flotante mientras el tema del visitante está aplicado al sitio. Sin él
   la función sería una trampa: siempre visible y siempre reversible. */
.tk-chip { position: fixed; z-index: var(--z-chip); inset: auto auto var(--s-4) 50%; translate: -50% 0; display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) var(--s-4); border-radius: var(--r-full); background: var(--fg); color: var(--bg); font-size: var(--t-caption); font-weight: var(--wght-ui); box-shadow: var(--sh-2); }
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .tk-chip { background: color-mix(in srgb, var(--fg) 86%, transparent); -webkit-backdrop-filter: var(--fx-glass); backdrop-filter: var(--fx-glass); }
}
/* El preview se construye sobre las variables que escribe la pieza, con el
   valor de marca como respaldo si el JS no llegó. */
.tokens-view { display: grid; gap: calc(var(--s-4) * var(--tk-space, 1)); padding: calc(var(--s-6) * var(--tk-space, 1)); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); max-inline-size: 100%; }
.tv-lockup { font-size: var(--t-h2); font-weight: var(--tk-wght, var(--wght-display)); line-height: var(--lh-tight); letter-spacing: var(--ls-h2); }
.tv-dot { color: var(--tk-accent, var(--accent)); }
.tv-h { font-size: var(--t-h3); font-weight: var(--tk-wght, var(--wght-h)); letter-spacing: var(--ls-h3); }
.tv-p { max-width: 46ch; color: var(--fg-2); font-size: var(--t-body-s); line-height: var(--lh-body); }
.tv-row { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; }
.tv-btn { display: inline-flex; align-items: center; min-height: 44px; padding-inline: var(--s-5); border-radius: var(--tk-radius, var(--r-full)); background: var(--tk-accent, var(--accent)); color: var(--on-accent); font-weight: var(--wght-ui); }
.tv-chip { display: inline-flex; align-items: center; min-height: 32px; padding-inline: var(--s-3); border: 1px solid var(--tk-accent, var(--accent)); border-radius: var(--tk-radius, var(--r-full)); color: var(--fg); font-size: var(--t-caption); font-weight: var(--wght-ui); }
.tv-card { display: grid; align-content: end; min-block-size: 120px; padding: calc(var(--s-4) * var(--tk-space, 1)); border: 1px solid var(--line-strong); border-radius: var(--tk-radius, var(--r-md)); background: var(--bg); }
.tv-card-t { font-weight: var(--tk-wght, var(--wght-ui)); }
@media (min-width: 900px) { .tokens-grid { grid-template-columns: minmax(0,.9fr) minmax(0,1.1fr); gap: var(--s-7); } }


/* ---------- 16. El Brief ---------- */

.brief { display: grid; gap: var(--s-6); align-items: start; }
.brief > * { min-width: 0; }
.brief-steps { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: 0; padding: 0; }
.brief-step { min-width: 0; margin: 0; padding: 0; border: 0; }
.brief-step legend { margin-block-end: var(--s-5); font-size: var(--t-h3); font-weight: var(--wght-h); letter-spacing: var(--ls-h3); }
.opt-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px,100%), 1fr)); gap: var(--s-3); }
.opt-grid[data-cols="1"] { grid-template-columns: minmax(0,1fr); }
.opt { display: grid; grid-template-columns: auto minmax(0,1fr); gap: var(--s-1) var(--s-3); align-items: start; padding: var(--s-4); border: 1px solid var(--line-strong); border-radius: var(--r-md); cursor: pointer; transition: border-color var(--t-2) var(--e-out), background-color var(--t-2) var(--e-out); }
.opt:hover { border-color: var(--fg); }
.opt input { grid-row: 1 / span 2; inline-size: 20px; block-size: 20px; margin: 0; accent-color: var(--accent); }
.opt:has(input:checked) { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.opt-t { font-weight: var(--wght-ui); }
.opt-d { color: var(--fg-muted); font-size: var(--t-body-s); line-height: var(--lh-body); }
.brief-hint { margin-block-start: var(--s-4); }
.brief-move { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-block-start: var(--s-6); }
/* Salida en vivo: contenido normal, nunca un panel entero con aria-live. */
.brief-out { display: grid; gap: var(--s-4); padding: var(--s-5); border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); }
.brief-sentence { font-size: var(--t-lead); line-height: var(--lh-lead); }
.brief-nums { display: grid; gap: var(--s-3); }
.brief-nums > div { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: var(--s-3); align-items: baseline; padding-block-end: var(--s-3); border-block-end: 1px solid var(--line); }
.brief-nums dt { color: var(--fg-muted); font-size: var(--t-body-s); }
.brief-nums dd { margin: 0; text-align: end; font-weight: var(--wght-ui); font-variant-numeric: tabular-nums; }
.brief-fases { display: grid; list-style: decimal; gap: var(--s-2); margin: 0; padding-inline-start: var(--s-5); }
.brief-fases li::marker { color: var(--accent); font-weight: var(--wght-ui); }
.brief-actions { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; }
.brief-legal { color: var(--fg-muted); font-size: var(--t-caption); line-height: var(--lh-body); }
@media (min-width: 1024px) {
  .brief { grid-template-columns: minmax(0,1.15fr) minmax(0,.85fr); gap: var(--s-7); }
  .brief-steps, .brief-body { grid-column: 1; }
  .brief-out { grid-column: 2; grid-row: 1 / span 2; position: sticky; inset-block-start: calc(var(--hd-h) + var(--s-5)); }
}


/* ---------- 18. Paso tinta → claro ---------- */

/* motion.css resuelve claro→tinta con la franja marcada data-mode="ink".
   El paso inverso NO se puede construir con .mode-fade:not([data-mode]): sin
   el atributo, --bg es el claro de la página y el gradiente sale blanco sobre
   blanco. La franja de salida lleva data-mode="ink" (para que --bg sea la
   tinta) más .salida, que sólo invierte la dirección.                         */
.mode-fade[data-mode="ink"].salida { background: linear-gradient(180deg, var(--bg), transparent); }


/* ---------- 19. 360px: nada se sale, nada secuestra el scroll ---------- */

@media (max-width: 420px) {
  .rail-panel { flex-basis: min(84vw, 320px); }
  .gauge { grid-template-columns: minmax(0,1fr); }
  .gauge-svg { width: 76px; height: 76px; }
  .brief-nums > div { grid-template-columns: minmax(0,1fr); }
  .brief-nums dd { text-align: start; }
  .stack-switch { flex-wrap: wrap; }
  .stack-switch label { flex: 1 0 auto; justify-content: center; }
}


/* ---------- 20bis. Capítulos cinematográficos (arte de credenciales) ----
   Los capítulos con arte editorial a página (el David, el astronauta, el
   retrato) y la ballena del cierre. La regla del arte es la de la casa:
   fotografía B/N, y el fucsia es quien habla.
   Duraciones ambientales: --t-nado y --t-flota, declaradas en los tokens. */

/* Contenedor de capítulo con arte a sangre. El clip corta parallax y zoom. */
.cine { position: relative; overflow: clip; }

/* Hashtag de esquina y rótulo vertical: los dos gestos del arte original. */
.cine-hash { position: absolute; z-index: var(--z-raised); top: var(--s-5); right: var(--pad); margin: 0; }
/* A la DERECHA: la canaleta izquierda queda limpia para el contenido. */
.cine-vert {
  position: absolute; z-index: var(--z-raised); right: calc(var(--pad) * .35); bottom: var(--s-8);
  writing-mode: vertical-rl; rotate: 180deg; margin: 0;
  font-size: var(--t-caption); font-weight: var(--wght-ui);
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase; color: var(--fg-muted);
}
@media (max-width: 900px) { .cine-vert { display: none; } }

/* -- Capítulo con arte lateral. El marco es la burbuja grande de la casa y
   trae el fondo de marca debajo: si el raster falta, el hueco se ve
   terminado (§7.3). El zoom de scroll vive en la imagen; el marco recorta.
   z-raised es obligatorio: el folio .cap-n es absoluto y sin él pintaría
   ENCIMA del texto (mismo convenio que .amz-in).                            */
.cap-split { position: relative; z-index: var(--z-raised); display: grid; gap: var(--s-7); align-items: center; }
.cap-split > * { min-width: 0; }
@media (min-width: 960px) {
  .cap-split { grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: clamp(var(--s-7), 6vw, var(--s-9)); }
  .cap-split.media-left > .cap-fig { order: -1; }
}
.cap-fig { margin: 0; }
.cap-media {
  position: relative; overflow: hidden; aspect-ratio: 4 / 5; border-radius: var(--r-bubble-lg);
  background-color: var(--pk-100);
  background-image: radial-gradient(var(--pk-300) 1px, transparent 1.3px),
                    linear-gradient(160deg, var(--pk-200) 0%, var(--pk-50) 58%, var(--surface) 100%);
  background-size: 8px 8px, auto;
  color: var(--fg); font-size: var(--t-caption);
}
[data-mode="ink"] .cap-media {
  background-color: var(--surface);
  background-image: radial-gradient(var(--pk-800) 1px, transparent 1.3px),
                    linear-gradient(160deg, var(--pk-900) 0%, var(--surface) 70%);
}
.cap-media img { width: 100%; height: 100%; object-fit: cover; filter: brightness(var(--img-bright)); }
.cap-fig figcaption { margin-block-start: var(--s-3); color: var(--fg-muted); font-size: var(--t-caption); }
/* -- Escena de misión (§03). La lámina del astronauta nace como cuadro al
   ~70% del ancho y el scroll la expande a sangre completa; la misión y la
   visión viven en los laterales que el cuadro deja libres. El REPOSO de
   todo es el estado final legible: sin scroll timelines (o con rm) la
   lámina ya está expandida y los textos son columnas normales — nada nace
   invisible. El video lo inserta motion.js (data-lazy-media, sólo ≥1024px);
   aquí únicamente se pinta. La expansión va por scale + border-radius:
   compositor y pintura, cero animación de layout.                          */
.mzn-pin { position: relative; }
.mzn-stage { position: relative; overflow: clip; }
.mzn-media { position: absolute; inset: 0; margin: 0; overflow: clip; transform-origin: 50% 50%; background: var(--surface); }
.mzn-media img, .mzn-media video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; filter: brightness(var(--img-bright));
}
/* Fondo interactivo: el folio 03, un cielo de estrellas leves, la bandera
   con el isotipo (video en loop), el durazno y el celular. Cada pieza
   deriva con el puntero: translate en PORCENTAJE = fracción de su propia
   caja, así cada una responde distinto sin JS nuevo. El vaivén ambiental
   vive en el wrapper .mzn-float: dos manos, cero pisotones.                */
.mzn-back { position: absolute; inset: 0; overflow: clip; }
.mzn-back::before {
  content: ''; position: absolute; inset: 0;
  background-image:
    radial-gradient(circle, color-mix(in srgb, var(--n-0) 55%, transparent) 1px, transparent 1.6px),
    radial-gradient(circle, color-mix(in srgb, var(--n-0) 30%, transparent) 1px, transparent 1.5px);
  background-size: 340px 260px, 210px 300px;
  background-position: 48px 72px, 130px 26px;
  opacity: .55;
}
.mzn-float { position: absolute; }
/* Reparto de esquinas: durazno arriba-izquierda, celular arriba-derecha,
   bandera abajo-derecha. La esquina baja-izquierda es de la misión (texto)
   y la canaleta izquierda al centro es del riel de capítulos.              */
.mzn-float-bandera { right: calc(var(--pad) * .8); bottom: 3%; width: clamp(180px, 18vw, 320px); animation: mzn-vaiven var(--t-flota) var(--e-inout) infinite alternate; }
.mzn-float-durazno { left: calc(var(--pad) * .4); top: 5%; width: clamp(110px, 11vw, 210px); animation: mzn-vaiven var(--t-nado) var(--e-inout) infinite alternate-reverse; }
.mzn-float-celular { right: calc(var(--pad) * .5); top: 6%; width: clamp(100px, 10vw, 180px); animation: mzn-vaiven var(--t-flota) var(--e-inout) infinite alternate; animation-delay: calc(-2 * var(--t-8)); }
@keyframes mzn-vaiven { from { translate: 0 -1.5%; } to { translate: 0 2.5%; } }

/* La bandera es video sobre negro: ojo de buey + máscara radial para que
   el clip se funda con la tinta de la sección sin necesitar alfa.          */
.mzn-bandera {
  position: relative; overflow: clip; aspect-ratio: 1 / 1; border-radius: var(--r-full);
  -webkit-mask-image: radial-gradient(closest-side, black 55%, transparent 94%);
  mask-image: radial-gradient(closest-side, black 55%, transparent 94%);
  translate: calc((var(--mx, 50%) - 50%) * -.08) calc((var(--my, 50%) - 50%) * -.08);
  transition: translate var(--t-6) var(--e-out);
}
.mzn-bandera img, .mzn-bandera video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.mzn-durazno {
  width: 100%; height: auto;
  filter: drop-shadow(0 24px 48px color-mix(in srgb, var(--pk-900) 45%, transparent));
  translate: calc((var(--mx, 50%) - 50%) * -.16) calc((var(--my, 50%) - 50%) * -.16);
  transition: translate var(--t-6) var(--e-out);
}
.mzn-celular {
  width: 100%; height: auto; rotate: -12deg;
  filter: drop-shadow(0 18px 40px color-mix(in srgb, var(--pk-900) 55%, transparent));
  translate: calc((var(--mx, 50%) - 50%) * .22) calc((var(--my, 50%) - 50%) * .22);
  transition: translate var(--t-6) var(--e-out);
}

/* Los textos. En móvil son bloques normales; en ancho, columnas ancladas a
   los bordes reales del viewport (por eso NO llevan .wrap).                */
.mzn-copy { display: grid; gap: var(--s-6); padding: var(--sec-y-tight) var(--pad); }
.mzn-txt { font-size: var(--t-body-s); color: var(--fg-2); }
.mzn-frase { max-width: var(--maxw-disp); }
.mzn-cap { font-size: var(--t-caption); color: var(--fg-2); }
.mzn-final { position: relative; padding: 0 var(--pad) var(--sec-y-tight); }
.mzn-hueco { display: none; }

@media (min-width: 960px) {
  .mzn-stage { position: sticky; top: 0; height: 100svh; }
  .mzn-flow { position: relative; z-index: var(--z-raised); margin-block-start: -100svh; }
  .mzn-copy {
    min-height: 100svh; padding-block: var(--s-7);
    grid-template-columns: minmax(150px, calc(19vw - var(--pad))) 1fr minmax(150px, calc(19vw - var(--pad)));
    grid-template-rows: 1fr auto;
  }
  /* El cuadro es el centro; los textos toman lo que él deja libre y lo que
     el riel de capítulos no reclama (la franja central izquierda es suya):
     la visión centrada en la canaleta derecha, la misión como TIRA
     horizontal en la banda inferior. El orden del DOM (misión → visión)
     no cambia: sólo la rejilla los reparte.                                */
  .mzn-col {
    grid-area: 2 / 1 / 3 / -1; align-self: end; justify-self: start;
    display: flex; align-items: flex-end; column-gap: var(--s-7); row-gap: var(--s-3); flex-wrap: wrap;
  }
  /* Al cruzar frente al riel de capítulos (≥1100), la tira le abre paso. */
  @media (min-width: 1100px) { .mzn-col:not(.mzn-col-b) { margin-inline-start: var(--s-7); } }
  .mzn-col .mzn-txt { max-width: 46ch; }
  /* La visión respira: nace en la canaleta derecha pero puede crecer sobre
     la zona central hasta un ancho de lectura cómodo, siempre anclada al
     borde derecho.                                                         */
  .mzn-col-b { grid-area: 1 / 2 / 2 / 4; align-self: center; justify-self: end; max-width: min(46ch, 38vw); }
  /* Al scrollear, los textos CRUZAN por encima de la lámina (el traje del
     astronauta es casi blanco): llevan la misma plaquita de tinta que el
     riel de capítulos usa para el problema idéntico. El vidrio es mejora;
     el fondo sólido de reposo es quien garantiza el contraste medido.      */
  .mzn-col, .mzn-col-b { background: var(--ink-950); border-radius: var(--r-bubble); padding: var(--s-5); box-shadow: var(--sh-inset); }
  @supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    .mzn-col, .mzn-col-b { background: var(--glass-ink); -webkit-backdrop-filter: var(--fx-glass); backdrop-filter: var(--fx-glass); }
  }
  .mzn-hueco { display: block; height: 78svh; }
  .mzn-final {
    min-height: 100svh; display: grid; align-content: end;
    padding-block-end: clamp(var(--s-8), 12svh, var(--s-10));
    background: linear-gradient(180deg, transparent 34%,
      color-mix(in srgb, var(--ink-950) 62%, transparent) 62%,
      color-mix(in srgb, var(--ink-950) 88%, transparent) 100%);
  }
}
/* Sin esto la lámina nace expandida (reposo = final). Con scroll timelines,
   el cuadro entra al 68% y crece hasta la sangre mientras el visitante baja. */
@supports (animation-timeline: view()) {
  @media (min-width: 960px) {
    html.js:not(.rm) .mzn-pin { view-timeline-name: --mzn; }
    html.js:not(.rm) .mzn-media { animation: mzn-crece var(--e-lin) both; animation-timeline: --mzn; animation-range: cover 36% cover 66%; }
    html.js:not(.rm) .mzn-back { animation: mzn-fondo var(--e-lin) both; animation-timeline: --mzn; animation-range: cover 46% cover 64%; }
  }
}
@keyframes mzn-crece {
  from { scale: .62; border-radius: calc(var(--r-xl) * 1.8) calc(var(--r-xl) * 1.8) calc(var(--r-xl) * 1.8) var(--r-md); }
  to { scale: 1; border-radius: 0; }
}
@keyframes mzn-fondo { from { opacity: 1; } to { opacity: 0; } }

/* En móvil la escena es la lámina misma: sin fondo flotante ni coreografía. */
@media (max-width: 959px) {
  .mzn-stage { aspect-ratio: 16 / 10; }
  .mzn-back { display: none; }
}
/* ≥1100 existe el riel de capítulos: la placa final le abre paso. */
@media (min-width: 1100px) {
  html.js .mzn-final { padding-inline-start: calc(var(--pad) + var(--s-8)); }
}

/* -- La sala del David (§02). Un travelling de entrada en tres tiempos: el
   cuadro (la lámina clipeada a la derecha del manifiesto, con su ficha de
   museo), la apertura (el clip cede hasta la sangre y la cámara empuja
   adentro) y la sala (la familia de objetos fucsia emerge escalonada
   alrededor del David). El REPOSO es el estado final abierto: sin scroll
   timelines o con rm la sala nace a sangre completa y los objetos ya están
   en su sitio — nada nace invisible. Todo viaja por clip-path (pintura) y
   scale/translate/opacity (compositor): cero animación de layout.          */
.dv-pin { position: relative; }
.dv-stage { position: relative; overflow: clip; }
/* El fondo del cuadro antes de que la sala lo devore: el folio 02 sobre la
   trama de puntos de la casa, en tinta (dv-fondo los funde al abrir).      */
.dv-back { position: absolute; inset: 0; }
.dv-back::before {
  content: ''; position: absolute; inset: 0;
  background-image: radial-gradient(color-mix(in srgb, var(--pk-800) 60%, transparent) 1px, transparent 1.3px);
  background-size: 8px 8px;
  opacity: .5;
}
.dv-media { position: absolute; inset: 0; margin: 0; overflow: clip; background: var(--surface); }
/* La escena lleva el viaje de cámara (translate + scale); el botón del
   pudor vive DENTRO para escalar con la lámina y no perderle el mármol.    */
.dv-escena { position: absolute; inset: 0; transform-origin: 50% 50%; }
.dv-lamina {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; filter: brightness(var(--img-bright));
}
/* El pudor: la gemela apenada entra en un corte rápido (e-snap, casi jump
   cut) y las dos láminas dan un respingo mínimo. El crossfade se queda con
   rm — es un cambio de estado que pidió la persona, no decoración.         */
.dv-lamina-pena { opacity: 0; transition: opacity var(--t-2) var(--e-snap); }
.dv-media.is-pena .dv-lamina-pena { opacity: 1; }
html:not(.rm) .dv-media.is-pena .dv-lamina { animation: dv-respingo var(--t-4) var(--e-snap); }
@keyframes dv-respingo {
  0% { rotate: 0deg; } 30% { rotate: .8deg; } 65% { rotate: -.5deg; } 100% { rotate: 0deg; }
}
/* La zona sobre el mármol más privado. Invisible, pero el cursor la delata
   (not-allowed: no deberías estar mirando ahí) y el foco la dibuja.        */
.dv-pudor {
  position: absolute; left: 41%; top: 40%; width: 18%; height: 26%;
  background: none; border: 0; padding: 0; cursor: not-allowed;
  border-radius: var(--r-full);
}
.dv-pudor:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 4px; }
/* El mirón. Sobre la lámina la flecha desaparece y en su lugar mira un
   sticker de ojos saltones que sigue al puntero: quien espía al David
   queda delatado. Se cuelga de --mx/--my (data-pointer-xy medido en
   .dv-stage: su caja ES el viewport mientras la sala está clavada, así
   el scroll no lo desfasa) y al rondar el pudor los ojos se abren de
   más con el golpe e-back — el respingo ya lo pone la lámina. Sólo
   puntero fino con JS y sin rm; al tacto o sin JS no existe y el pudor
   conserva su not-allowed de siempre.                                      */
/* Van CORRIDOS abajo-derecha del puntero, no centrados en él: ahí vive el
   triángulo del cursor propio y, encimados, los ojos se lo tragaban y se
   perdía la mira. Ahora acompañan.                                          */
.dv-ojos {
  position: absolute; left: var(--mx, 50%); top: var(--my, 50%);
  z-index: var(--z-raised); translate: 28px 22px;
  width: clamp(64px, 6.5vw, 104px); pointer-events: none;
  opacity: 0; scale: .55; rotate: 10deg;
  transition: opacity var(--t-2) var(--e-out),
    scale var(--t-3) var(--e-back), rotate var(--t-3) var(--e-back);
}
.dv-ojos img { display: block; width: 100%; height: auto; }
html.js.fine:not(.rm) .dv-media:hover ~ .dv-ojos { opacity: 1; scale: 1; rotate: 0deg; }
html.js.fine:not(.rm) .dv-media.is-pena ~ .dv-ojos { scale: 1.32; rotate: -8deg; }
/* Aquí no hace falta apagar la flecha a mano: el cursor propio del sitio ya la
   sustituye en todas partes (§cursor propio) y los ojos van encima de él.    */

/* ── CURSOR PROPIO ────────────────────────────────────────────────────────
   El puntero del SITIO entero: en cualquier página y sobre cualquier apartado
   la flecha del sistema se retira y en su lugar va este triángulo, siempre el
   mismo — no cambia de cara según dónde estés. Un solo nodo fijo al viewport
   que monta motion.js (§cursor) y al que le escribe --cx/--cy en coords de
   puntero, así no hay un solo getBoundingClientRect por frame ni desfase con
   el scroll. Puntero fino, con JS y sin rm; en cualquier otro caso ni existe y
   la flecha nativa manda. Sobre el David (§02) el triángulo sigue siendo el
   puntero y sus ojos saltones siguen brotando encima: son la reacción de la
   imagen al hover, no un cursor aparte.                                      */
/* Va suelto a nivel de <body>, no anidado, porque se pinta con
   mix-blend-mode:difference y tiene que mezclarse contra la PÁGINA; dentro de
   un wrapper transformado se mezclaría contra el wrapper (transparente) y no
   invertiría nada. El estado —posición --cx/--cy y las clases cur-— vive en
   <html> y él lo lee.                                                        */
/* El triángulo ES el cursor: su punta (arriba-izquierda) marca dónde apuntas.
   Blanco + difference = el color EXACTO opuesto al fondo que tenga debajo
   (negro sobre claro, blanco sobre tinta, verde-lima sobre fucsia…): siempre
   contrasta, sin trazo que lo despegue. Con cuerpo suficiente para no perderse
   sobre las láminas cargadas: ~1.7× la flecha del sistema.                   */
.cursor-tip {
  position: fixed; left: 0; top: 0; z-index: var(--z-loader);
  pointer-events: none; visibility: hidden;
  translate: calc(var(--cx, -50vw) - 2px) calc(var(--cy, -50vh) - 2px);
  width: clamp(22px, 1.7vw, 28px); height: auto; max-width: none;
  color: var(--n-0); mix-blend-mode: difference;
  /* La punta vive en el 10% de la caja: escalar desde ahí la deja clavada
     donde apuntas en vez de arrastrarla al crecer.                          */
  transform-origin: 10% 10%;
  transition: scale var(--t-2) var(--e-back);
}
.cursor-tip path {
  fill: currentColor; stroke: currentColor; stroke-width: 1;
  stroke-linejoin: round; paint-order: stroke;
}
html.cur-on .cursor-tip { visibility: visible; }
/* Sobre algo cliqueable crece un poco; al presionar se aprieta. Único gesto
   que le queda: la mira no salta ni gira.                                    */
html.cur-on.cur-click .cursor-tip { scale: 1.22; }
html.cur-on.cur-press .cursor-tip { scale: .86; }
/* La flecha nativa se retira en TODA la página mientras el triángulo esté
   puesto (cur-on lo pone motion.js al primer movimiento de ratón y lo quita al
   salir de la ventana, con rm o al tacto): así nunca hay hueco sin puntero, y
   en cuanto el cursor propio se apaga vuelve la flecha del sistema. El
   selector incluye a * para ganarle a los cursores locales —ew-resize del
   comparador, not-allowed del pudor, el text de los campos—: puntero único,
   sin excepciones.                                                           */
html.js.fine:not(.rm).cur-on, html.js.fine:not(.rm).cur-on * { cursor: none; }

/* La ficha de museo del cuadro. Sus dos lecturas se apilan en la misma
   celda y la pena las conmuta; glass con respaldo sólido, como el riel.    */
.dv-ficha {
  position: absolute; right: 8%; bottom: 14%; z-index: var(--z-raised);
  display: grid; max-width: 36ch;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-bubble);
  background: var(--ink-950); box-shadow: var(--sh-inset);
  font-size: var(--t-caption); color: var(--fg-2); text-wrap: balance;
}
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .dv-ficha { background: var(--glass-ink); -webkit-backdrop-filter: var(--fx-glass); backdrop-filter: var(--fx-glass); }
}
.dv-ficha > span { grid-area: 1 / 1; transition: opacity var(--t-3) var(--e-out); }
.dv-ficha-b { opacity: 0; }
.dv-media.is-pena .dv-ficha-a { opacity: 0; }
.dv-media.is-pena .dv-ficha-b { opacity: 1; }
/* Los textos ruedan POR ENCIMA de la sala (mzn dixit), pero esta sala se
   toca: el flow deja pasar el puntero y sólo los bloques de contenido lo
   recuperan — el cuadro, el pudor y los objetos siguen vivos en el viaje.  */
.dv-flow { position: relative; z-index: var(--z-raised); pointer-events: none; }
.dv-flow .flow { pointer-events: auto; }
.dv-copy { display: grid; align-content: center; padding: var(--sec-y-tight) var(--pad); }
.dv-titulo { max-width: var(--maxw-disp); }
.dv-verso { max-width: 42ch; font-size: var(--t-h3); line-height: var(--lh-lead); color: var(--fg-2); }
.dv-tri { max-width: 46ch; font-size: var(--t-h4); line-height: var(--lh-lead); color: var(--fg-2); }
.dv-tri b { color: var(--fg); font-weight: var(--wght-h3); }
.dv-frase { max-width: var(--maxw-disp); }
.dv-cap { font-size: var(--t-caption); color: var(--fg-muted); }
.dv-hueco { display: none; }
.dv-final { position: relative; padding: 0 var(--pad) var(--sec-y-tight); }

@media (min-width: 960px) {
  .dv-stage { position: sticky; top: 0; height: 100svh; }
  .dv-flow { margin-block-start: -100svh; }
  .dv-copy { min-height: 100svh; }
  .dv-copy .flow { max-width: min(46vw, 58ch); }
  .dv-final .flow { max-width: 56ch; }
  .dv-hueco { display: block; height: 130svh; }
  .dv-final {
    min-height: 100svh; display: grid; align-content: end;
    padding-block-end: clamp(var(--s-8), 12svh, var(--s-10));
  }
  /* El oscurecimiento de la placa final vive EN la sala sticky, no en el
     bloque de texto que sube — un fondo en el bloque se vería VIAJAR sobre
     la escena. Aquí se funde en su sitio (dv-oscurece, más abajo): un scrim
     lateral apaga el mármol claro donde la frase en display lo cruza, y el
     de piso asienta la placa. Reposo: encendido — la placa siempre lee.    */
  .dv-stage::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background:
      linear-gradient(94deg, color-mix(in srgb, var(--ink-950) 72%, transparent) 0%,
        color-mix(in srgb, var(--ink-950) 46%, transparent) 36%, transparent 62%),
      linear-gradient(180deg, transparent 40%,
        color-mix(in srgb, var(--ink-950) 55%, transparent) 74%,
        color-mix(in srgb, var(--ink-950) 84%, transparent) 100%);
  }
}
/* Sin esto la sala nace abierta (reposo = final). Con scroll timelines el
   cuadro cuelga a la derecha del manifiesto (clip con esquina de burbuja)
   y la lámina viaja corrida para asomar al David por esa ventana; el
   scroll abre el clip, endereza el viaje y EMPUJA la cámara adentro; los
   objetos emergen escalonados —grandes y encima, como si nos rebasaran—
   cuando ya estamos dentro de la sala.                                     */
@supports (animation-timeline: view()) {
  @media (min-width: 960px) {
    html.js:not(.rm) .dv-pin { view-timeline-name: --dv; }
    /* El reposo al pie de la sección queda en cover ~77% (el pin mide
       ~3.3vh): todos los rangos CIERRAN antes de 74% para que nada se
       quede a medio emerger cuando el visitante lee la placa final.        */
    html.js:not(.rm) .dv-media { animation: dv-abre var(--e-lin) both; animation-timeline: --dv; animation-range: cover 28% cover 52%; }
    html.js:not(.rm) .dv-escena { animation: dv-viaja var(--e-lin) both; animation-timeline: --dv; animation-range: cover 28% cover 74%; }
    html.js:not(.rm) .dv-back { animation: dv-fondo var(--e-lin) both; animation-timeline: --dv; animation-range: cover 38% cover 52%; }
    html.js:not(.rm) .dv-stage::after { animation: dv-oscurece var(--e-lin) both; animation-timeline: --dv; animation-range: cover 54% cover 70%; }
  }
}
@keyframes dv-abre {
  from { clip-path: inset(12% 6% 12% 54% round var(--r-bubble-lg)); }
  to { clip-path: inset(0 round 0); }
}
/* El 3% vertical del arranque le da aire a la cabeza dentro del cuadro.    */
@keyframes dv-viaja {
  from { translate: 24% 3%; scale: 1; }
  to { translate: 0 0; scale: 1.14; }
}
@keyframes dv-fondo { from { opacity: 1; } to { opacity: 0; } }
@keyframes dv-oscurece { from { opacity: 0; } to { opacity: 1; } }

/* En corto la sala ES la lámina: cuadro vertical (recorte central de la
   panorámica), sin oscurecer — la placa final va aparte en el flujo; el
   pudor y la ficha siguen vivos, con zona de dedo generosa.                */
@media (max-width: 959px) {
  .dv-stage { aspect-ratio: 4 / 5; }
  .dv-back { display: none; }
  .dv-ficha { left: var(--s-4); right: var(--s-4); bottom: var(--s-4); max-width: none; }
  .dv-pudor { left: 32%; top: 38%; width: 36%; height: 28%; }
}
/* ≥1100 existe el riel de capítulos: el copy y la placa le abren paso.     */
@media (min-width: 1100px) {
  html.js .dv-copy, html.js .dv-final { padding-inline-start: calc(var(--pad) + var(--s-8)); }
}
/* -- Valores: lista editorial. El nombre en la voz serif, el porqué al lado. */
.val-list { border-block-start: 1px solid var(--line); }
.val-list li { display: grid; gap: var(--s-1) var(--s-5); padding-block: var(--s-4); border-block-end: 1px solid var(--line); }
@media (min-width: 640px) { .val-list li { grid-template-columns: minmax(12ch, .5fr) minmax(0, 1fr); align-items: baseline; } }
.val-t { font-family: var(--serif); font-weight: 400; font-synthesis: none; font-size: calc(var(--t-h3) * 1.1); letter-spacing: -.006em; }
.val-d { color: var(--fg-muted); font-size: var(--t-body-s); line-height: var(--lh-body); }
.val-list li .dot { display: inline-block; transform-origin: 50% 85%; transition: transform var(--t-3) var(--e-back); }
.val-list li:hover .dot { transform: scale(1.35); }
/* La fila despierta entera: una barra de acento crece en el margen, el nombre
   se corre un paso y el porqué recupera tinta. Nada cambia de sitio.          */
.val-list li { position: relative; }
.val-list li::before {
  content: ''; position: absolute; inset-block: var(--s-4); inset-inline-start: calc(var(--s-4) * -1);
  width: 2px; border-radius: var(--r-full); background: var(--accent);
  transform-origin: 50% 0; scale: 1 0; transition: scale var(--t-3) var(--e-out);
}
.val-list li:hover::before { scale: 1 1; }
.val-list .val-t { transition: translate var(--t-3) var(--e-out); }
.val-list li:hover .val-t { translate: var(--m-1) 0; }
.val-list .val-d { transition: color var(--t-2) var(--e-out); }
.val-list li:hover .val-d { color: var(--fg-2); }

/* -- El cierre: la ballena sobre el desierto. data-mode="ink" pone los
   tokens claros; la foto y el velo ponen el fondo. El velo existe por
   1.4.3: blanco directo sobre nube rosa mide ~2:1, con el velo pasa AA. */
.amz { display: grid; align-content: end; min-height: min(100svh, 960px); }
.amz-bg { position: absolute; inset: 0; margin: 0; }
.amz-bg img { width: 100%; height: 100%; object-fit: cover; }
.amz::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--ink-950) 22%, transparent) 0%,
    transparent 32%, transparent 46%,
    color-mix(in srgb, var(--ink-950) 74%, transparent) 90%);
}
/* La ballena nada por encima del velo: el arte se queda brillante y el
   texto, más abajo, ya tiene su fondo garantizado. */
.amz-ballena {
  position: absolute; z-index: var(--z-raised); top: clamp(var(--s-7), 11vh, 140px); left: 50%;
  width: min(56vw, 720px); height: auto; translate: -44% 0;
  filter: drop-shadow(0 40px 80px color-mix(in srgb, var(--pk-900) 45%, transparent));
  animation: amz-nada var(--t-nado) var(--e-inout) infinite alternate;
}
@keyframes amz-nada {
  from { transform: translateY(-1.5%) rotate(-2.2deg); }
  to   { transform: translateY(2.5%) rotate(1.4deg); }
}
.amz-in {
  position: relative; z-index: var(--z-raised); display: grid; gap: var(--s-4);
  justify-items: start; padding-block: clamp(280px, 46svh, 520px) var(--s-8);
}
@media (max-width: 700px) { .amz-ballena { width: 84vw; translate: -50% 0; } }
/* En pantallas bajas la aleta alcanzaba la primera línea del titular: la
   ballena cede tamaño antes que el texto ceda contraste. */
@media (min-width: 701px) and (max-height: 780px) { .amz-ballena { width: min(40vw, 520px); } }

/* El B/N editorial de .duo (speach.css §retratos) perdía contra el
   brightness del marco (§0: mismo peso 0,1,1 y este archivo carga después).
   Se restituye con un peso mayor: retrato en gris, color al hover/foco. */
.team-ph.duo > img, .cap-media.duo > img {
  filter: grayscale(1) contrast(1.06) brightness(calc(var(--img-bright) * 1.03));
}
:is(.team-ph, .cap-media).duo:is(:hover, :focus-within) > img { filter: brightness(var(--img-bright)); }
@media (hover: none) { :is(.team-ph, .cap-media).duo > img { filter: brightness(var(--img-bright)); } }


/* ---------- 21. Contacto: la página que contesta ---------- */

/* El encabezado abierto lleva la burbuja de trama del hero del home: la
   misma textura, en el mismo rincón. */
.cu-head::before {
  content: ''; position: absolute; z-index: 0; inset: calc(var(--s-6) * -1) calc(var(--pad) * -.4) auto auto;
  width: min(42vw, 460px); aspect-ratio: 1; border-radius: var(--r-bubble-lg);
  background-image: radial-gradient(var(--pk-200) 1px, transparent 1.4px); background-size: 14px 14px;
  mask-image: radial-gradient(70% 70% at 70% 30%, currentColor, transparent); pointer-events: none;
}

/* El correo-héroe: el dato más importante de la página, en voz de display.
   .big-mail ya trae el subrayado de acento (speach.css); aquí sólo crece. */
.cu-mail { display: grid; gap: var(--s-3); justify-items: start; }
.cu-mail .big-mail { font-size: clamp(1.75rem, 4.6vw, 3.4rem); overflow-wrap: anywhere; text-align: start; }
.cu-mail .caption { color: var(--fg-muted); }

/* Quien contesta: retratos B/N solapados que recuperan color al hover (la
   firma .duo de la casa) y se asoman uno a uno. */
.cu-humans { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3) var(--s-4); }
.cu-humans .body-s { max-width: 52ch; color: var(--fg-2); }
.cu-faces { display: flex; margin: 0; padding: 0; list-style: none; }
.cu-faces li {
  position: relative; width: 52px; height: 52px; flex: none;
  margin-inline-start: calc(var(--s-3) * -1);
  border-radius: var(--r-full); overflow: hidden;
  border: 2px solid var(--bg); background: var(--pk-100);
  transition: translate var(--t-3) var(--e-back);
}
.cu-faces li:first-child { margin-inline-start: 0; }
.cu-faces img {
  width: 100%; height: 100%; object-fit: cover; scale: 1.09;
  filter: grayscale(1) contrast(1.06) brightness(calc(var(--img-bright) * 1.03));
  transition: filter var(--t-3) var(--e-out);
}
.cu-humans:hover .cu-faces img, .cu-faces li:hover img { filter: brightness(var(--img-bright)); }
.cu-faces li:hover { translate: 0 -4px; z-index: var(--z-raised); }
@media (hover: none) { .cu-faces img { filter: brightness(var(--img-bright)); } }

/* El latido de «te contesta una persona»: el punto de la marca respirando. */
.cu-live {
  display: inline-block; width: 8px; height: 8px; margin-inline-end: var(--s-2);
  border-radius: var(--r-full); background: var(--accent);
  animation: cu-late calc(var(--t-8) * 1.75) var(--e-inout) infinite;
}
@keyframes cu-late { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.45); } }

/* El directorio: puertas editoriales. El filete gris se reescribe en acento
   de izquierda a derecha y el título se corre un paso (gesto .qs-num). */
/* 320px de piso: con seis puertas la retícula cae en 3+3, nunca en 4+2.      */
.cu-doors { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px,100%), 1fr)); gap: var(--s-6) var(--s-7); }
.cu-door {
  position: relative; overflow: clip; display: grid; gap: var(--s-2); align-content: start;
  padding-block-start: var(--s-4); border-block-start: 1px solid var(--line);
}
.cu-door::after {
  content: ''; position: absolute; inset: 0 0 auto; height: 2px;
  background: var(--accent); transform-origin: 0 50%; scale: 0 1;
  transition: scale var(--t-4) var(--e-expo);
}
.cu-door:is(:hover,:focus-within)::after { scale: 1 1; }
.cu-door h3 { transition: translate var(--t-3) var(--e-out); }
.cu-door:is(:hover,:focus-within) h3 { translate: var(--m-1) 0; }
.cu-door .body-s { color: var(--fg-muted); line-height: var(--lh-body); }

/* El formulario a dos columnas donde cabe: se LEE corto porque lo es. */
.cu-fgrid { display: grid; gap: 0 var(--s-6); }
@media (min-width: 720px) {
  .cu-fgrid { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .cu-fgrid .cu-wide { grid-column: 1 / -1; }
}


/* ---------- 20ter. Movimiento reducido de los capítulos ---------- */
@media (prefers-reduced-motion: reduce) {
  .amz-ballena { animation: none; }
  .val-list li .dot { transition: none; }
  .cu-live { animation: none; }
  .cu-door::after, .cu-faces li { transition: none; }
  .cu-door:is(:hover,:focus-within) h3, .cu-faces li:hover { translate: none; }
}
html.rm .amz-ballena { animation: none; }
html.rm .cu-live { animation: none; }
html.rm .cu-faces li:hover { translate: none; }


/* ---------- 19bis. Galería de caso: el material real ---------- */

/* Carril horizontal con scroll propio. Cada pieza mide por ALTURA (--gal-h)
   y su formato pone el ancho: story 9/16, post cuadrado 1/1, film 16/9.
   El material es el protagonista: el carril no recorta, se recorre. */
.gal { --gal-h: clamp(250px, 34vw, 400px); }
.gal-track {
  display: flex; gap: var(--s-4); overflow-x: auto; overscroll-behavior-x: contain;
  padding-block: var(--s-2) var(--s-4);
  scroll-snap-type: x proximity; scrollbar-width: thin;
  scrollbar-color: var(--pk-300) transparent;
}
.gal-t {
  position: relative; overflow: hidden; flex: 0 0 auto; height: var(--gal-h);
  margin: 0; border-radius: var(--r-bubble); scroll-snap-align: start;
  background-color: var(--pk-100);
  background-image: radial-gradient(var(--pk-300) 1px, transparent 1.3px),
                    linear-gradient(160deg, var(--pk-200) 0%, var(--pk-50) 58%, var(--surface) 100%);
  background-size: 8px 8px, auto;
  color: var(--fg); font-size: var(--t-caption);
  transition: translate var(--t-3) var(--e-out), box-shadow var(--t-3) var(--e-out);
}
[data-mode="ink"] .gal-t {
  background-color: var(--surface);
  background-image: radial-gradient(var(--pk-800) 1px, transparent 1.3px),
                    linear-gradient(160deg, var(--pk-900) 0%, var(--surface) 70%);
}
.gal-t.v { aspect-ratio: 9 / 16; }
.gal-t.s { aspect-ratio: 1 / 1; }
.gal-t.w { aspect-ratio: 16 / 9; }
.gal-t > :is(img, video) {
  width: 100%; height: 100%; object-fit: cover; filter: brightness(var(--img-bright));
  transition: scale var(--t-4) var(--e-out);
}
.gal-t:hover { translate: 0 -6px; box-shadow: var(--sh-2); }
.gal-t:hover > :is(img, video) { scale: var(--s-zoom); }
.gal-t:has(video) { cursor: pointer; }
.gal-t.is-playing { box-shadow: 0 0 0 2px var(--accent), var(--sh-2); }

/* El botón de play: el punto fucsia de la marca, con triángulo de tinta. */
.gal-play {
  position: absolute; inset: 0; margin: auto; z-index: var(--z-raised);
  display: grid; place-items: center; width: 54px; height: 54px; padding: 0;
  border: 0; border-radius: var(--r-full); cursor: pointer;
  background: var(--accent); color: var(--on-accent); font-size: var(--t-body);
  box-shadow: var(--sh-2);
  transition: scale var(--t-2) var(--e-back), opacity var(--t-2) var(--e-out);
}
.gal-play:hover { scale: var(--s-pop); }
/* Mientras suena, el botón se retira; vuelve con el puntero o el foco. */
.gal-t.is-playing .gal-play { opacity: 0; }
.gal-t.is-playing:is(:hover, :focus-within) .gal-play { opacity: 1; }
.gal-play:focus-visible { opacity: 1; }

/* Etiqueta de formato: plaquita de vidrio abajo a la izquierda. */
.gal-tag {
  position: absolute; left: var(--s-3); bottom: var(--s-3); z-index: var(--z-raised);
  padding: var(--s-1) var(--s-3); border-radius: var(--r-full);
  background: var(--glass-ink); color: var(--n-0);
  font-size: var(--t-caption); font-weight: var(--wght-ui); letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase; pointer-events: none;
}
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .gal-tag { -webkit-backdrop-filter: var(--fx-glass); backdrop-filter: var(--fx-glass); }
}
.gal-t.is-playing .gal-tag { background: var(--accent); color: var(--on-accent); }

/* ---------- 19ter. Muro de clientes: las firmas que han confiado ---------- */

/* Reusa el motor del marquee (motion.js §8). Los logos son tinta sobre papel:
   este muro NO se usa en secciones [data-mode="ink"]. */
.wall-row { display: inline-flex; align-items: center; white-space: nowrap; }
.wall-row img {
  height: clamp(30px, 3.4vw, 44px); width: auto; max-width: none;
  margin-inline: clamp(22px, 3vw, 48px);
  opacity: .68; transition: opacity var(--t-2) var(--e-out);
}
.wall-row img:hover { opacity: 1; }
.wall + .wall { margin-block-start: var(--s-5); }


/* ---------- 20. Movimiento reducido ---------- */

/* No es "sitio muerto": se conservan color y opacidad, se van los
   desplazamientos. La funcionalidad de cada pieza queda intacta (§8.5·17). */
@media (prefers-reduced-motion: reduce) {
  .svc-row:is(:hover,:focus-within), .svc-row:is(:hover,:focus-within) .svc-i { transform: none; }
  .dot, .cifra-mas::after, .faq summary::after { transition: none; }
  .gauge-arc { transition: stroke var(--t-2) var(--e-lin); }
  /* Los estados de hover se conservan (color y presencia), se van los viajes:
     la cortina aparece sin barrer, las barras sin crecer, nada se desplaza.   */
  .svc-index .svc-row::before, .svc-n, .qs-num::after, .val-list li::before { transition: none; }
  .qs-num:hover b, .val-list li:hover .val-t { translate: none; }
  .cap-media[data-pointer-xy]::after { transition: none; }
  /* Galería: se van los viajes, quedan el anillo de reproducción y el foco. */
  .gal-t, .gal-t > :is(img, video), .gal-play { transition: none; }
  .gal-t:hover { translate: none; }
  .gal-t:hover > :is(img, video) { scale: none; }
  .gal-play:hover { scale: none; }
}
html.rm .gal-t:hover { translate: none; box-shadow: none; }
html.rm .gal-t.is-playing { box-shadow: 0 0 0 2px var(--accent); }
html.rm .gal-t:hover > :is(img, video) { scale: none; }


/* ---------- 21. La carretera: el interludio de la persecución ---------- */

/* Tres planos en video loop apilados en un escenario clavado; el scroll los
   monta como una sola toma continua: la carretera, el coche, la cabina. El
   reposo de la escena es la cabina —el último plano del DOM gana el
   apilado—, así que sin timelines, sin JS o con rm el capítulo se ve
   completo: nada nace invisible. Los supers y la coreografía sólo existen
   donde hay motor que los sostenga.                                        */
.rta-pin { position: relative; }
.rta-stage { position: relative; overflow: clip; background: var(--ink-950); aspect-ratio: 16 / 10; }
.rta-plano { position: absolute; inset: 0; margin: 0; }
.rta-plano :is(img, video) { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Los dos búferes del loop sin costura (data-xfade, motion.js): nacen
   apagados sobre el poster y sólo el activo se enciende; el relevo es un
   fundido cruzado que tapa el aterrizaje del clip saliente.               */
.rta-plano video { opacity: 0; transition: opacity var(--t-4) var(--e-lin); }
.rta-plano video.vx-on { opacity: 1; }

/* El lienzo del grabado reproduce la geometría de object-fit:cover (16:9
   centrado que nunca baja de la caja): sus posiciones en % son coordenadas
   del cuadro del video en cualquier viewport. Los objetos de la cabina
   —colgante del logotipo, charms del tablero— viven DENTRO del video.      */
.rta-cabina {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  aspect-ratio: 16 / 9; min-width: 100%; min-height: 100%;
  pointer-events: none;
}

/* El grabado del espejo: la advertencia de retrovisor americano, dicha en
   marca. Respira apenas, como texto esmerilado sobre el parabrisas, y
   deriva una nada con el puntero para sentirse dentro del vidrio.          */
.rta-grabado {
  position: absolute; left: 29%; top: 27%; margin: 0;
  translate: calc(-50% + (var(--mx, 50%) - 50%) * .1) calc((var(--my, 50%) - 50%) * .05);
  font-size: var(--t-caption); text-transform: uppercase; letter-spacing: .3em;
  text-align: center; line-height: 2; color: var(--n-0); opacity: .5;
  text-shadow: 0 1px 18px color-mix(in srgb, var(--ink-950) 85%, transparent);
  animation: rta-alienta calc(3 * var(--t-8)) var(--e-inout) infinite alternate;
  transition: translate var(--t-6) var(--e-out);
}
@keyframes rta-alienta { from { opacity: .38; } to { opacity: .62; } }

/* Los supers de los dos primeros actos. Sólo existen con coreografía.      */
.rta-linea {
  display: none; position: absolute; left: 50%; top: 40%; translate: -50% -50%;
  margin: 0; width: min(86vw, 26ch);
  font-family: var(--serif); font-weight: 400; font-synthesis: none;
  font-size: calc(var(--t-h1) * 1.15); line-height: 1.05; letter-spacing: -.012em;
  text-align: center; text-wrap: balance; color: var(--n-0);
  text-shadow: 0 2px 28px color-mix(in srgb, var(--ink-950) 80%, transparent);
}

/* El cierre del interludio, patrón de la misión: el texto scrollea con su
   gradiente de lectura y el escenario queda clavado detrás.                */
.rta-hueco { display: none; }
.rta-final { position: relative; padding: var(--sec-y-tight) var(--pad); }
/* El flow tapa al escenario clavado: sin esto ni el dossier recibe hover ni
   el puntero alimenta --mx. El texto final recupera su puntero en el wrap. */
.rta-flow { pointer-events: none; }
.rta-final .wrap { pointer-events: auto; }

@media (max-width: 959px) {
  /* En móvil la escena es la cabina misma: un solo plano, sin persecución.
     El grabado no cabe en la viñeta: desborda sobre la lámina.             */
  .rta-lateral, .rta-grabado { display: none; }
}

@media (min-width: 960px) {
  .rta-stage { position: sticky; top: 0; height: 100svh; aspect-ratio: auto; }
  .rta-flow { position: relative; z-index: var(--z-raised); margin-block-start: -100svh; }
  .rta-final {
    min-height: 100svh; display: grid; align-content: end;
    padding: 0 var(--pad) var(--sec-y-tight);
    background: linear-gradient(180deg, transparent 34%,
      color-mix(in srgb, var(--ink-950) 62%, transparent) 62%,
      color-mix(in srgb, var(--ink-950) 88%, transparent) 100%);
  }
}

/* La coreografía: el pin presta su timeline y el scroll monta la toma. El
   plano lateral corre, acelera y se ZAMBULLE por la ventana del piloto (el
   transform-origin ES la ventana: el zoom entra por ahí), un parpadeo de
   tinta hace el paso a través de la carrocería y la cabina aterriza.       */
@supports (animation-timeline: view()) {
  @media (min-width: 960px) {
    html.js:not(.rm) .rta-pin { view-timeline-name: --rta; }
    html.js:not(.rm) .rta-hueco { display: block; height: 320svh; }
    html.js:not(.rm) .rta-lateral {
      display: block; transform-origin: 56% 45%;
      animation: rta-lateral-zambulle var(--e-lin) both; animation-timeline: --rta;
      animation-range: cover 0% cover 56%;
    }
    html.js:not(.rm) .rta-interior {
      animation: rta-entra var(--e-lin) both; animation-timeline: --rta;
      animation-range: cover 52% cover 76%;
    }
    html.js:not(.rm) .rta-stage::after {
      content: ''; position: absolute; inset: 0; background: var(--ink-950);
      opacity: 0; pointer-events: none;
      animation: rta-parpadeo var(--e-lin) both; animation-timeline: --rta;
      animation-range: cover 48% cover 60%;
    }
    html.js:not(.rm) .rta-cabina {
      animation: rta-cabina-llega var(--e-lin) both; animation-timeline: --rta;
      animation-range: cover 62% cover 76%;
    }
    html.js:not(.rm) .rta-linea {
      display: block;
      animation: rta-super var(--e-lin) both; animation-timeline: --rta;
    }
    html.js:not(.rm) .rta-l1 { animation-range: cover 10% cover 26%; }
    html.js:not(.rm) .rta-l2 { animation-range: cover 30% cover 46%; }
  }
}
@keyframes rta-lateral-zambulle {
  0% { opacity: 1; scale: 1; }
  55% { opacity: 1; scale: 1.1; }
  84% { opacity: 1; scale: 2.1; }
  100% { opacity: 0; scale: 3; }
}
@keyframes rta-entra {
  0% { opacity: 0; scale: 1.32; }
  30% { opacity: 1; scale: 1.22; }
  100% { opacity: 1; scale: 1; }
}
@keyframes rta-parpadeo {
  0% { opacity: 0; }
  45% { opacity: .92; }
  100% { opacity: 0; }
}
@keyframes rta-super {
  0% { opacity: 0; translate: -50% -46%; }
  22% { opacity: 1; translate: -50% -50%; }
  74% { opacity: 1; translate: -50% -50%; }
  100% { opacity: 0; translate: -50% -54%; }
}
@keyframes rta-cabina-llega {
  from { opacity: 0; translate: -50% -48%; }
  to { opacity: 1; translate: -50% -50%; }
}

/* Movimiento reducido: la escena queda en su cuadro final —la cabina— y
   los viajes se van; el grabado deja de respirar.                          */
@media (prefers-reduced-motion: reduce) { .rta-grabado { animation: none; } }
html.rm .rta-grabado { animation: none; }
