/* Hallmark · macrostructure: Split Studio · H6 hero: fotográfico a sangre, texto sin caja sobre velo
 * (era H2 «bloque de oro a la izquierda, figura a la derecha». Dejó de valer cuando el hero pasó a
 *  vídeo a sangre detrás de todo: el bloque era media composición y se convirtió en una pegatina.)
 * theme: custom · vibe: "cronometraje deportivo, marino, oro en bloque" · paper: #0F1F3A oklch(24% 0.056 260) · accent: #C8A44D oklch(73% 0.114 87)
 * display: Space Grotesk · body: IBM Plex Sans · outlier: IBM Plex Mono · axes: dark / geometric-sans / warm
 * nav: N9 edge-aligned, UNA sola barra (antes dos superpuestas) · footer: Ft1 mast-headed · secciones: F4 secuencia + F3 hoja de especificaciones · CTA: C1 chip perfilado
 * enrichment: none (las figuras son huecos declarados hasta que lleguen las fotos)
 * studied: no · context: explícito (referencia pedida: hyrox.com) · v0.9.0
 * v0.19.0 · «Del suelo a tu mesa» absorbe los tipos de salida y la sección
 *   «Salgan como salgan» desaparece. El render aéreo lleva ahora a los seis
 *   cruzando, manda el alto de la sección —nada por debajo de su pie— y se
 *   corre a la izquierda hasta que su contenido acaba antes del teléfono: la
 *   cuarta parte derecha del PNG es aire, así que ese desplazamiento casi no
 *   se lleva nada por delante. A la derecha, una pila: titular, aparatos, los
 *   tres tipos en icono y nombre, y las dos garantías en cifra. El texto largo
 *   se fue: lo que explica la sección es lo que se ve.
 * v0.18.0 · se arregla lo invisible. El escalonado tenía escrito sólo el
 *   camino del observador (`opacity: 0` + clase `encendido`), pero el JS se
 *   retira en cuanto el navegador soporta `animation-timeline`, así que en
 *   Chrome y Edge esas listas se quedaban en blanco. Ahora hay regla nativa
 *   con `view()` y la opacidad de base se limita a `.sin-linea-de-scroll`.
 * v0.17.0 · fuera la panorámica. La sección doble gana propósito declarado
 *   («Del suelo a tu mesa») y se reordena: las dos puntas del viaje —la vista
 *   aérea y el portátil con el teléfono— enfrentadas en la misma fila, y las
 *   dos garantías debajo, en banda compacta sin tarjeta.
 * v0.16.0 · orden de lectura para quien llega sin contexto: «Un arco. Todo lo
 *   que cruza» sube al segundo puesto porque es la que DEFINE el arco (antes se
 *   usaba la palabra tres secciones antes de explicarla), «Se planta donde haga
 *   falta» detrás, y fuera «La pulsera manda» — eran reglas de uso, no valor.
 * v0.15.0 · el criterio de escala se aplica a todos: contrapicado al 128 %
 *   sangrando por el canto derecho, pelotón al 124 %, teléfonos del relato de
 *   16 a 21 rem. Y los `sizes` sincerados: el del cenital declaraba 46vw para
 *   una pieza de 96vw, así que el navegador bajaba la variante de 960 px y la
 *   estiraba a 1638 — eso era lo que se veía «de baja calidad», no el codec.
 * v0.14.0 · la vista aérea a lo grande: 1680 px, cortada por el canto
 *   izquierdo y metiéndose en la sección de arriba, con las cifras por delante.
 * v0.13.0 · el hueco del cenital acoge las dos cifras (una sección menos), el
 *   portátil pasa de foto con mesa a marco vectorial con alfa y en
 *   perspectiva, y el clip de Blender (WebM con alfa) entra en «Se planta
 *   donde haga falta». Ningún render se recorta ya.
 * v0.12.0 · la PC en dos vistas cenitales (el arco desde el aire + la
 *   pantalla, solapadas en diagonal), y el carrusel de seis destacados se
 *   sustituye por «La pulsera manda»: cuatro de sus seis tarjetas repetían
 *   otras secciones, quedan las dos reglas propias sobre el contrapicado.
 * v0.11.0 · la app se cuenta a scroll (tres pantallas fijas por turno, sin JS),
 *   la sección del arco pasa de rejilla recortada a banda a sangre de cuatro
 *   planos con ritmo 2·1·1,4·1, y las disciplinas van en pastilla.
 * v0.10.0 · composiciones con los renders: el equipo a sangre (el objeto sale
 *   del cuadro y lo corta el borde), el pelotón cortado por abajo y el
 *   escaparate de la app — tres pantallas escalonadas con las piezas del
 *   propio sistema flotando en los huecos. Patrón nuevo: `figura-suelta`
 *   (render con alfa, sin caja, con sombra de apoyo).
 * v0.9.0 · barra única (fusionadas la global y la del producto), el avance de
 *   lectura pasa de damero a corredor sobre pista, sección de disciplinas, y
 *   barrido editorial: fuera el paso a paso del sistema, el diagrama del cruce
 *   y las fichas que contaban cómo está hecho por dentro.
 * =========================================================================== */

/* ===========================================================================
   Novaris · portada pública de novaris.run

   POR QUÉ ESTA HOJA ES PROPIA. La consola (`estilo.css`) es un instrumento que
   se mira al sol y sigue el tema del sistema; esto es una página de
   presentación y se compromete con un solo aspecto. Mezclarlas obligaba a que
   una de las dos cediera, y las dos tienen razón por separado.

   DE DÓNDE SALE EL ASPECTO. Se miraron las webs de la categoría antes de
   dibujar nada: race result (tipografía industrial DIN, foto de piernas con
   barrido, catálogo de producto sobre gris), mylaps, y sobre todo hyrox.com,
   que es la referencia que pidió el encargo. Lo que se trajo de ahí, y lo que
   no:

     · SÍ · El acento como BLOQUE macizo que desborda el canto de la pantalla,
       no como filete decorativo. Es lo que hace que la página se lea de lejos.
     · SÍ · La fotografía a plomo, cortada en recto y ocupando media pantalla.
       Ni esquinas redondeadas, ni sombras, ni marcos de mentira.
     · SÍ · Canto vivo en todo: `--radius: 0`. Ni una esquina redondeada en la
       página entera, que es lo primero que delata una plantilla.
     · NO · El negro puro de hyrox. Aquí el papel es el azul de la marca, con
       los valores exactos de la app de PC: la web y la app tienen que ser el
       mismo producto, no dos parecidos.
     · NO · Su tipografía (Brutal Type, de pago). Aquí Space Grotesk, libre y
       servida desde este mismo dominio.

   LO QUE LA SEPARA DE LA COMPETENCIA. Las dos webs grandes de cronometraje de
   México cargan Poppins y Orbitron con sombra doble sobre la foto del hero: la
   firma exacta de la plantilla comprada. Nada de eso aparece aquí.

   PROHIBIDOS QUE SE RESPETAN: ni degradado de fondo, ni texto con degradado,
   ni sombra que haga halo sobre oscuro, ni cristal esmerilado, ni emoji de
   icono, ni blanco puro, ni negro puro, ni cursiva en encabezados, ni
   `transition: all`, ni tres tarjetas idénticas con icono arriba, ni rótulo de
   capítulo encima de cada sección.
   =========================================================================== */

/* Los tokens NO se traen con `@import` desde aquí: se enlazan desde el HTML
   antes que esta hoja. Con `@import`, `tokens.css` viaja sin número de versión
   y quien ya visitó el dominio se queda con la paleta vieja en la caché; y
   además el navegador tiene que leer esta hoja entera antes de empezar a pedir
   la otra. Dos `<link>` se piden a la vez y los dos llevan versión. */

/* --- Base ------------------------------------------------------------------
   `overflow-x: clip` y no `hidden`: `clip` no crea contenedor de desplazamiento,
   así que no rompe `position: sticky` ni atrapa el foco dentro. Va en los dos
   elementos porque Safari viejo sólo obedece en `body`. Es la red que permite
   que el bloque de oro del hero se salga por el canto sin que la página se
   desplace de lado en un teléfono. */
*, *::before, *::after { box-sizing: border-box; }

html, body { overflow-x: clip; }

body {
  margin: 0;
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 400;
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

img, video { max-width: 100%; display: block; }

/* El foco aparece al instante y nunca se transiciona: si se desvanece durante
   200 ms, quien navega con el teclado se queda a ciegas justo al llegar. */
a:focus-visible,
button:focus-visible {
  outline: var(--rule-2) solid var(--color-focus);
  outline-offset: 3px;
}

::selection { background: var(--color-accent); color: var(--color-accent-ink); }

/* El cuerpo es contenedor de consulta para que cualquier caja pueda medir el
   ancho real de la ventana con `cqw`. Es lo que permite que una figura salga
   al canto sin usar `100vw`, que incluye la barra de desplazamiento y deja la
   página moviéndose de lado en escritorio. */
body { container-type: inline-size; }

/* LA CAJA, copiada del `.viewport-content` de Apple: ancho proporcional
   (87,5 %) con tope, centrada, y SIN relleno lateral. El margen lo hace el
   propio porcentaje, así que crece con la pantalla en vez de quedarse clavado
   en 56 px. Es el cambio que más aire mete en escritorio. */
.contenedor {
  width: var(--caja-ancho);
  max-width: var(--ancho);
  margin-inline: auto;
  /* Lo que queda entre el canto de la ventana y el borde de esta caja. Quien
     quiera sangrar hasta el canto, resta esto. */
  --sangria: max(0px, (100cqw - min(var(--ancho), 100cqw * 0.875)) / 2);
}
/* El hero respira más que el resto, igual que en su página. */
.portada .contenedor { max-width: var(--ancho-hero); }
.portada .contenedor { --sangria: max(0px, (100cqw - min(var(--ancho-hero), 100cqw * 0.875)) / 2); }

.sr {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* --- La línea de meta ------------------------------------------------------
   El separador de la casa, y la única figura decorativa que se permite la
   página: es la forma del oficio. Damero dibujado con gradientes, sin imagen,
   sin peticiones y nítido a cualquier densidad de pantalla. */
.meta-linea {
  height: 12px;
  background-image:
    linear-gradient(45deg, var(--color-accent) 25%, transparent 25%, transparent 75%, var(--color-accent) 75%),
    linear-gradient(45deg, var(--color-accent) 25%, transparent 25%, transparent 75%, var(--color-accent) 75%);
  background-size: 12px 12px;
  background-position: 0 0, 6px 6px;
}
/* Variante fina para cerrar el cuerpo: sólo la fila de arriba, y apagada. */
.meta-fina {
  height: 6px;
  background-image: linear-gradient(90deg, var(--color-accent-2) 50%, transparent 50%);
  background-size: 12px 6px;
}

/* --- N9 · Barra superior de canto a canto ----------------------------------
   Logotipo a la izquierda, una sola acción a la derecha, y entre medias nada.
   El vacío ES el diseño: meter ahí cuatro enlaces para «llenar» convierte esto
   en la barra que emite cualquier plantilla. Esta página tiene dos destinos de
   verdad (ella misma y la consola), así que se dice así. */
/* UNA sola barra. Antes eran dos superpuestas —marca arriba, producto debajo—
   y entre las dos se comían 96 px de alto fijo en cada pantalla. Ahora la
   marca, el nombre del producto y las dos acciones van en una línea, y es esa
   línea la que se queda pegada al bajar. */
.cabecera {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  border-bottom: var(--rule) solid var(--color-rule-2);
  /* Translúcida con desenfoque: el contenido pasa por debajo y se nota que
     hay una capa, sin tapar la sección con un bloque opaco. */
  background: color-mix(in srgb, var(--color-paper) 82%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
}
.cabecera .contenedor {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  min-height: var(--alto-barra);
}
/* Hairline entre la marca y el nombre del producto. Es lo que sustituye al
   corte horizontal que antes hacían las dos barras. */
.cabecera-separador {
  flex: 0 0 auto;
  inline-size: var(--rule);
  block-size: 20px;
  background: var(--color-rule-2);
}
.cabecera-producto {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: 0.012em;
  color: var(--color-ink);
  white-space: nowrap;
}
/* `auto` a la izquierda empuja las acciones al borde derecho sin necesidad de
   un `justify-content: space-between` que descolocaría el separador. */
.cabecera-acciones {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: var(--space-lg);
}
.cabecera-enlace {
  font-size: var(--ap-cuerpo);
  color: var(--color-ink-2);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: var(--rule-2) solid transparent;
  transition: color var(--dur-micro) var(--ease-out),
              border-color var(--dur-micro) var(--ease-out);
}
.cabecera-enlace:hover,
.cabecera-enlace:focus-visible {
  color: var(--color-ink);
  border-bottom-color: var(--color-accent);
}
.cabecera-boton {
  font-family: var(--font-display);
  font-size: var(--ap-cuerpo-menor);
  font-weight: 600;
  color: var(--color-accent-ink);
  background: var(--color-accent);
  padding: 0.45em 1em;
  text-decoration: none;
  white-space: nowrap;
  border-radius: var(--radius);
  transition: background var(--dur-micro) var(--ease-out);
}
.cabecera-boton:hover,
.cabecera-boton:focus-visible { background: var(--color-accent-claro); }
/* El enlace del logotipo NO se encoge. Sin esto, en un teléfono de 320 px el
   enlace de la derecha se queda con todo el ancho y la marca queda aplastada a
   31 px: una raya ilegible. Pasó de verdad, y sólo se ve midiendo el DOM,
   porque en escritorio sobra sitio. */
.marca-enlace {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  /* Área de toque de 44 px de alto aunque la imagen mida 26. */
  min-height: 44px;
}
.logo { height: 32px; width: auto; }


/* --- H2 · El hero en díptico -----------------------------------------------
   Izquierda: el titular dentro de un bloque de oro macizo que se sale por el
   canto izquierdo de la pantalla. Derecha: la figura, a plomo.

   EL SANGRADO. El hero es la única pieza que NO se mete en la caja centrada de
   76 rem: su fila ocupa el ancho de la ventana, así que el bloque de oro nace
   en el canto izquierdo de verdad y no en el borde de una columna. Un bloque
   que toca el canto y se va se lee como impreso; uno que respeta la caja se lee
   como una tarjeta. El texto de dentro se alinea con el margen de página, de
   modo que el titular, el rótulo y la entradilla comparten eje aunque el fondo
   se salga. Se hace con márgenes reales y no con `100vw`, que incluye la barra
   de desplazamiento y provoca desplazamiento lateral en escritorio.

   EL ACENTO. Éste es el ÚNICO bloque de oro de la página. El resto del oro son
   filetes, ordinales y estados. Un acento repartido por todas partes deja de
   ser acento y pasa a ser fondo. */
.portada {
  position: relative;
  background: var(--color-paper-2);
  /* La primera pantalla es una FOTO, no una columna de texto con una imagen de
     acompañante. Alto grande de verdad, con tope en píxeles para que en un
     monitor vertical no se convierta en un cartel de tres metros. */
  /* LA PANTALLA ENTERA MENOS LA BARRA, y el «menos» es el arreglo.

     La barra es `sticky`, pero `sticky` NO saca del flujo: ocupa sus 64 px de
     verdad, y el hero venia pidiendo `100dvh` DEBAJO de ellos. Entre los dos
     sumaban 100dvh + 64, asi que la primera pantalla nunca cabia entera: la
     entradilla se quedaba siempre por debajo del pliegue y habia que hacer
     scroll para leer la frase que explica que es esto. Medido con el telefono
     tumbado: seccion de 390 px empezando en y=65 sobre una pantalla de 390.

     `--alto-barra` ya se encoge sola en el telefono (52 px), asi que la resta
     se ajusta sin un punto de corte propio. */
  /* La hairline de abajo de la barra tambien ocupa: `--alto-barra` es el
     `min-height` del contenido, y el `border-bottom` suma su pixel encima. Sin
     restarlo el hero se pasaba por uno y aparecia barra de scroll. */
  min-height: calc(100dvh - var(--alto-barra) - var(--rule));
  display: grid;
  align-items: end;                /* el texto se apoya en la parte baja */
  /* El respiro era `--space-3xl` fijo, 96 px arriba y 96 abajo. Con 390 px de
     alto no caben: el `clamp` los encoge cuando no hay altura y los deja en 96
     cuando la hay.

     `svh` y no `dvh`: el `dvh` cambia cuando el navegador movil esconde su
     barra de direcciones, y el relleno se pondria a bailar durante el scroll. */
  padding-block:
    clamp(var(--space-md), 4svh, var(--space-2xl))
    clamp(var(--space-lg), 6svh, var(--space-3xl));
  overflow: hidden;                /* recorta la foto, no la página */
  /* Contenedor de consulta para medir el ancho real de la ventana en `cqw`. */
  container-type: inline-size;
}

/* La foto, cubriendo la sección entera. */
.portada-lienzo {
  position: absolute;
  inset: 0;
  z-index: var(--z-base);
}
/* El velo. Sin él, el texto claro sobre una foto clara no se lee, y bajar el
   texto a gris sobre color es de los tells más viejos del oficio. Dos paradas
   del mismo azul de marca, nada de degradados de dos colores. */
.portada-lienzo::after {
  content: "";
  position: absolute;
  inset: 0;
  /* DOS velos, y el de abajo es el que de verdad trabaja. El lateral solo
     oscurece la izquierda y dejaba limpio justo el PIE de la imagen, que es
     donde se apoya el texto: sin caja detras, el titular se perdia contra la
     hierba iluminada. El que sube desde abajo es el que sostiene la lectura. */
  background:
    linear-gradient(to top,
      color-mix(in srgb, var(--color-paper) 94%, transparent) 0%,
      color-mix(in srgb, var(--color-paper) 62%, transparent) 34%,
      transparent 68%),
    linear-gradient(95deg,
      color-mix(in srgb, var(--color-paper) 62%, transparent) 0%,
      transparent 62%);
}

.portada-texto {
  position: relative;
  z-index: var(--z-raised);
  width: 100%;
}

/* UN SOLO EJE DE TEXTO EN TODA LA PÁGINA.
   Un intento anterior sacó el hero entero de la caja centrada, y el resultado
   era que el titular arrancaba en un sitio y las secciones de abajo en otro:
   dos ejes verticales a cuatro centímetros uno del otro, que se leen como un
   descuadre y no como una decisión. El TEXTO se queda en la caja, con todos
   los demás; lo que sale al canto son los FONDOS y las fotos. */

.rotulo {
  display: block;
  margin-bottom: var(--space-lg);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-accent);
}

/* AQUI YA NO HAY CAJA, y la ausencia es la decision.
   Habia un bloque de oro macizo que entraba por el canto. No fue un descuido:
   el sello del principio lo declara como «bloque de oro a la izquierda, figura
   a la derecha», y era la mitad izquierda de un DIPTICO. Funcionaba.
   Lo que se rompio fue el contexto. El hero paso a ser video a sangre detras
   de TODO, y el mismo rectangulo dejo de ser media composicion para ser una
   pegatina opaca sobre una fotografia: no se alineaba con nada del cuadro —ni
   el sendero, ni el horizonte, ni las antenas— porque lo colocaba el CSS y no
   la toma. Y hacia un trabajo que no le toca, taparlo todo para que el titular
   se lea. De eso se encarga el velo, y un velo no amputa un tercio de imagen.
   El elemento se queda como gancho de maquetacion: es quien limita la medida
   del titular sin tocar el parrafo de debajo. */
.bloque-titular {
  max-width: 100%;
}

h1.titular {
  margin: 0;
  font-family: var(--font-display);
  /* 29 caracteres, cinco palabras. Por debajo de 50 el titular aguanta el
     tamaño grande sin amontonarse; la primera versión medía 63 y había que
     bajarla un escalón, porque un titular largo a tamaño máximo es el delator
     más fiable que existe. El texto se acortó, así que la escala sube. */
  /* El tamano lo manda el ancho, pero con un tope por ALTO. Sin el, en una
     pantalla baja el titular se come el sitio de la entradilla y la primera
     pantalla deja de caber. 10svh no toca nada en un telefono de pie (39 px
     frente a los 40 que ya tenia); solo actua cuando la pantalla es corta. */
  font-size: min(var(--text-display), 10svh);
  font-weight: 700;
  font-style: normal;             /* los encabezados van en redonda. Siempre. */
  line-height: 1.03;
  letter-spacing: -0.025em;
  text-transform: uppercase;
  text-wrap: balance;
  overflow-wrap: anywhere;
  min-width: 0;
}
/* El énfasis del titular NO es cursiva: es un subrayado dibujado, grueso, a la
   altura de la base. La palabra en cursiva dentro de un titular por lo demás
   recto es de los tics más reconocibles de una página generada. */
.titular .clave {
  font-style: normal;
  /* Oro, no tinta: el subrayado vivia sobre el bloque dorado y ahora vive
     sobre el video, con el titular en claro. */
  box-shadow: inset 0 -0.14em 0 var(--color-accent);
  /* Las tres palabras subrayadas viajan juntas. Partidas entre dos líneas, el
     subrayado se rompe en dos trozos sueltos y parece un error de maquetación
     en vez de un énfasis. En pantallas estrechas se suelta, porque ahí lo que
     no cabe se sale, y eso es peor. */
  white-space: nowrap;
}
@media (max-width: 40rem) {
  .titular .clave { white-space: normal; }
}

.entradilla {
  margin: var(--space-lg) 0 0;
  max-width: 46ch;                /* medida de lectura, entre 45 y 75 */
  color: var(--color-ink-2);
}

/* --- Figuras y huecos declarados -------------------------------------------
   Cada figura busca su archivo; si no está, pinta un hueco que DICE qué va
   ahí. Un hueco declarado no parece un error: parece una página a medio
   vestir, que es exactamente lo que es mientras no haya fotos de carreras
   reales. La alternativa —una foto de banco de imágenes con corredores
   genéricos— contradice en el primer golpe de vista a una página escrita para
   no prometer nada que no se pueda comprobar. */
figure { margin: 0; }

.figura {
  position: relative;
  overflow: hidden;
  background: var(--color-paper-3);
  border: var(--rule) solid var(--color-rule-2);
}
/* `<picture>` no pinta nada por sí mismo: con `display: contents` desaparece de
   la maquetación y el `<img>` de dentro se mide contra `.figura`, igual que
   cuando no había envoltura. Sin esto, el `height: 100%` de abajo se resolvería
   contra una caja en línea de altura cero y la foto no se vería. */
.figura picture { display: contents; }
.figura :is(img, video) { width: 100%; height: 100%; object-fit: cover; }

.figura-3x2   { aspect-ratio: 3 / 2; }
.figura-ancha { aspect-ratio: 21 / 8; }

/* --- Las dos formas a sangre -----------------------------------------------
   Sin proporción fija y sin borde: se estiran a lo que les dé el sitio. Son
   las que hacen que la página se vea de lejos. */
.figura-sangre {
  height: 100%;
  width: 100%;
  border: 0;
  background: transparent;
}
.figura-sangre :is(img, video) { height: 100%; }

/* La panorámica del cruce. Es LA pieza de la página, así que es la más alta de
   todas por una razón medida: en `apple.com/iphone-duo` la sección de la
   cámara ocupa 4 195 px y veinticuatro piezas, mientras las secundarias se
   quedan en mil y pico. La jerarquía la marca el TAMAÑO, no el titular. Aquí
   la idea equivalente es el instante del cruce.

   `dvh` y no `vh` porque en un teléfono la barra del navegador aparece y
   desaparece, y con `vh` la foto pega un salto cada vez. */
.figura-panoramica {
  width: 100%;
  height: 100dvh;
  border: 0;
  border-block: var(--rule) solid var(--color-rule-2);
}

/* El hueco. Casi del color del fondo: es un sitio reservado, no una pieza de
   la página. En la primera versión iba en el azul medio con el rayado bien
   marcado y pasaba lo contrario de lo que debe pasar: el hueco vacío pesaba
   más que el titular. Un hueco tiene que verse lo justo para saber que ahí va
   una foto y desaparecer en cuanto llegue. */
.figura.hueco {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--space-md);
  padding: var(--space-xl);
  text-align: center;
  border-style: dashed;
  border-color: var(--color-rule-2);
  background-color: color-mix(in oklab, var(--color-paper-3) 35%, var(--color-paper));
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0 11px,
    color-mix(in oklab, var(--color-rule) 45%, transparent) 11px 12px
  );
}
.figura.hueco img {
  width: 40px; height: 40px;
  object-fit: contain;
  opacity: 0.45;
}
.figura.hueco span {
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--color-muted);
  max-width: 34ch;
}

figcaption {
  margin-top: var(--space-sm);
  color: var(--color-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}

/* --- El reloj --------------------------------------------------------------
   La cifra como pieza tipográfica, no como dato. Es el FORMATO en que se
   entregan los tiempos; no hay una sola cifra de rendimiento en toda la página
   porque todavía no hay carreras que contar, y en un producto que ES la
   medición, inventar un número es el peor pecado posible. */
.reloj {
  background: var(--color-paper);
  min-height: 100dvh;
  display: grid;
  align-content: center;
  padding-block: var(--space-3xl);
}
.reloj .contenedor {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
}
.reloj-cifra {
  margin: 0;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--text-reloj);
  line-height: 0.95;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--color-ink);
  overflow-wrap: anywhere;
  min-width: 0;
}
.reloj-cifra .cent { color: var(--color-accent); }

.reloj-texto {
  margin: 0;
  max-width: 58ch;
  color: var(--color-ink-2);
}
.reloj-texto strong { color: var(--color-ink); font-weight: 600; }

/* --- Secciones y encabezados (S2 · colgado) --------------------------------
   El encabezado flota sobre la sección en su propio aire: sin regla, sin caja
   y SIN rótulo de capítulo al lado. El patrón «01 · LA VUELTA» en una columna
   estrecha con el título a la derecha es el tic más reconocible de la falsa
   página editorial; aquí no aparece ni una vez. */
/* UNA IDEA POR PANTALLA.
   Es el cambio que separa una página de producto de un folleto largo. En
   `apple.com/iphone-duo` ninguna idea comparte pantalla con otra: la sección
   más pequeña ocupa 904 px y la mayor 4 195. Aquí cada sección pide la altura
   de la ventana y centra lo suyo, así que al bajar se pasa de una idea a la
   siguiente en vez de leer una lista.

   `min-height` y no `height`: si el contenido crece (un teléfono estrecho, un
   texto más largo, la letra ampliada por accesibilidad), la sección crece con
   él en vez de recortarlo. `dvh` porque la barra del navegador móvil aparece y
   desaparece. */
.seccion {
  min-height: 100dvh;
  display: grid;
  align-content: center;
  padding-block: var(--space-3xl);
}
/* La franja de la foto grande no centra nada: la foto ES la sección. */
.seccion-sangre {
  min-height: 0;
  display: block;
  padding-block: var(--space-2xl);
}

.titulo {
  margin: 0 0 var(--space-lg);
  font-family: var(--font-display);
  /* Un escalón por encima del primer ajuste: al lado de un titular de 76 px,
     un título de sección de 31 px se leía como un subtítulo y la página perdía
     el pulso a mitad de recorrido. */
  font-size: var(--text-2xl);
  font-weight: 700;
  font-style: normal;
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--color-ink);
  overflow-wrap: anywhere;
  min-width: 0;
}
.bajada {
  margin: 0 0 var(--space-xl);
  max-width: 62ch;
  color: var(--color-ink-2);
}

/* --- Díptico · el ritmo de la página ---------------------------------------
   Split Studio: cada bloque grande parte la pantalla, texto a un lado y prueba
   al otro, y el lado se ALTERNA al bajar. `.diptico-invertido` manda la figura
   a la izquierda cambiando el orden visual, no el del documento: quien usa un
   lector de pantalla sigue oyendo primero el texto. */
.diptico {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-2xl);
  align-items: center;
}
.diptico-invertido > figure { order: -1; }

/* El díptico en el que la figura se va al canto en vez de quedarse dentro de
   la caja. La imagen gana la mitad entera de la pantalla y el texto se queda
   en su columna, que es el reparto que hace que una página se vea moderna en
   vez de acartonada. */
.diptico-sangre { align-items: stretch; }
.diptico-sangre > figure {
  margin-inline-start: calc(-1 * var(--sangria, var(--gutter)));
}
.diptico-sangre > figure .figura {
  height: 100%;
  min-height: clamp(16rem, 46dvh, 30rem);
  aspect-ratio: auto;
}
.diptico-sangre > div { align-self: center; }

/* Sección cuya figura sale de la caja: el pie de foto sí vuelve a la caja. */
.seccion-sangre { padding-block: var(--space-2xl); }
.pie-sangre {
  margin: var(--space-sm) 0 0;
  color: var(--color-muted);
  font-size: var(--text-sm);
}

/* --- F4 · La secuencia de pasos --------------------------------------------
   Ordinales de verdad (el orden importa: primero la pulsera, luego el arco,
   luego el tiempo), así que aquí el número SÍ se gana su sitio. Van colgados
   en el margen, monoespaciados y apagados. */
.pasos {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-lg);
}
.pasos > li {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: var(--space-lg);
  align-items: start;
  padding-top: var(--space-lg);
  border-top: var(--rule) solid var(--color-rule-2);
}
.paso-n {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--text-lg);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--color-accent-2);
}
.paso h3 {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 700;
  font-style: normal;
  line-height: 1.2;
  color: var(--color-ink);
}
.paso p {
  margin: 0;
  max-width: 58ch;
  color: var(--color-ink-2);
}

/* --- F3 · Hoja de especificaciones -----------------------------------------
   Las tres formas en que esto se estropea de verdad, y la respuesta concreta a
   cada una. Filas con filete, no tarjetas: tres tarjetas iguales con un icono
   arriba es la retícula que emite cualquier generador. */
.fallos { margin: 0; }
.fallos > div {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.4fr);
  gap: var(--space-lg);
  padding-block: var(--space-lg);
  border-top: var(--rule) solid var(--color-rule-2);
}
.fallos > div:last-child { border-bottom: var(--rule) solid var(--color-rule-2); }
.fallos dt {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 700;
  line-height: 1.25;
  color: var(--color-ink);
}
.fallos dd {
  margin: 0;
  max-width: 60ch;
  color: var(--color-ink-2);
}

/* --- La tabla de salidas ---------------------------------------------------
   Tabla de verdad, con `th` de fila: son datos, no maquetación. En un teléfono
   no se encoge hasta ser ilegible, se desplaza dentro de su propia caja. */
.tabla-caja { overflow-x: auto; }

.salidas {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-base);
  font-variant-numeric: tabular-nums;
}
.salidas th,
.salidas td {
  text-align: start;
  vertical-align: top;
  padding: var(--space-md) var(--space-lg) var(--space-md) 0;
  border-top: var(--rule) solid var(--color-rule-2);
}
.salidas thead th {
  border-top: none;
  border-bottom: var(--rule-2) solid var(--color-accent-2);
  padding-bottom: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-muted);
}
.salidas tbody th {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--color-ink);
  white-space: nowrap;
}
.salidas td { color: var(--color-ink-2); }

/* --- Cierre y C1 · chip perfilado ------------------------------------------
   Un solo botón. Dos botones juntos reparten la intención y no decide nadie.
   Perfilado y transparente, no macizo: el único macizo de la página es el
   bloque del titular. */
.cierre {
  background: var(--color-paper-2);
  padding-block: var(--space-3xl);
}
.cierre .titulo { margin-bottom: var(--space-lg); }
.cierre .bajada { margin-bottom: var(--space-xl); }

.boton {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  min-height: 48px;
  padding: var(--space-sm) var(--space-lg);
  border: var(--rule-2) solid var(--color-accent);
  border-radius: var(--radius);
  background: transparent;
  color: var(--color-accent);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur-micro) var(--ease-out),
              color var(--dur-micro) var(--ease-out),
              transform var(--dur-micro) var(--ease-out);
}
.boton:hover,
.boton:focus-visible { background: var(--color-accent); color: var(--color-accent-ink); }
.boton:active { transform: translateY(1px); }

/* --- Ft1 · El pie con mástil -----------------------------------------------
   El logotipo ancla una sola banda horizontal con el eslogan al lado. Nada de
   cuatro columnas de enlaces con fila de iconos sociales debajo: esta página
   no tiene mapa del sitio que catalogar, y fingir que lo tiene es justo la
   forma de pie que emite cualquier plantilla. */
.pie {
  border-top: var(--rule) solid var(--color-rule);
  padding-block: var(--space-xl);
  background: var(--color-paper);
}
.pie .contenedor {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-sm) var(--space-xl);
}
.pie-marca {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-ink);
}
.pie-lema,
.pie-anio {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-muted);
}
.pie-lema { letter-spacing: 0.04em; }

/* ===========================================================================
   MOVIMIENTO LIGADO AL SCROLL

   CÓMO, Y POR QUÉ ASÍ. Todo lo que se mueve aquí usa las animaciones nativas
   de scroll de CSS (`animation-timeline`), no JavaScript. La diferencia no es
   de gusto: un `addEventListener('scroll')` corre en el hilo principal y pelea
   con el desplazamiento del dedo, mientras que estas animaciones las conduce
   el compositor y van finas aunque la página esté ocupada. Cero bytes de JS en
   una página que no tiene ni una línea.

   LA REGLA QUE NO SE ROMPE. Nada de esto puede esconder contenido. Si el
   navegador no entiende `animation-timeline` (hoy: Safari viejo y Firefox sin
   la bandera), la página se ve entera y quieta, que es un final perfectamente
   digno. Por eso cada regla que empieza con `opacity: 0` vive DENTRO de un
   `@supports`: sin soporte, nadie pone nada a cero y no hay texto invisible.
   Es el fallo clásico de las animaciones de scroll y se evita así.

   QUÉ SE MUEVE, Y QUÉ NO. Tres cosas, y ninguna es decorativa:
     1. Las piezas entran una vez al aparecer. Sube 14 px y aparece. Ya está.
     2. El cronómetro CORRE mientras la franja cruza la pantalla. El scroll es
        el tiempo: en una página de cronometraje, mover el dedo y ver correr
        las centésimas dice lo que hace el producto mejor que un párrafo.
     3. La línea de meta se desplaza de lado, como cuando la pasas corriendo.
   No hay parallax, no hay tarjetas que se levanten, no hay nada que se repita
   en bucle para siempre pidiendo atención.
   =========================================================================== */

/* 1 · Entrada. `view()` arranca la animación cuando el elemento asoma por el
   borde inferior y la termina cuando ya está dentro; `both` la deja fija en su
   estado final, así que no vuelve a desvanecerse al subir. */
@supports (animation-timeline: view()) {
  html.con-movimiento {
    .reveal {
      /* NI `opacity: 0` DE BASE NI `both`. Con los dos, un elemento cuya línea
         de tiempo no avanza se queda clavado en el primer fotograma —es decir,
         invisible para siempre—. Y eso pasa en cuanto un ANCESTRO tiene
         `overflow: clip`: ese ancestro pasa a ser el scrollport de `view()`, no
         hace scroll nunca, y el progreso se queda en cero. Con los sangrados
         que lleva esta página (equipo, dosvistas, banda, compuesta…) eso dejó
         23 de 25 bloques en blanco.

         Con `forwards` y sin opacidad de base, fuera del rango no se aplica
         nada: el contenido se ve. La animación sigue entrando donde la línea de
         tiempo sí avanza, y donde no, simplemente no hay animación. Una entrada
         nunca debe poder dejar la página en blanco. */
      animation: entrar var(--dur-long) var(--ease-out) forwards;
      animation-timeline: view();
      animation-range: entry 5% cover 22%;
    }
  }
}
@keyframes entrar {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* 1b · Los titulares suben desde detrás de una máscara ----------------------
   El recurso de Apple para los encabezados: la línea no aparece, ENTRA. La
   caja de fuera recorta y la de dentro sube desde abajo. El relleno vertical
   de la máscara está para que no se corten las colas de la g y la j ni la
   virgulilla de la ñ: `overflow: hidden` recorta en la caja de relleno, así
   que ese margen sobrevive.

   Cuando hay más de una línea se escalonan moviendo el RANGO, no con
   `animation-delay`: un retardo no significa nada cuando el tiempo lo marca el
   scroll y el navegador lo ignora. `--l` lo pone el PHP en cada línea. */
.linea    { display: block; overflow: hidden; padding-block: 0.06em; }
.linea-i  { display: block; }

@supports (animation-timeline: view()) {
  html.con-movimiento {
    .linea-i {
      animation: subir-linea 1s var(--ease-out) both;
      animation-timeline: view();
      animation-range: entry calc(6% + var(--l, 0) * 9%) entry calc(72% + var(--l, 0) * 9%);
    }
  }
}
@keyframes subir-linea {
  from { transform: translateY(105%); }
  to   { transform: none; }
}

/* 1c · Las piezas de una lista entran una detrás de otra --------------------
   Cada `li` y cada fila lleva su propia línea de tiempo, así que el escalonado
   sale solo: la de abajo empieza más tarde porque entra más tarde. No hace
   falta contar índices ni repartir retardos. */
@supports (animation-timeline: view()) {
  html.con-movimiento {
    .pasos > li,
    .fallos > div,
    .salidas tbody tr {
      opacity: 0;
      animation: entrar-lado var(--dur-long) var(--ease-out) both;
      animation-timeline: view();
      animation-range: entry 8% cover 30%;
    }
  }
}
@keyframes entrar-lado {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}

/* 1d · El avance de la lectura: un corredor recorriendo una pista -----------
   Antes era un damero de línea de meta que se iba pintando. Esto dice más con
   menos: la pista es una hairline que cruza la pantalla, lo ya recorrido se
   pinta en oro, y encima va un corredor de 16 px que avanza con el scroll.
   Discreto a propósito — 16 px de alto, sin fondo ni caja.
   `scroll(root block)` mide el documento entero, que es lo que hay que medir.

   El corredor se mueve con `translate`, nunca con `left`: `left` es layout y
   provoca reflow en cada fotograma. El recorrido va en `cqw` (ancho del propio
   contenedor), así no hay que descontar a mano la barra de scroll como pasaría
   con `100vw`. */
.avance {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  height: 18px;
  z-index: var(--z-sticky);
  pointer-events: none;   /* no se puede hacer clic en una barra de progreso */
  container-type: inline-size;
}
/* La pista: siempre visible, tenue, centrada en la franja. */
.avance::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 3px;
  height: var(--rule);
  background: var(--color-rule-2);
}
/* La estela: lo ya leído, por detrás del corredor. */
.avance-estela {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 3px;
  height: calc(var(--rule) * 2);
  transform-origin: left center;
  transform: scaleX(0);
  background: var(--color-accent);
  opacity: 0.55;
}
/* El icono lleva ~3 px de aire bajo los pies a este tamaño, que es justo la
   altura a la que va la pista: pegando el SVG al fondo, el corredor la pisa
   en vez de flotar por encima. */
.avance-corredor {
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  color: var(--color-accent);
  /* Sin líneas de tiempo de scroll el corredor se quedaría clavado en el 0 %
     fingiendo que no has bajado nada: en ese caso no se enseña. */
  display: none;
}
@supports (animation-timeline: scroll()) {
  html.con-movimiento {
    .avance-estela {
      animation: avanzar-estela 1s linear both;
      animation-timeline: scroll(root block);
    }
    .avance-corredor {
      display: block;
      animation: correr-la-pista 1s linear both;
      animation-timeline: scroll(root block);
    }
  }
  html.sin-linea-de-scroll .avance-corredor { display: none; }
}
@keyframes avanzar-estela { to { transform: scaleX(1); } }
@keyframes correr-la-pista { to { translate: calc(100cqw - 16px) 0; } }

/* 1e · La foto del hero se acerca mientras la dejas atrás -------------------
   Doce por ciento en toda la primera pantalla. Es el gesto de Apple y el único
   sitio donde se permite, porque una foto que se mueve en cada sección marea.
   Va sobre la imagen, no sobre su caja, para que el recorte no se despegue de
   los bordes. */
@supports (animation-timeline: view()) {
  html.con-movimiento {
    .portada-lienzo .figura :is(img, video) {
      animation: acercar 1s linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
  }
}
@keyframes acercar {
  from { transform: scale(1); }
  to   { transform: scale(1.12); }
}

/* 2 · El cronómetro en marcha ------------------------------------------------
   Cada dígito que corre es una tira vertical de once cifras (0 a 9 y otra vez
   0, para que la vuelta cierre sin salto) dentro de una ventana de la altura
   de una sola. La tira sube de una en una con `steps()`, que es lo que le da
   el golpe seco de un contador mecánico en vez de un deslizamiento blando.

   Las velocidades son las de un cronómetro de verdad: la centésima de la
   derecha gira diez veces por cada vuelta de la de su izquierda, y el segundo
   avanza un paso mientras tanto. No es exacto al milisegundo, es legible, que
   aquí es lo que importa.

   Ojo: la ventana usa `em`, así que la pieza sigue a la escala fluida del
   reloj sin tener que repetir el `clamp` en ningún sitio. */
.rodillo {
  display: inline-block;
  width: 0.62em;             /* ancho de una cifra en IBM Plex Mono */
  height: 1em;
  overflow: hidden;
  vertical-align: baseline;
  /* Empuja la ventana para que la cifra visible se apoye en la línea de base
     igual que el texto fijo de al lado. */
  margin-bottom: -0.12em;
}
.rodillo b {
  display: block;
  height: 1em;
  font-weight: inherit;
  text-align: center;
}
/* (Aqui iba la version con linea de tiempo de scroll de los rodillos del reloj.
   Fuera por lo mismo: ahora los pinta el script atados al video. El resto de
   piezas de la pagina siguen usando `animation-timeline: view()` donde toca.) */
/* MUEVEN `margin-top`, NO `transform`, y la diferencia no es de gusto: es que
   con `transform` esto NO FUNCIONA. Las cifras son hermanas en flujo normal
   dentro de una ventana de 1em con `overflow: hidden`. Un `transform` sobre la
   primera mueve SOLO a la primera: las otras se quedan donde estaban, asi que
   la primera se va hacia arriba y detras no aparece ninguna. La ventana queda
   EN BLANCO. Medido: con tres cifras a 0/20/40 px, `translateY(-1em)` las deja
   en -20/20/40 (ventana vacia) y `margin-top: -1em` en -20/0/20 (se ve la
   siguiente, que es lo que tiene que pasar).
   `margin-top` negativo sobre la primera arrastra a todas las siguientes,
   porque eso es lo que hacen los margenes en flujo normal. */
@keyframes girar   { to { margin-top: -10em; } }
@keyframes avanzar { to { margin-top: -4em; } }

/* 3 · La línea de meta pasa de largo ----------------------------------------
   El damero se desplaza a lo ancho mientras la franja cruza la pantalla. Es la
   misma sensación de pasar corriendo por encima de la meta pintada en el
   suelo. Se mueve un pseudo-elemento más ancho que la caja, con `transform`,
   así que no hay repintado de fondo ni salto de maquetación. */
.meta-linea, .meta-fina { position: relative; overflow: hidden; }
.meta-linea > i, .meta-fina > i {
  position: absolute;
  inset: 0 -20% 0 -20%;
  display: block;
  background-image: inherit;
  background-size: inherit;
  background-position: inherit;
}
@supports (animation-timeline: view()) {
  html.con-movimiento {
    .meta-linea > i, .meta-fina > i {
      animation: correr-meta 1s linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
  }
}
@keyframes correr-meta { to { transform: translateX(-96px); } }

/* --- El respaldo para quien no sabe animar con el scroll -------------------
   `animation-timeline` no es Baseline: falta en Firefox estable y en los
   Safari anteriores al 26. En esos navegadores `portada.js` pone la clase de
   abajo en la raíz y marca cada pieza cuando asoma, y aquí se hace lo mismo
   con una animación de toda la vida.

   La diferencia está en de dónde sale el tiempo: arriba lo marca el dedo que
   arrastra la página, aquí lo marca el reloj del navegador. El efecto se
   parece; el de arriba es mejor y por eso va primero.

   NADA DE ESTO SE APLICA SI EL JAVASCRIPT NO CORRE, porque la clase la pone el
   propio archivo. Sin él no hay `opacity: 0` en ningún sitio y la página se ve
   completa. Es la única forma de que una animación de entrada no acabe siendo
   una página en blanco. */
html.con-movimiento.sin-linea-de-scroll .reveal { opacity: 0; }
html.con-movimiento.sin-linea-de-scroll .reveal.a-la-vista {
  animation: entrar var(--dur-long) var(--ease-out) both;
}
/* El reloj YA NO SE ANIMA DESDE AQUI. Lo pinta `portada.js` cifra a cifra desde
   el `currentTime` del clip que va detras, para que se pare exactamente en el
   fotograma del cruce. Aqui habia cuatro reglas mas que apuntaban a
   `.rodillo-segundo` y `.rodillo-centesima-1/2`: esos rodillos ya no existen
   —ahora son seis, de `min-d` a `cent-2`— asi que no seleccionaban nada.
   Se quitan en vez de renombrarse: una animacion de respaldo que girase cifras
   al azar seria peor que el reloj quieto en 0:00:00.00 que queda si el script
   no corre, y que es justo «el formato» que la seccion dice estar enseñando. */

/* Quien pide menos movimiento se queda con la página quieta y completa. Las
   reglas de arriba ni siquiera se aplican, así que aquí sólo hay que apagar
   las transiciones de estado. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

/* El alzado del botón sólo donde hay un ratón de verdad. */
@media (hover: hover) and (pointer: fine) {
  .boton:hover { transform: translateY(-1px); }
}

/* --- Anchos ----------------------------------------------------------------
   De menor a mayor, que es la única dirección honesta: el teléfono es el caso
   base y no la excepción. Comprobado a 320, 375, 414 y 768 px.
   Hasta 60 rem todo va en una columna, y el bloque de oro deja de desbordar
   sólo por un lado: a esos anchos se estira de canto a canto, porque un bloque
   cortado en un teléfono se lee como roto, no como impreso. */
@media (max-width: 60rem) {
  .portada .contenedor,
  .diptico {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xl);
  }
  .diptico-invertido > figure { order: 0; }

  /* En una sola columna el bloque sangra por los DOS cantos: con el texto
     apilado, un bloque que llega a la izquierda y se corta a la derecha parece
     recortado a tijera. */
  .bloque-titular {
    margin-inline-end: calc(-1 * var(--gutter));
    padding-inline-end: var(--gutter);
  }

  .fallos > div,
  .pasos > li { grid-template-columns: minmax(0, 1fr); gap: var(--space-sm); }

  .figura-ancha { aspect-ratio: 16 / 9; }
}

@media (max-width: 40rem) {
  body { font-size: var(--text-base); }

  .seccion { padding-block: var(--space-2xl); }
  .portada { padding-block: var(--space-2xl) var(--space-xl); }
  .cierre  { padding-block: var(--space-2xl); }

  .bloque-titular { padding-block: var(--space-lg); }

  /* La barra baja a 52 px en el teléfono. Se redefine el token, no la regla:
     así bajan con él la pista del corredor y el salto de las anclas. */
  :root { --alto-barra: 52px; }
  .cabecera .contenedor { gap: var(--space-sm); }
  .logo { height: 24px; }
  /* En un teléfono no caben la marca, el nombre del producto y dos acciones
     en la misma línea. Se van el separador, el nombre y el enlace secundario;
     quedan la marca y el botón, que es lo que alguien viene a pulsar. Acortar
     antes que partir en dos líneas o encoger la marca. */
  .cabecera-separador, .cabecera-producto, .cabecera-enlace { display: none; }

  .figura-3x2 { aspect-ratio: 4 / 3; }

  /* El pie se apila: en un teléfono la banda de mástil no cabe en una línea. */
  .pie .contenedor { flex-direction: column; align-items: flex-start; gap: var(--space-xs); }

  .boton { width: 100%; justify-content: center; }
}

/* ===========================================================================
   LA GALERÍA QUE AVANZA CON EL SCROLL

   Cómo funciona, porque no es evidente: la sección `.galeria` es una pista
   alta (tres pantallas). Dentro, `.galeria-fija` se queda pegada arriba
   ocupando la ventana entera, así que mientras recorres esas tres pantallas
   ves siempre lo mismo. Lo único que cambia es la posición de la tira, que se
   desplaza de lado conducida por lo que llevas recorrido de la pista.

   Es el mecanismo de las páginas de producto de Apple, hecho sin JavaScript:
   allí lo mueve un script sobre el hilo principal y aquí lo mueve el
   compositor con `animation-timeline: view()`.

   EL RESPALDO IMPORTA MÁS QUE EL EFECTO. Sin líneas de tiempo de scroll, la
   pista se queda de una pantalla, nada se pega y la tira pasa a ser una fila
   que se arrastra con el dedo, con anclaje por pieza. Se ve distinto, pero se
   lee entero, que es lo único que no se negocia.
   =========================================================================== */
.galeria {
  background: var(--color-paper-2);
  border-block: var(--rule) solid var(--color-rule-2);
}
.galeria-fija {
  min-height: 100dvh;
  display: grid;
  align-content: center;
  gap: var(--space-2xl);
  padding-block: var(--space-3xl);
  overflow: hidden;   /* recorta la tira, que es más ancha que la ventana */
}
.galeria-titulo { margin: 0; }

.galeria-tira {
  list-style: none;
  margin: 0;
  padding-inline: var(--sangria, var(--gutter));
  display: flex;
  gap: var(--space-xl);
  /* Sin línea de tiempo de scroll esto es una fila que se arrastra. */
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.galeria-tira::-webkit-scrollbar { display: none; }

.galeria-pieza {
  flex: 0 0 min(78vw, 34rem);
  scroll-snap-align: center;
  display: grid;
  align-content: start;
  gap: var(--space-sm);
  padding: var(--space-xl);
  background: var(--color-paper);
  border: var(--rule) solid var(--color-rule-2);
  min-height: clamp(15rem, 42dvh, 24rem);
}
.galeria-pieza .paso-n {
  font-size: var(--text-2xl);
  line-height: 1;
  margin-bottom: var(--space-sm);
}
.galeria-pieza h3 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1.15;
  color: var(--color-ink);
}
.galeria-pieza p {
  margin: 0;
  color: var(--color-ink-2);
  font-size: var(--text-base);
}

@supports (animation-timeline: view()) {
  html.con-movimiento {
    /* La pista se alarga: ese alto de más es el recorrido que se convierte en
       desplazamiento lateral. */
    .galeria { min-height: 300dvh; }
    .galeria-fija {
      position: sticky;
      top: 0;
      height: 100dvh;
    }
    /* Ya no se arrastra a mano: lo mueve el scroll. */
    .galeria-tira {
      overflow-x: visible;
      scroll-snap-type: none;
      animation: desfilar 1s linear both;
      animation-timeline: view();
      animation-range: cover 12% cover 88%;
    }
  }
}
/* Dos piezas y media de recorrido: la última queda a la vista al final de la
   pista, no pegada al canto. */
@keyframes desfilar {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-2 * (min(78vw, 34rem) + var(--space-xl)))); }
}

@media (max-width: 40rem) {
  .galeria-pieza { flex-basis: 86vw; padding: var(--space-lg); }
}

/* ===========================================================================
   PANTALLAS: UNA IDEA, UNA PIEZA, UNA PANTALLA

   Es el cambio de fondo que separa esto de un folleto. Antes había secciones
   con tres ideas apiladas en texto; ahora cada idea tiene su pantalla, su
   titular centrado y su pieza visual grande. En `apple.com/iphone-duo` no hay
   ni una sola sección de puro texto: si algo merece contarse, merece una
   imagen que lo enseñe.

   El texto va centrado y CORTO (veinte caracteres de medida en el titular,
   cincuenta en el apoyo). Centrar funciona aquí, y no en el hero, porque la
   pieza que manda es la imagen: el texto sólo la presenta.
   =========================================================================== */
.pantalla {
  min-height: 100dvh;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: var(--space-2xl);
  /* Arriba menos que abajo, como ellos: 144 / 224 en pantalla grande. */
  padding-block: var(--pad-seccion) var(--pad-seccion-final);
}
.pantalla-texto { display: grid; justify-items: center; }

.titulo-centro {
  text-align: center;
  /* `max-width: 75%` es la medida que usa Apple en
     `.section-header-headline`. Con caracteres el titular se estrechaba de más
     y salía en cuatro líneas. */
  max-width: 75%;
  margin-inline: auto;
  font-size: var(--text-3xl);
}
.bajada-centro {
  text-align: center;
  max-width: 52ch;
  margin-inline: auto;
  color: var(--color-ink-2);
}
/* El titular centrado necesita que sus líneas también lo estén. */
.titulo-centro .linea-i { text-align: center; }

/* La cifra que hace de pieza visual donde no hay foto. Un cero de seis
   centímetros dice «no se pierde ninguno» mejor que el párrafo que tiene
   debajo, y es honesto: no es una métrica inventada, es el número que sale de
   cómo está hecho el sistema. */
.cifra-gigante {
  margin: 0 0 var(--space-md);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(7rem, 26vw, 22rem);
  line-height: 0.82;
  letter-spacing: -0.05em;
  color: var(--color-accent);
  font-variant-numeric: tabular-nums;
}

/* La pieza de escenario: una imagen enorme, centrada, con aire alrededor. */
.figura-escenario {
  width: min(100%, 78rem);
  height: clamp(20rem, 64dvh, 44rem);
  margin-inline: auto;
  border: 0;
}
.pantalla > figure { width: 100%; padding-inline: var(--gutter); }

/* La imagen de cada pieza de la galería. */
.figura-pieza {
  width: 100%;
  height: clamp(11rem, 26dvh, 17rem);
  border: 0;
  margin-bottom: var(--space-lg);
}

@supports (animation-timeline: view()) {
  html.con-movimiento {
    /* Las piezas grandes entran creciendo un poco. Es el gesto que más se
       asocia a las páginas de producto y aquí sólo lo llevan las imágenes
       grandes, no cada tarjeta de la página. */
    .figura-escenario :is(img, video),
    .figura-panoramica :is(img, video) {
      animation: crecer 1s var(--ease-out) both;
      animation-timeline: view();
      animation-range: entry 0% cover 45%;
    }
    /* Y la cifra gigante sube y aparece. */
    .cifra-gigante {
      opacity: 0;
      animation: entrar-cifra 1s var(--ease-out) both;
      animation-timeline: view();
      animation-range: entry 10% cover 38%;
    }
  }
}
@keyframes crecer {
  from { transform: scale(1.14); }
  to   { transform: scale(1); }
}
@keyframes entrar-cifra {
  from { opacity: 0; transform: translateY(24px) scale(0.94); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 40rem) {
  .pantalla { padding-block: var(--space-3xl); gap: var(--space-xl); }
  .titulo-centro { max-width: 14ch; }
}

/* ===========================================================================
   EL RITMO DE FONDOS

   Apple alterna el color de fondo de una sección a la siguiente. Lo tiene
   declarado así:

       --global-section-background-color-alt:      rgb(245,245,247)
       --global-section-background-color-alt-dark: rgb(29,29,31)

   y lo aplica con la clase `background-alt` sobre `.section`. No es un adorno:
   es lo que separa una idea de la siguiente sin dibujar una línea. Una página
   entera del mismo color se lee como un solo bloque largo, que es justo lo que
   le pasaba a ésta.

   Aquí los dos valores son los azules de la app de PC: el hondo y el de marca.
   La alternancia va por posición, con `:nth-of-type`, para que no haya que
   acordarse de poner una clase cada vez que se añade una sección.
   =========================================================================== */
.pantalla:nth-of-type(even) { background: var(--color-paper-2); }
.pantalla:nth-of-type(odd)  { background: var(--color-paper); }

/* Las secciones que ya traen fondo propio no entran en el reparto. */
.portada,
.galeria,
.cierre { background: var(--color-paper-2); }
.reloj  { background: var(--color-paper); }

/* Un filete finísimo entre pantallas del mismo color, por si dos quedan
   seguidas: sin él, el corte desaparece. */
.pantalla + .pantalla { border-top: var(--rule) solid var(--color-rule-2); }

/* --- El enlace que acompaña al titular -------------------------------------
   En su página cada cabecera de sección lleva un enlace corto al lado
   (`Watch the film ▸`). Da una salida a quien ya se convenció y no obliga a
   bajar hasta el final. */
.titulo-con-accion {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md) var(--space-xl);
  width: 100%;
}
.accion-seccion {
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-accent-claro);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: var(--rule-2) solid transparent;
  transition: border-color var(--dur-micro) var(--ease-out);
}
.accion-seccion:hover,
.accion-seccion:focus-visible { border-bottom-color: var(--color-accent-claro); }

/* ===========================================================================
   LA PANTALLA CLARA

   Apple alterna blanco y gris claro entre secciones, y sus fotos de producto
   viven sobre ese fondo: el objeto va recortado, sin escenario y sin sombra,
   así que el blanco de la foto se funde con el blanco de la página y parece
   que el aparato flota en la hoja.

   Poner esa misma foto sobre el marino dejaría un rectángulo blanco pegado en
   medio. Por eso la sección que enseña producto cambia de papel: el azul
   clarísimo de la app de PC, que ya es de la marca.
   =========================================================================== */
.pantalla.pantalla-clara {
  background: var(--color-papel-claro);
  color: var(--color-tinta-clara);
}
.pantalla-clara .titulo { color: var(--color-tinta-clara); }
.pantalla-clara .bajada { color: color-mix(in oklab, var(--color-tinta-clara) 78%, transparent); }
.pantalla-clara .figura { background: transparent; border: 0; }
/* En papel claro el acento oscurece, porque el oro claro sobre casi blanco no
   se lee: 1,6:1. El oro normal sobre este azul tenue da 2,4:1, tampoco. Se usa
   el propio azul de marca, que da 12:1. */
.pantalla-clara .paso-n,
.pantalla-clara .cifra-gigante { color: var(--color-tinta-clara); }

/* La pieza de producto: enorme, sin caja, sin borde, sin sombra. */
.figura-producto {
  width: min(100%, 86rem);
  height: clamp(18rem, 58dvh, 40rem);
  margin-inline: auto;
  border: 0;
  background: transparent;
}
.figura-producto > img { object-fit: contain; }

/* El blanco de la foto de producto se funde con el papel de la sección.
   `multiply` deja pasar el fondo allí donde la foto es blanca, así que el
   aparato queda flotando sin el rectángulo que delata el recorte. Es el truco
   de siempre para fotos de producto sobre fondo claro, y evita tener que pedir
   PNG con transparencia. Sólo vale sobre papel claro: sobre el marino
   oscurecería la foto entera. */
.pantalla-clara .figura-producto > img { mix-blend-mode: multiply; }


/* ===========================================================================
   EL SISTEMA DE LA REFERENCIA, APLICADO
   Todo lo de este bloque sale de `ESTUDIO_APPLE_IPHONE_DUO.md`: valores
   medidos en la página descargada, no aproximados. Va al final de la hoja
   para ganar a lo anterior donde se solapan.
   =========================================================================== */

/* --- Tipografía: caja baja, peso 600, espaciado negativo en lo grande -------
   Las mayúsculas venían de HYROX. La referencia no usa ni una; el peso de
   todos sus titulares es 600 y el del cuerpo 400. Es el cambio de un solo
   golpe que más acerca la página. */
h1.titular,
.titulo,
.titulo-seccion,
.ficha-titular,
.tarjeta-titular,
.losa-titular {
  text-transform: none;
  font-weight: var(--peso-titular);
  font-style: normal;
}
h1.titular {
  font-size: var(--ap-titular-portada);
  line-height: 1.062;
  letter-spacing: -0.009em;
}
.titulo-seccion {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--ap-titular-seccion);
  line-height: 1.083;
  letter-spacing: -0.003em;
  color: var(--color-ink);
  max-width: 75%;
  overflow-wrap: anywhere;
  min-width: 0;
}
body { font-size: var(--ap-cuerpo); line-height: 1.47; letter-spacing: -0.022em; }
.bajada, .entradilla, .reloj-texto { font-size: var(--ap-cuerpo); }
.rotulo {
  font-size: var(--ap-antetitulo); line-height: 1; letter-spacing: 0.011em;
  text-transform: none; font-weight: 600;
}

/* --- La barra local del producto ------------------------------------------
   La segunda barra de la referencia: nombre del producto a la izquierda, dos
   acciones a la derecha, y es la que se queda pegada al bajar. La global va
   translúcida con desenfoque (rgba(232,232,237,.4) en su caso; aquí el marino
   al 72 %). */
.logo { height: 24px; }
/* La pista del corredor cuelga justo por debajo de la barra. */
.avance { top: var(--alto-barra); }

/* --- Secciones: una idea por pantalla, con fondos alternos de verdad --------
   Aquí «clara» es una sección clara de verdad (el azul tenue de la app de PC),
   no un azul un poco menos oscuro. La referencia alterna blanco y gris claro;
   nosotros marino y azul tenue. Sin regla entre secciones: el corte lo hace el
   color. */
.seccion {
  min-height: 0;
  display: block;
  padding-block: var(--pad-seccion) var(--pad-seccion-final);
  background: var(--color-paper);
  border: 0;
}
.seccion.clara {
  background: var(--color-papel-claro);
  color: var(--color-tinta-clara);
}
.seccion.clara .titulo-seccion { color: var(--color-tinta-clara); }
/* La cabecera de esta sección no va arriba y a lo ancho, sino en la columna
   de la mesa: por la franja de arriba pasa el render, que sube -46 % hasta la
   sección anterior, y con los corredores dentro el titular quedaba encima de
   cuerpos oscuros —tinta marina sobre marrón— y no se leía. */

.seccion.clara .bajada { color: color-mix(in oklab, var(--color-tinta-clara) 78%, transparent); }
.seccion.clara .figura { background: transparent; border: 0; }
.seccion.clara .accion-seccion { color: var(--color-tinta-clara); }
.seccion.clara .figura.hueco {
  background-color: color-mix(in oklab, var(--color-tinta-clara) 6%, transparent);
  background-image: none;
  border: var(--rule) dashed color-mix(in oklab, var(--color-tinta-clara) 30%, transparent);
}
.seccion.clara .figura.hueco span { color: color-mix(in oklab, var(--color-tinta-clara) 70%, transparent); }
.seccion.clara .figura.hueco img { display: none; }

.cabecera-seccion {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: var(--space-md) var(--space-xl);
  margin-bottom: var(--space-2xl);
}
.cabecera-centro { flex-direction: column; align-items: center; text-align: center; }
.cabecera-centro .titulo-seccion { max-width: 100%; text-align: center; }
.cabecera-centro .titulo-seccion .linea-i { text-align: center; }
.cabecera-centro .bajada { max-width: 52ch; text-align: center; margin: 0; }
.accion-seccion { text-transform: none; letter-spacing: -0.022em; font-size: var(--ap-cuerpo); font-weight: 400; }

/* --- Las tarjetas de destacados (MediaCardGallery) --------------------------
   Tarjetas casi de ancho completo que se desplazan de lado con anclaje; la
   siguiente asoma por la derecha para que se vea que hay más. Titular a 28 px
   arriba centrado, la pieza debajo. Sin JavaScript se desplazan igual con el
   dedo o la rueda; el script sólo pinta los puntos y las flechas. */
.tarjetas { position: relative; }
.tarjetas-pista {
  list-style: none; margin: 0;
  padding-inline: var(--sangria, var(--gutter));
  display: flex; gap: var(--space-lg);
  overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--sangria, var(--gutter));
  scrollbar-width: none; overscroll-behavior-x: contain;
}
.tarjetas-pista::-webkit-scrollbar { display: none; }
.tarjeta {
  flex: 0 0 min(88vw, var(--ancho));
  scroll-snap-align: start;
  display: grid; grid-template-rows: auto minmax(0, 1fr);
  justify-items: center; gap: var(--space-lg);
  min-height: clamp(20rem, 66dvh, 44rem);
  padding: var(--space-xl) var(--space-lg) var(--space-lg);
  background: color-mix(in srgb, #fff 55%, var(--color-papel-claro));
}
.tarjeta-titular {
  margin: 0; text-align: center;
  font-family: var(--font-display); font-size: var(--ap-tarjeta); line-height: 1.142; letter-spacing: 0.007em;
  color: var(--color-tinta-clara); max-width: 24ch;
}
.tarjeta .fig { width: 100%; height: 100%; margin: 0; }
.figura-tarjeta { width: 100%; height: 100%; min-height: 14rem; border: 0; background: transparent; }
.figura-tarjeta :is(img, video) { object-fit: cover; }
.figura-tarjeta-fundida :is(img, video) { object-fit: contain; mix-blend-mode: multiply; }
/* La tarjeta que es una frase: el texto es la pieza. */
.tarjeta-frase { background: var(--color-paper); align-content: center; }
.tarjeta-frase .tarjeta-titular {
  color: var(--color-ink); font-size: var(--ap-titular-seccion);
  line-height: 1.083; letter-spacing: -0.003em; max-width: 16ch;
}
.tarjeta-frase-texto { margin: 0; max-width: 40ch; text-align: center; color: var(--color-ink-2); }
/* El gráfico del anillo de centésimas: la pieza no fotográfica de la galería. */
.tarjeta-grafico { display: grid; place-items: center; position: relative; width: 100%; }
.anillo {
  display: block; width: clamp(9rem, 26dvh, 15rem); aspect-ratio: 1;
  border-radius: 50%;
  border: 1.1rem solid color-mix(in oklab, var(--color-accent) 22%, transparent);
  position: relative;
}
.anillo > i {
  position: absolute; inset: -1.1rem; border-radius: 50%;
  border: 1.1rem solid var(--color-accent);
  border-right-color: transparent; border-bottom-color: transparent;
  transform: rotate(-45deg);
}
.anillo-cifra {
  position: absolute; font-family: var(--font-mono); font-size: var(--ap-titular-seccion);
  color: var(--color-tinta-clara);
}
.tarjetas-control {
  display: flex; align-items: center; justify-content: center; gap: var(--space-md);
  margin-top: var(--space-lg);
}
.tarjetas-puntos {
  list-style: none; margin: 0; padding: 0.4rem 0.8rem; display: flex; gap: 0.5rem;
  background: color-mix(in oklab, var(--color-tinta-clara) 10%, transparent); border-radius: 999px;
}
.tarjetas-puntos li {
  width: 0.5rem; height: 0.5rem; border-radius: 999px;
  background: color-mix(in oklab, var(--color-tinta-clara) 32%, transparent);
  transition: width 250ms cubic-bezier(0,0,0.5,1), background-color 250ms cubic-bezier(0,0,0.5,1);
}
.tarjetas-puntos li.activo { width: 1.5rem; background: var(--color-tinta-clara); }
.tarjetas-flecha {
  width: 2.25rem; height: 2.25rem; border-radius: 50%; border: 0;
  background: color-mix(in oklab, var(--color-tinta-clara) 10%, transparent); color: var(--color-tinta-clara);
  font-size: 1.4rem; line-height: 1; cursor: pointer;
  transition: background-color 200ms cubic-bezier(0,0,0.5,1);
}
.tarjetas-flecha:hover { background: color-mix(in oklab, var(--color-tinta-clara) 18%, transparent); }

/* --- El objeto en sus estados (ProductViewerGallery) ----------------------- */
.estados {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: var(--space-lg);
}
.figura-estado { aspect-ratio: 1.89; border: 0; }
.estados .fig figcaption {
  text-align: center; font-size: var(--ap-cuerpo-menor);
  color: color-mix(in oklab, var(--color-tinta-clara) 70%, transparent);
}

/* --- La panorámica con el titular encima ----------------------------------- */
.panoramica { position: relative; }
.panoramica .figura-panoramica { position: relative; height: clamp(24rem, 92dvh, 56rem); }
.panoramica .figura-panoramica::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 40%, color-mix(in srgb, var(--color-paper) 88%, transparent) 100%);
}
.panoramica-texto { position: absolute; inset-inline: 0; bottom: var(--space-2xl); z-index: var(--z-raised); }
.titulo-sobre-foto { color: var(--color-ink); }
.bajada-sobre-foto { margin: var(--space-sm) 0 0; color: var(--color-ink-2); max-width: 52ch; }

/* --- Las fichas verticales (CaptionTileGallery) ----------------------------
   Proporción 744×904 como las suyas; fondo OSCURO sobre sección clara. El
   pie va debajo, fuera de la ficha, en 14 px. */
.fichas {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); gap: var(--space-lg);
}
.ficha { display: grid; gap: var(--space-md); align-content: start; }
.ficha-cuerpo {
  aspect-ratio: 744 / 904; background: var(--color-paper); color: var(--color-ink);
  display: grid; align-content: end; gap: var(--space-sm); padding: var(--space-xl);
}
.ficha-cifra {
  margin: 0; font-family: var(--font-mono); font-weight: 500;
  font-size: clamp(6rem, 12vw, 10rem); line-height: 0.85; letter-spacing: -0.05em; color: var(--color-accent);
}
.ficha-titular {
  margin: 0; font-family: var(--font-display); font-size: var(--ap-tarjeta);
  line-height: 1.142; letter-spacing: 0.007em;
}
.ficha-pie {
  margin: 0; font-size: var(--ap-cuerpo-menor); line-height: 1.428; letter-spacing: -0.016em;
  color: color-mix(in oklab, var(--color-tinta-clara) 78%, transparent);
}
.figura-ficha { aspect-ratio: 744 / 904; border: 0; }

/* --- Las losas de tipos de salida ------------------------------------------ */
.losas {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr)); gap: var(--space-lg);
}
.losa {
  background: var(--color-paper-2); padding: var(--space-xl);
  display: grid; align-content: end; gap: var(--space-sm); min-height: 16rem;
}
.losa-titular {
  margin: 0; font-family: var(--font-display); font-size: var(--ap-tarjeta);
  line-height: 1.142; letter-spacing: 0.007em; color: var(--color-accent-claro);
}
.losa p { margin: 0; color: var(--color-ink-2); }

/* --- El fundido escalonado (StaggeredFadeIn) --------------------------------
   Como lo tiene programado la referencia: cada pieza arranca en opacidad 0 y
   se enciende en 0,45 s con 0,15 s entre una y la siguiente. Se dispara al
   entrar la LISTA, no cada pieza, para que el escalonado se vea. La clase
   `encendido` la pone `portada.js` con un IntersectionObserver. */
/* El escalonado tiene DOS caminos, y antes sólo estaba escrito el segundo:
   · Con líneas de tiempo de scroll (Chrome, Edge): lo lleva el CSS, igual que
     los `.reveal`. Sin opacidad de base y con `forwards`, para que un elemento
     cuya línea no avance se quede visible en vez de desaparecer.
   · Sin ellas: lo lleva `portada.js` con su IntersectionObserver y su clase
     `encendido`, y ahí sí hace falta la opacidad de base.
   El fallo estaba en que la opacidad 0 se aplicaba SIEMPRE, pero la clase
   `encendido` sólo llega por JS — y el JS se retira en cuanto detecta soporte
   nativo. Resultado: las listas se quedaban invisibles justo en los
   navegadores que mejor soportan todo lo demás. */
@supports (animation-timeline: view()) {
  html.con-movimiento [data-staggered] {
    animation: fade-in 0.45s cubic-bezier(0, 0, 0.5, 1) forwards;
    animation-delay: calc(var(--i, 0) * 0.15s);
    animation-timeline: view();
    animation-range: entry 5% cover 20%;
  }
}
html.con-movimiento.sin-linea-de-scroll [data-staggered] { opacity: 0; animation: none; }
html.con-movimiento.sin-linea-de-scroll .encendido [data-staggered] {
  animation: fade-in 0.45s cubic-bezier(0, 0, 0.5, 1) both;
  animation-delay: calc(var(--i, 0) * 0.15s);
}
@keyframes fade-in {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

@media (max-width: 40rem) {
  .cabecera-enlace { display: none; }
  .titulo-seccion { max-width: 100%; }
  .tarjeta { flex-basis: 92vw; min-height: 0; }
  .tarjetas-flecha { display: none; }
}

/* ===========================================================================
   SEGUNDA CAPA DEL SISTEMA DE LA REFERENCIA: lo visual que no son fotos
   Medido en su CSS: tarjetas y medios con esquinas de 28 px, botones en
   píldora (980 px), botones «+» circulares que abren un detalle, acordeón de
   preguntas, notas al pie. Y los clips de un solo gesto, aquí dibujados.
   =========================================================================== */

/* --- Esquinas y píldoras ------------------------------------------------- */
:root { --radio-tarjeta: 28px; --radio-pildora: 980px; }
.tarjeta, .ficha-cuerpo, .losa, .figura-estado, .figura-ficha, .figura-producto, .figura-tarjeta,
.clip, .pregunta {
  border-radius: var(--radio-tarjeta);
  overflow: hidden;
}
.figura-tarjeta { border-radius: calc(var(--radio-tarjeta) - 8px); }
.boton, .cabecera-boton {
  border-radius: var(--radio-pildora);
  letter-spacing: -0.022em; text-transform: none; font-size: var(--ap-cuerpo); font-weight: 400;
}
.boton { padding: 0.7em 1.4em; min-height: 0; border-width: 1px; }
.cabecera-boton { font-size: var(--ap-cuerpo-menor); padding: 0.4em 1em; }
/* Los enlaces de acción llevan el chevrón de la casa. */
.accion-seccion::after, .cabecera-enlace::after { content: " \203A"; }
.accion-seccion { border: 0; }

/* --- El botón «+» y el detalle -------------------------------------------
   En la referencia cada ficha lleva un círculo con «+» abajo a la derecha que
   abre una ventana con la explicación larga. Aquí es un `<dialog>` nativo: sin
   librería, se cierra con Escape y devuelve el foco solo. */
.ficha-cuerpo { position: relative; }
.mas {
  position: absolute; inset-inline-end: var(--space-lg); inset-block-end: var(--space-lg);
  width: 2.25rem; height: 2.25rem; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--color-ink); color: var(--color-paper);
  font-family: var(--font-display); font-size: 1.5rem; line-height: 1; font-weight: 400;
  display: grid; place-items: center;
  transition: transform 200ms cubic-bezier(0, 0, 0.5, 1), background-color 200ms cubic-bezier(0, 0, 0.5, 1);
}
.mas:hover { transform: scale(1.08); background: var(--color-accent-claro); }
.mas:active { transform: scale(0.96); }
.detalle {
  border: 0; padding: 0; background: transparent;
  max-width: min(92vw, 44rem); width: 100%;
}
.detalle::backdrop { background: color-mix(in srgb, var(--color-paper) 70%, transparent); backdrop-filter: blur(6px); }
.detalle-caja {
  background: var(--color-papel-claro); color: var(--color-tinta-clara);
  border-radius: var(--radio-tarjeta); padding: var(--space-2xl) var(--space-xl) var(--space-xl);
  position: relative;
}
.detalle-caja h3 { margin: 0 0 var(--space-md); font-family: var(--font-display); font-size: var(--ap-titular-seccion); font-weight: 600; line-height: 1.083; letter-spacing: -0.003em; }
.detalle-caja p { margin: 0 0 var(--space-md); font-size: var(--ap-cuerpo); line-height: 1.47; }
.detalle-cerrar {
  position: absolute; inset-inline-end: var(--space-md); inset-block-start: var(--space-md);
  width: 2.25rem; height: 2.25rem; border-radius: 50%; border: 0; cursor: pointer;
  background: color-mix(in oklab, var(--color-tinta-clara) 10%, transparent); color: var(--color-tinta-clara);
  font-size: 1.25rem; line-height: 1; display: grid; place-items: center;
}
html.con-movimiento .detalle[open] .detalle-caja { animation: abrir-detalle 400ms cubic-bezier(0.33, 1, 0.68, 1) both; }
@keyframes abrir-detalle { from { opacity: 0; transform: translateY(16px) scale(0.98); } to { opacity: 1; transform: none; } }

/* --- El acordeón de preguntas --------------------------------------------
   `<details>` nativo. La apertura anima `grid-template-rows`, que es la forma
   de animar la altura sin recalcular la maqueta a cada fotograma. */
.preguntas { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-sm); }
.pregunta { background: var(--color-paper-2); }
.pregunta summary {
  list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; gap: var(--space-md);
  padding: var(--space-lg) var(--space-xl);
  font-family: var(--font-display); font-size: var(--ap-tarjeta); font-weight: 600; line-height: 1.142; letter-spacing: 0.007em;
  color: var(--color-ink);
}
.pregunta summary::-webkit-details-marker { display: none; }
.pregunta summary::after {
  content: "+"; flex: 0 0 auto; width: 2rem; height: 2rem; border-radius: 50%;
  display: grid; place-items: center; background: color-mix(in oklab, var(--color-ink) 12%, transparent);
  font-weight: 400; transition: transform 250ms cubic-bezier(0, 0, 0.5, 1);
}
.pregunta[open] summary::after { transform: rotate(45deg); }
.pregunta .respuesta { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 400ms cubic-bezier(0.33, 1, 0.68, 1); }
.pregunta[open] .respuesta { grid-template-rows: 1fr; }
.pregunta .respuesta > div { overflow: hidden; }
.pregunta .respuesta p { margin: 0; padding: 0 var(--space-xl) var(--space-lg); color: var(--color-ink-2); max-width: 62ch; }

/* --- Notas al pie ----------------------------------------------------------- */
.nota { font-size: 0.7em; vertical-align: super; line-height: 0; color: inherit; text-decoration: none; margin-inline-start: 0.1em; }
.notas { padding-block: var(--space-xl); }
.notas ol { margin: 0; padding-inline-start: 1.2em; color: var(--color-muted); font-size: var(--ap-pie); line-height: 1.333; letter-spacing: -0.01em; max-width: 80ch; }
.notas li { margin-bottom: var(--space-xs); }

/* --- La tira de datos del sistema (tout-stat) ------------------------------
   Cifras de 28/600 con su pie de 12: los números que son del sistema, no
   promesas. Dos puntos, un teléfono, ninguna conexión, una centésima. */
.datos { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr)); gap: var(--space-lg); margin-top: var(--space-2xl); }
.dato { border-top: var(--rule) solid color-mix(in oklab, currentColor 18%, transparent); padding-top: var(--space-md); }
.dato b { display: block; font-family: var(--font-display); font-size: var(--ap-tarjeta); font-weight: 600; line-height: 1.142; letter-spacing: 0.007em; }
.dato span { display: block; font-size: var(--ap-pie); line-height: 1.333; letter-spacing: -0.01em; opacity: 0.75; margin-top: 0.3em; }

/* --- El anillo, ahora de verdad animado ---------------------------------------
   Es la tarjeta gráfica de los destacados: el anillo se llena al entrar, como
   el de la batería en la referencia. SVG con `stroke-dashoffset`, que se
   compone en la GPU. */
.anillo-svg { width: clamp(9rem, 26dvh, 15rem); height: auto; display: block; }
.anillo-svg .fondo { stroke: color-mix(in oklab, var(--color-accent) 22%, transparent); }
.anillo-svg .traza { stroke: var(--color-accent); stroke-dasharray: 283; stroke-dashoffset: 283; transform: rotate(-90deg); transform-origin: 50% 50%; }
html.con-movimiento .encendido .anillo-svg .traza { animation: llenar 1.4s cubic-bezier(0.33, 1, 0.68, 1) 0.3s both; }
@keyframes llenar { to { stroke-dashoffset: 40; } }

/* --- El clip dibujado: así se lee un cruce ----------------------------------
   El sustituto del vídeo mientras no hay vídeo, y con la misma regla que los
   suyos: un solo gesto. La pulsera cruza entre las dos antenas, las lecturas
   se acumulan y, al llegar a suficientes, el cruce queda. Es un diagrama, y
   se ve que lo es: no finge ser una foto. */
.clip { background: var(--color-paper-2); padding: var(--space-xl); }
.clip svg { width: 100%; height: auto; display: block; }
.clip .antena { fill: var(--color-ink); }
.clip .suelo { stroke: color-mix(in oklab, var(--color-ink) 22%, transparent); }
.clip .onda { fill: none; stroke: var(--color-accent); stroke-width: 2; opacity: 0; transform-origin: center; }
.clip .pulsera { fill: var(--color-accent); }
.clip .lectura { fill: color-mix(in oklab, var(--color-ink) 18%, transparent); }
.clip .marca { fill: var(--color-ink); font-family: var(--font-mono); font-size: 14px; opacity: 0; }
.clip .cruce { fill: var(--color-accent); font-family: var(--font-display); font-size: 22px; font-weight: 600; opacity: 0; }
html.con-movimiento .encendido .clip .pulsera { animation: pasar 3.2s cubic-bezier(0.33, 1, 0.68, 1) both; }
html.con-movimiento .encendido .clip .onda { animation: latir 0.9s ease-out 0.7s 3 both; }
html.con-movimiento .encendido .clip .onda:nth-child(2) { animation-delay: 1s; }
html.con-movimiento .encendido .clip .lectura { animation: leer 0.25s steps(1) both; }
html.con-movimiento .encendido .clip .lectura:nth-of-type(1) { animation-delay: 0.9s; }
html.con-movimiento .encendido .clip .lectura:nth-of-type(2) { animation-delay: 1.2s; }
html.con-movimiento .encendido .clip .lectura:nth-of-type(3) { animation-delay: 1.5s; }
html.con-movimiento .encendido .clip .lectura:nth-of-type(4) { animation-delay: 1.8s; }
html.con-movimiento .encendido .clip .lectura:nth-of-type(5) { animation-delay: 2.1s; }
html.con-movimiento .encendido .clip .cruce { animation: aparecer 0.5s cubic-bezier(0.33, 1, 0.68, 1) 2.4s both; }
html.con-movimiento .encendido .clip .marca { animation: aparecer 0.5s cubic-bezier(0.33, 1, 0.68, 1) 2.7s both; }
@keyframes pasar { from { transform: translateX(-140px); } to { transform: translateX(560px); } }
@keyframes latir { 0% { opacity: 0.9; transform: scale(0.6); } 100% { opacity: 0; transform: scale(1.6); } }
@keyframes leer { to { fill: var(--color-accent); } }
@keyframes aparecer { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* --- Entrada de la portada al cargar ------------------------------------------
   Rótulo, bloque y entradilla entran escalonados nada más abrir, con el mismo
   0,15 s entre piezas. */
html.con-movimiento .portada-texto > * { opacity: 0; animation: fade-in 0.45s cubic-bezier(0, 0, 0.5, 1) both; }
html.con-movimiento .portada-texto > :nth-child(1) { animation-delay: 0.1s; }
html.con-movimiento .portada-texto > :nth-child(2) { animation-delay: 0.25s; }
html.con-movimiento .portada-texto > :nth-child(3) { animation-delay: 0.4s; }
html.con-movimiento .portada-texto.reveal { animation: none; opacity: 1; }

@media (max-width: 40rem) {
  .detalle-caja { padding: var(--space-xl) var(--space-lg) var(--space-lg); }
  .pregunta summary { padding: var(--space-md) var(--space-lg); font-size: var(--ap-cuerpo); }
}

/* --- Legibilidad: nada por debajo de 13 px --------------------------------
   El enlace de la barra global iba a 12,8 px y las notas a 12: el mínimo
   cómodo en pantalla es 14 para lo que se lee y 13 para lo que se consulta. */
.notas ol { font-size: 0.8125rem; line-height: 1.45; }

/* ===========================================================================
   TERCERA CAPA: iconos propios, menos texto, contraste sin dudas
   =========================================================================== */

/* --- Contraste que cualquier medidor lee: fondos planos, de la paleta ------- */
:root { --color-papel-tarjeta: #F6F8FC; }   /* el blanco casi puro de las tarjetas sobre papel claro */
.tarjeta { background: var(--color-papel-tarjeta); }
.dato span { font-size: 0.8125rem; opacity: 1; color: color-mix(in oklab, currentColor 82%, transparent); }

/* --- El juego de iconos ---------------------------------------------------- */
.icono { width: 1.5rem; height: 1.5rem; display: block; flex: 0 0 auto; }
.icono-grande { width: 3rem; height: 3rem; }
.ficha-icono {
  position: absolute; inset-inline-start: var(--space-xl); inset-block-start: var(--space-xl);
  width: 1.75rem; height: 1.75rem; color: var(--color-accent-claro);
}
.losa-icono { width: 2rem; height: 2rem; color: var(--color-accent-claro); margin-bottom: var(--space-lg); }
.dato-icono { width: 1.5rem; height: 1.5rem; margin-bottom: var(--space-sm); color: var(--color-accent-2); }
.seccion.clara .dato-icono { color: var(--color-tinta-clara); }

/* --- El recorrido en cuatro pasos ------------------------------------------
   Cuatro columnas, icono grande arriba, tres palabras y una línea. Es lo
   contrario de la lista de pasos con párrafos: lo que hay que entender de un
   vistazo cabe en el icono; el texto sólo lo confirma. */
.flujo-seccion { background: var(--color-paper-2); }
.flujo {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: var(--space-xl) var(--space-lg);
  counter-reset: paso;
}
.paso-flujo { position: relative; padding-top: var(--space-md); border-top: var(--rule) solid var(--color-rule); counter-increment: paso; }
.paso-flujo::before {
  content: counter(paso, decimal-leading-zero);
  position: absolute; inset-block-start: calc(-1 * var(--rule) - 0.6em); inset-inline-start: 0;
  font-family: var(--font-mono); font-size: var(--ap-cuerpo-menor); color: var(--color-accent-claro);
  background: var(--color-paper-2); padding-inline-end: 0.5em;
}
.paso-flujo .icono { color: var(--color-accent-claro); margin: var(--space-md) 0 var(--space-md); }
.paso-flujo h3 {
  margin: 0 0 var(--space-xs); font-family: var(--font-display); font-size: var(--ap-etiqueta);
  font-weight: 600; line-height: 1.166; letter-spacing: 0.009em; color: var(--color-ink);
}
.paso-flujo p { margin: 0; color: var(--color-ink-2); font-size: var(--ap-cuerpo); max-width: 28ch; }

/* Con icono arriba a la izquierda, la cifra de la ficha baja un poco. */
.ficha-cuerpo { padding-top: calc(var(--space-xl) + 2.5rem); }

/* El envoltorio `figure.fig` de la portada tiene que llenar el lienzo: sin
   esto, en pantallas más altas que la foto quedaba una franja lisa debajo. */
.portada-lienzo .fig, .portada-lienzo .figura { height: 100%; }

/* La tarjeta de frase es la oscura de la galería: la regla de fondo claro de
   las tarjetas venía después y se la comía, y dejaba texto claro sobre papel
   claro (1,07:1). Misma especificidad, declarada al final. */
.tarjeta.tarjeta-frase { background: var(--color-paper); }


/* ===========================================================================
   LA PLATAFORMA: portátil y teléfono con capturas reales
   Marcos vectoriales propios (herramientas/mockup.py), a petición expresa:
   la interfaz se enseña dentro de un aparato, como hacen las páginas de
   producto, y no como una captura flotando. El portátil manda; el teléfono se
   le monta encima por la esquina y asoma por debajo de la base, que es el
   gesto clásico de «dos dispositivos, un sistema».
   =========================================================================== */
.plataforma {
  position: relative;
  width: min(100%, var(--ancho));
  margin-inline: auto;
  padding-inline: var(--gutter);
  /* Sitio para que el teléfono sobresalga por debajo del portátil. */
  padding-bottom: clamp(3rem, 9vw, 7.5rem);
}
.plataforma figure { margin: 0; }
.plataforma img { display: block; width: 100%; height: auto; }
.plataforma-pc {
  width: min(100%, 68rem);
  margin-inline: auto;
  filter: drop-shadow(0 30px 50px rgb(15 31 58 / 0.22));
}
.plataforma-telefono {
  position: absolute;
  inset-inline-end: max(var(--gutter), 6%);
  inset-block-end: 0;
  width: clamp(7.5rem, 17%, 12.5rem);
  filter: drop-shadow(0 24px 40px rgb(15 31 58 / 0.38));
}
.plataforma-pie {
  margin-top: var(--space-md);
  text-align: center;
  font-size: var(--ap-cuerpo-menor);
  font-weight: 600;
  color: color-mix(in oklab, var(--color-tinta-clara) 78%, transparent);
}
/* El pie del teléfono cabe mejor bajo el propio teléfono, no bajo el portátil. */
.plataforma-telefono .plataforma-pie { margin-top: var(--space-sm); }

/* Movimiento: el portátil entra con el revelado normal; el teléfono llega
   después y desde más abajo, para que se lea como una segunda pieza. */
@supports (animation-timeline: view()) {
  html.con-movimiento .plataforma-telefono.reveal {
    animation-name: llegar-telefono;
    animation-range: entry 25% cover 50%;
  }
}
@keyframes llegar-telefono {
  from { opacity: 0; transform: translateY(48px); }
  to   { opacity: 1; transform: none; }
}

/* Estrecho: el teléfono ya no cabe encima sin tapar la pantalla; se apila
   debajo, centrado, y la sección deja de reservar sitio abajo. */
@media (max-width: 45.875rem) {
  .plataforma { padding-bottom: 0; }
  .plataforma-pc { filter: drop-shadow(0 16px 28px rgb(15 31 58 / 0.22)); }
  .plataforma-telefono {
    position: static;
    width: min(60%, 14rem);
    margin: var(--space-xl) auto 0;
  }
}

/* Al anclar a una sección, la cabecera (44 px) y la barra local (52 px) son
   fijas y taparían el titular. El margen deja el título a la vista. */
html { scroll-padding-top: calc(var(--alto-barra) + var(--space-lg)); }


/* ===========================================================================
   EL TABLERO EN EL TELÉFONO: tres pantallas reales de la app
   El tríptico de la referencia: tres aparatos iguales, en fila, cada uno con
   su rótulo y una línea. Cada teléfono entra un poco después que el anterior
   (el rango se desplaza con --i), que es lo que hace que la fila se lea como
   una secuencia y no como un bloque que aparece.
   =========================================================================== */
.trio {
  list-style: none; margin: 0;
  width: min(100%, var(--ancho)); margin-inline: auto;
  padding: 0 var(--gutter);
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-xl) var(--space-lg);
}
.trio-pieza { text-align: center; }
.trio-pieza img {
  display: block; width: min(100%, 20rem); height: auto; margin: 0 auto var(--space-lg);
  filter: drop-shadow(0 28px 44px rgb(15 31 58 / 0.32));
}
.trio-pieza h3 {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display); font-size: var(--ap-etiqueta); font-weight: 600;
  line-height: 1.166; color: var(--color-tinta-clara);
}
.trio-pieza p {
  margin: 0 auto; max-width: 26ch;
  font-size: var(--ap-cuerpo-menor);
  color: color-mix(in oklab, var(--color-tinta-clara) 78%, transparent);
}
@supports (animation-timeline: view()) {
  html.con-movimiento .trio-pieza.reveal {
    animation-range: entry calc(5% + var(--i, 0) * 9%) cover calc(24% + var(--i, 0) * 9%);
  }
}
/* Estrecho: la fila se vuelve pista con imán, como la galería de destacados. */
@media (max-width: 45.875rem) {
  .trio {
    display: flex; gap: var(--space-md);
    overflow-x: auto; scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none; overscroll-behavior-x: contain;
  }
  .trio::-webkit-scrollbar { display: none; }
  .trio-pieza { flex: 0 0 min(72vw, 18rem); scroll-snap-align: center; }
  .trio-pieza img { filter: drop-shadow(0 16px 28px rgb(15 31 58 / 0.3)); }
}

/* La tarjeta del tablero en la galería: el teléfono asoma por abajo, cortado
   por la propia tarjeta, como los aparatos en las tarjetas de la referencia. */
.tarjeta:has(.figura-tarjeta-telefono) { overflow: hidden; padding-bottom: 0; }
.figura-tarjeta-telefono {
  display: block; height: 100%; min-height: 0; aspect-ratio: auto; overflow: hidden;
  border: 0; background: transparent;
}
.figura-tarjeta-telefono > img {
  position: static; display: block; margin: 0 auto;
  width: min(72%, 17rem); height: auto; object-fit: unset;
  filter: drop-shadow(0 20px 36px rgb(15 31 58 / 0.3));
}
/* Más grande de lo que cabe, a propósito: la tarjeta lo corta por abajo. */
.figura-tarjeta-telefono > img { width: min(92%, 26rem); }

/* Los teléfonos ahora son la foto de un aparato real (herramientas/mockup_foto.py)
   y traen su propia sombra: la de CSS sobraría. */
.trio-pieza img, .plataforma-telefono, .figura-tarjeta-telefono > img { filter: none; }
@media (max-width: 45.875rem) { .trio-pieza img { filter: none; } }
/* La foto trae aire de sombra a la derecha: un poco más de ancho para que el cuerpo mida lo que medía. */
.trio-pieza img { width: min(100%, 22rem); }

/* Fotos de Pexels (herramientas/mockup_pexels.py): el portátil es una ESCENA
   (mesa, luz de ventana) y va en una loseta con las esquinas de la casa; los
   teléfonos son recortes del aparato y vuelven a llevar sombra de CSS. */
.plataforma-pc { width: min(100%, 72rem); filter: none; }
.plataforma-pc img { border-radius: var(--radio-tarjeta); }
.trio-pieza img, .figura-tarjeta-telefono > img { filter: drop-shadow(0 22px 34px rgb(15 31 58 / 0.28)); }
.plataforma-telefono { filter: drop-shadow(0 22px 34px rgb(15 31 58 / 0.4)); }
@media (max-width: 45.875rem) { .trio-pieza img { filter: drop-shadow(0 14px 22px rgb(15 31 58 / 0.28)); } }


/* ===========================================================================
   EL TABLERO EN EL TELÉFONO, EN FOTOS
   Una escena grande a todo el ancho de la caja y una fila de tres escenas
   verticales (4:5), todas en losetas con las esquinas de la casa. Las fotos
   son de Pexels con la app montada por homografía (mockup_pexels.py).
   =========================================================================== */
.escena { margin: 0; overflow: hidden; border-radius: var(--radio-tarjeta); background: var(--color-papel-tarjeta); }
.escena img { display: block; width: 100%; height: auto; }
.escena-grande { width: min(100%, var(--ancho)); margin: 0 auto var(--space-lg); }
.escenas {
  list-style: none; margin: 0;
  width: min(100%, var(--ancho)); margin-inline: auto;
  padding: 0 var(--gutter);
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-xl) var(--space-lg);
}
.escena-pieza h3 {
  margin: var(--space-md) 0 var(--space-xs);
  font-family: var(--font-display); font-size: var(--ap-etiqueta); font-weight: 600;
  line-height: 1.166; color: var(--color-tinta-clara);
}
.escena-pieza p {
  margin: 0; max-width: 30ch;
  font-size: var(--ap-cuerpo-menor);
  color: color-mix(in oklab, var(--color-tinta-clara) 78%, transparent);
}
@supports (animation-timeline: view()) {
  html.con-movimiento .escena-pieza.reveal {
    animation-range: entry calc(5% + var(--i, 0) * 9%) cover calc(24% + var(--i, 0) * 9%);
  }
}
/* En la caja al 87,5 % la escena grande lleva el mismo margen lateral que el resto. */
.escena-grande { width: min(calc(100% - 2 * var(--gutter)), calc(var(--ancho) - 2 * var(--gutter))); }
@media (max-width: 45.875rem) {
  .escenas {
    display: flex; gap: var(--space-md);
    overflow-x: auto; scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none; overscroll-behavior-x: contain;
  }
  .escenas::-webkit-scrollbar { display: none; }
  .escena-pieza { flex: 0 0 min(76vw, 20rem); scroll-snap-align: center; }
  .escena-grande { border-radius: calc(var(--radio-tarjeta) - 8px); }
}


/* ===========================================================================
   LOS CLIPS: vídeo real donde había un dibujo

   Un clip son dos capas en la misma caja. Debajo el PÓSTER —el primer
   fotograma, imagen de verdad, con sus formatos y sus anchos—, encima el
   vídeo, invisible hasta que `portada.js` consigue arrancarlo. Quien no puede
   reproducir (un códec que falta, el ahorro de batería del teléfono) o quien no
   quiere (pidió menos movimiento) ve exactamente la misma composición, quieta,
   sin caja negra y sin un botón de reproducir roto. No hay «estado de error»:
   el estado de error es la foto.

   El vídeo no lleva el atributo `poster`: esa capa está debajo y es un
   `<picture>` de verdad, que es lo que el atributo no puede ser. Ver el
   comentario de `$clip()` en `index.php`.

   Y NO SE REPITE EN BUCLE. Se reproduce una vez y se queda en el último
   fotograma, como los diecisiete vídeos medidos en `ESTUDIO_APPLE_IPHONE_DUO.md`.
   Un vídeo en bucle detrás de un texto es el gesto de plantilla que esta página
   no hace.
   =========================================================================== */
.figura.con-clip :is(img, video) { position: absolute; inset: 0; }

.figura.con-clip video {
  opacity: 0;
  /* Sólo la opacidad, nunca `transition: all`. 220 ms es el salto de estado de
     la casa y la curva es la de entrada de la referencia. */
  transition: opacity var(--dur-short) cubic-bezier(0, 0, 0.5, 1);
}
/* La pone `portada.js` cuando `play()` ha resuelto de verdad, no cuando se
   pidió: así el cruce a vídeo ocurre con el primer fotograma ya presentado y no
   hay un parpadeo en negro entre las dos capas. */
.figura.con-clip video.clip-listo { opacity: 1; }

/* El cinturón, por si el script fallara: a quien pidió menos movimiento el
   vídeo ni se le compone. `movimiento-forzado` (?mov=1 o el servidor local) lo
   levanta, que es la única forma de revisar los clips desde una máquina con la
   preferencia puesta — la misma puerta que ya usa todo lo demás. */
@media (prefers-reduced-motion: reduce) {
  html:not(.movimiento-forzado) .figura.con-clip video { display: none; }
}

/* La caja del clip de «Así se lee un cruce». La proporción es la del material
   grabado (1,85:1, la del cine), no una inventada por el CSS: así el recorte
   que se ve es el que se decidió al montarlo. */
.figura-clip {
  aspect-ratio: 1.85;
  border: 0;
  border-radius: var(--radio-tarjeta);
  background: var(--color-paper-3);
}
@media (max-width: 45.875rem) {
  /* En un teléfono, 1,85:1 deja una tira de 200 px de alto que no se lee. Se
     abre a 3:2 recortando por el centro, que es donde pasa el corredor. */
  .figura-clip { aspect-ratio: 3 / 2; border-radius: calc(var(--radio-tarjeta) - 8px); }
}

/* El clip va encima del diagrama y con aire de sobra: son dos piezas distintas
   de la misma idea, no una ilustración de la otra. */
.clip-real { width: min(100%, var(--ancho)); margin: 0 auto var(--space-2xl); }
.clip-real .fig { margin: 0; }
.clip-real figcaption {
  margin-top: var(--space-sm);
  text-align: center; font-size: var(--ap-pie);
  color: color-mix(in oklab, var(--color-ink) 62%, transparent);
}


/* ===========================================================================
   LA REJILLA: TODO LO QUE CRUZA

   Seis piezas de tamaños distintos, no seis cuadrados iguales. El tamaño dice
   la jerarquía, igual que en el resto de la página: el cruce ocupa cuatro
   celdas porque es LA idea, y el detalle de la cuna ocupa una porque es una
   nota al pie. Una rejilla regular daría seis piezas de la misma importancia,
   que es justo lo que no son.

   Cinco se mueven y una está quieta —la foto de la cuna—, a propósito: sin un
   punto de reposo, seis vídeos a la vez no son seis vídeos, son ruido.

   Las posiciones van explícitas y no por colocación automática: con `span` y
   auto-flow, cambiar el orden del HTML recoloca la rejilla entera y un día
   aparece un hueco sin que nadie sepa por qué.
   =========================================================================== */
.rejilla {
  list-style: none; margin: 0; padding: 0;
  width: min(100%, var(--ancho)); margin-inline: auto;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: clamp(8rem, 13vw, 14rem);
  gap: var(--space-md);
}
.rejilla-pieza { margin: 0; min-width: 0; }
/* Fila 1: el cruce (2×2) y el ciclista (2×1).
   Fila 2: sigue el cruce, más el montaje y las antenas, los dos de dos filas.
   Fila 3: el cenital y la cuna, debajo del cruce. */
.rejilla-cruce    { grid-area: 1 / 1 / 3 / 3; }
.rejilla-ciclista { grid-area: 1 / 3 / 2 / 5; }
.rejilla-montaje  { grid-area: 2 / 3 / 4 / 4; }
.rejilla-antenas  { grid-area: 2 / 4 / 4 / 5; }
.rejilla-cenital  { grid-area: 3 / 1 / 4 / 2; }
.rejilla-cuna     { grid-area: 3 / 2 / 4 / 3; }

.rejilla .fig { margin: 0; width: 100%; height: 100%; }
.figura-bento {
  width: 100%; height: 100%;
  border: 0; border-radius: var(--radio-tarjeta);
  background: var(--color-paper-3);
}

/* El rótulo de cada pieza: dentro, abajo, sobre un velo que sólo existe donde
   hay letra. Fuera de la caja obligaría a reservar altura y la rejilla dejaría
   de cuadrar. */
.rejilla-pieza figcaption {
  position: absolute; inset-inline: 0; bottom: 0; z-index: var(--z-raised);
  margin: 0; padding: var(--space-lg) var(--space-md) var(--space-sm);
  font-size: var(--ap-cuerpo-menor); font-weight: 600;
  color: var(--color-ink);
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--color-paper) 82%, transparent));
  pointer-events: none;
}
.rejilla-pieza .fig { position: relative; }

/* Con un ratón de verdad, la pieza se levanta al señalarla: es el aviso de que
   eso se puede activar. `transform` en hover va SIEMPRE tras esta puerta, como
   el alzado del botón. En un táctil no existe: allí los clips entran solos. */
@media (hover: hover) and (pointer: fine) {
  .rejilla-pieza .figura-bento {
    transition: transform var(--dur-short) var(--ease-out);
  }
  .rejilla-pieza:hover .figura-bento { transform: scale(1.015); }
}
/* Quien pidió menos movimiento no recibe ni el alzado. */
@media (prefers-reduced-motion: reduce) {
  .rejilla-pieza:hover .figura-bento { transform: none; }
}

/* Dos columnas por debajo de 60rem y el cruce a todo lo ancho: a cuatro
   columnas las piezas de una celda se quedan en sellos ilegibles. */
@media (max-width: 60rem) {
  .rejilla {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: clamp(9rem, 26vw, 13rem);
  }
  .rejilla-cruce    { grid-area: 1 / 1 / 3 / 3; }
  .rejilla-ciclista { grid-area: 3 / 1 / 4 / 3; }
  .rejilla-montaje  { grid-area: 4 / 1 / 6 / 2; }
  .rejilla-antenas  { grid-area: 4 / 2 / 5 / 3; }
  .rejilla-cenital  { grid-area: 5 / 2 / 6 / 3; }
  .rejilla-cuna     { grid-area: 6 / 1 / 7 / 3; }
}
@media (max-width: 45.875rem) {
  .rejilla { gap: var(--space-sm); }
  .figura-bento { border-radius: calc(var(--radio-tarjeta) - 10px); }
}


/* ===========================================================================
   EL TALLER: LOS RENDERS

   El otro registro. Todo lo demás en esta página está rodado en monte, con
   barro y luz de verdad; esto es el mismo arco dibujado, y se enseña como lo
   que es. No compiten: la foto demuestra que existe y funciona, el render
   explica cómo está hecho. Una sola de las dos deja la mitad de la historia.

   LOS RENDERS NO LLEVAN CAJA. Vienen con transparencia de verdad (alfa 0 en el
   borde, comprobado), así que se apoyan directamente sobre el marino de la
   página, sin recuadro, sin fondo y sin sombra. Es el registro de producto
   recortado, y es EXACTAMENTE lo contrario del tratamiento de las fotos, que
   van todas en loseta con esquinas de 28 px. Esa diferencia es la que hace que
   se lean como dos capítulos y no como un revoltijo.

   Y `object-fit: contain`, no `cover`: a un objeto recortado no se le corta un
   pie ni una antena para cuadrar una caja.
   =========================================================================== */

.figura-render {
  width: 100%;
  border: 0;
  background: transparent;    /* pisa el `--color-paper-3` de `.figura` */
}
.figura-render :is(img, video) { object-fit: contain; height: auto; }

/* Los renders NO tienen sección propia: dedicarle una entera al tripié le daba
   un peso que no le toca. Van repartidos, cada uno donde explica algo que la
   fotografía de ese sitio no puede explicar.

   COMPOSICIÓN COMPUESTA: el render a un lado, el texto al otro.

   Es la forma que pide un objeto recortado, y la razón de renderizarlo desde
   ángulos distintos en vez de uno de catálogo. Un render centrado y solo
   desperdicia lo único que lo separa de una foto: que NO TIENE FONDO, así que
   puede salirse de la caja e invadir el margen. Cortado por el canto izquierdo
   se lee como una pieza entrando en cuadro; centrado, como una lámina de manual.

   Va a la izquierda porque el objeto entra desde ese lado y «apunta» a la
   derecha: la vista sigue al objeto y aterriza en el texto. Al revés, empuja la
   mirada fuera de la página. */
.compuesta {
  width: min(100%, var(--ancho));
  margin: var(--space-2xl) auto 0;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: var(--space-2xl);
  align-items: center;
}
.compuesta .fig { margin: 0; }
/* El render sangra por el canto izquierdo hasta el borde de la ventana. Es lo
   que lo hace ver grande sin robarle columna al texto. */
.compuesta-pieza { margin-left: calc(-1 * var(--gutter)); }
.compuesta-texto h3 {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--ap-titular-seccion);
  font-weight: var(--peso-titular);
  line-height: 1.083; letter-spacing: -0.003em;
  color: var(--color-ink);
}
.compuesta-texto p {
  margin: 0; max-width: 40ch;
  font-size: var(--ap-cuerpo); color: var(--color-ink-2);
}
.compuesta-datos {
  list-style: none; margin: var(--space-xl) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-md) var(--space-2xl);
}
.compuesta-datos b {
  display: block;
  font-family: var(--font-mono); font-size: var(--ap-tarjeta);
  font-weight: 500; color: var(--color-accent-claro);
}
.compuesta-datos span { font-size: var(--ap-pie); color: var(--color-ink-2); }

/* La versión espejada: texto a la izquierda y pieza sangrando por la DERECHA.
   Se alterna con la normal para que dos composiciones seguidas en la misma
   página no se lean como una plantilla repetida. */
.compuesta-inversa { grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); }
.compuesta-inversa .compuesta-pieza {
  margin-left: 0;
  margin-right: calc(-1 * var(--gutter));
}

@media (max-width: 60rem) {
  /* En una columna el objeto va primero y el texto debajo, y sangra por los dos
     cantos: a lo ancho se ve mejor que encajonado en media pantalla. */
  .compuesta { grid-template-columns: 1fr; gap: var(--space-lg); }
  .compuesta-pieza { margin-inline: calc(-1 * var(--gutter)); }
  .compuesta-inversa { grid-template-columns: 1fr; }
  .compuesta-inversa .compuesta-pieza { margin-inline: calc(-1 * var(--gutter)); }
  /* La pieza siempre primero, aunque en el HTML vaya detrás del texto: en
     vertical la imagen abre y el texto explica, nunca al revés. */
  .compuesta-inversa .compuesta-pieza { order: -1; }
}

/* Las tres vistas de «así se lee un cruce». Son renders y no fotos porque esto
   NO se puede fotografiar: el alcance de una antena no se ve. */
.cruce-vistas {
  list-style: none; margin: var(--space-2xl) auto 0; padding: 0;
  width: min(100%, var(--ancho));
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-xl) var(--space-lg);
}
.cruce-vistas .figura-render { aspect-ratio: 4 / 3; }
.cruce-vistas .figura-render :is(img, video) { height: 100%; }
.cruce-vistas h3 {
  margin: var(--space-sm) 0 var(--space-3xs);
  font-family: var(--font-display); font-size: var(--ap-etiqueta);
  font-weight: 600; line-height: 1.166; color: var(--color-ink);
}
.cruce-vistas p {
  margin: 0; max-width: 32ch;
  font-size: var(--ap-cuerpo-menor); color: var(--color-ink-2);
}

/* Preguntas: el aparato a un lado, las respuestas al otro. */
.preguntas-caja {
  display: grid;
  grid-template-columns: minmax(0, 18rem) minmax(0, 1fr);
  gap: var(--space-2xl);
  align-items: start;
}
.preguntas-pieza { margin: 0; position: sticky; top: 8rem; }
@media (max-width: 60rem) {
  /* En una columna, una imagen entre el titular y las respuestas sólo alarga el
     camino hasta lo que se venía a leer. Se cae. */
  .preguntas-caja { display: block; }
  .preguntas-pieza { display: none; }
}


/* ===========================================================================
   EL CRONÓMETRO, CON EL CAMINO DETRÁS

   Era una pantalla entera de azul plano con una línea de cifras. Ahora lleva
   detrás el vuelo a ras de suelo, muy velado: el cronómetro sigue siendo lo
   único que se lee, y el fondo sólo aporta que esto ocurre en un camino y no
   en un estudio. Mismo patrón exacto que la portada (`.portada-lienzo`), sin
   inventar nada nuevo.
   =========================================================================== */
.reloj { position: relative; overflow: hidden; }
.reloj-lienzo { position: absolute; inset: 0; z-index: var(--z-base); }
.reloj-lienzo .fig { margin: 0; width: 100%; height: 100%; }
.reloj-lienzo .figura { width: 100%; height: 100%; border: 0; }
/* El velo. Más cerrado que el de la portada porque aquí lo que va encima son
   cifras finas, no un bloque de oro: si el fondo respira, no se leen. */
.reloj-lienzo::after {
  content: ""; position: absolute; inset: 0;
  background: color-mix(in srgb, var(--color-paper) 86%, transparent);
}
.reloj > .contenedor { position: relative; z-index: var(--z-raised); }

/* --- Las disciplinas, en una tira ------------------------------------------
   Ocho palabras separadas por una hairline vertical. Ni tarjetas ni iconos: la
   pregunta que contestan («¿esto me sirve a mí?») se responde de un vistazo, y
   ocho cajas con su icono la convertirían en una lectura de treinta segundos.
   El separador va en `::before` de cada hermano y no como `border-left`, así el
   primero de cada línea nunca arrastra una raya suelta al envolver. */
.disciplinas {
  list-style: none;
  margin: var(--space-lg) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  max-width: 60ch;
  font-family: var(--font-display);
  font-size: var(--ap-cuerpo);
  color: var(--color-ink-2);
}
.disciplinas > li {
  display: inline-flex; align-items: center;
  padding: 0.34em 0.85em;
  border: var(--rule) solid var(--color-rule-2);
  border-radius: var(--radio-pildora, 980px);
  line-height: 1.1;
}
/* La tira vive en una sección CLARA: hereda la tinta oscura de la sección, no
   el gris claro de las bajadas del marino. Sin esto el contraste cae a 1.5 y
   el texto desaparece — medido, no supuesto. */
.seccion.clara .disciplinas { color: color-mix(in oklab, var(--color-tinta-clara) 82%, transparent); }
.seccion.clara .disciplinas > li { border-color: color-mix(in oklab, var(--color-tinta-clara) 22%, transparent); }

@media (max-width: 40rem) {
  .disciplinas { font-size: var(--ap-cuerpo-menor); }

}

/* ===========================================================================
   COMPOSICIONES CON RENDERS
   Los renders salen con alfa, así que no necesitan caja: se apoyan sobre el
   marino. `figura-suelta` es justo eso — ni fondo, ni borde, ni recorte de
   esquinas, ni `object-fit: cover` que los recortaría por donde no toca. Una
   foto necesita marco porque trae su propio fondo; un render, no.
   =========================================================================== */
.figura-suelta,
.figura-suelta .figura {
  background: transparent;
  border: 0;
  border-radius: 0;
  overflow: visible;
  aspect-ratio: auto;
}
.figura-suelta img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  object-fit: contain;
  /* La sombra va DEBAJO y muy difusa: sin ella un objeto recortado flota como
     una calcomanía. Con ella, se apoya. */
  filter: drop-shadow(0 18px 28px rgb(0 0 0 / 0.38));
}

/* --- 4b · El equipo, A SANGRE ---------------------------------------------
   El render deja de ser una ilustración dentro de su columna y pasa a ser el
   suelo de la sección: ocupa el 54 % izquierdo de punta a punta, lo recorta su
   propia caja, y la pata en primer plano no cabe entera a propósito. Ese
   recorte es lo que mete a quien mira DENTRO de la escena, en vez de dejarlo
   delante de una foto de catálogo.

   El primer intento lo hizo con `margin-inline-start: calc(50% - 50vw)` sobre
   la columna y salió mal: la columna conserva su ancho y sólo se desplaza, así
   que el objeto se iba por el canto y dejaba medio lienzo vacío. Lo que
   funciona es que la caja OCUPE el borde y recorte ella: `object-fit: cover`
   con `object-position` puesto donde vive lo que interesa —abajo a la
   izquierda, la pata— y `overflow: clip` para que el resto se pierda fuera.

   `clip` y no `hidden`: hidden abre un contexto de scroll y rompe el `sticky`
   de la cabecera. */
.equipo {
  padding-block: 0;
  overflow-x: clip;
}
.equipo-escena {
  display: grid;
  grid-template-columns: 56% 44%;
  align-items: stretch;
  min-block-size: calc(var(--alto-util) * 0.68);
}
.equipo-render {
  grid-column: 1;
  overflow: clip;
  min-width: 0;
  pointer-events: none;
}
.equipo-render .fig,
.equipo-render .figura { block-size: 100%; margin: 0; }
/* `contain` y no `cover`: con cover la caja se comía la pata y el trípode del
   fondo, y el plano dejaba de entenderse. Entero y apoyado en la base, el
   recorte lo hace el borde de la pantalla —que es donde debe hacerlo— y no la
   caja. */
.equipo-render img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  object-position: center bottom;
}
.equipo-texto {
  grid-column: 2;
  align-self: center;
  min-width: 0;
  /* El texto se alinea con el contenedor del resto de la página: el hueco de
     la derecha es el mismo que el de cualquier otra sección. */
  padding-inline: var(--space-2xl) max(var(--space-xl), calc((100vw - var(--ancho)) / 2));
  padding-block: var(--space-2xl);
}
.equipo-texto .titulo-seccion { margin-bottom: var(--space-md); }
.equipo-datos {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--space-md);
}
.equipo-datos li { display: grid; grid-template-columns: 4.5rem 1fr; gap: var(--space-md); align-items: baseline; }
.equipo-datos b {
  font-family: var(--font-display); font-size: var(--ap-antetitulo);
  font-weight: 600; color: var(--color-accent); letter-spacing: -0.01em;
}
.equipo-datos span { font-size: var(--ap-cuerpo-menor); color: var(--color-ink-2); line-height: 1.4; }

@media (max-width: 60rem) {
  .equipo-escena { grid-template-columns: 1fr; min-block-size: 0; }
  .equipo-render { grid-row: 2; block-size: 48svh; }
  .equipo-texto {
    grid-row: 1;
    padding-inline: var(--space-lg);
    padding-block: var(--space-2xl) var(--space-lg);
  }
}

/* ===========================================================================
   UNA SECCIÓN, UNA PANTALLA
   Medido en la página real: #tablero ocupaba 2,41 pantallas y #destacados
   2,47. Dos scrolls para leer una sola idea es justo lo que rompe el ritmo de
   «una idea por pantalla» que la página dice seguir. Aquí no se recorta
   contenido: se acota lo que crece sin límite, que son los MEDIOS. El texto
   nunca se toca — si algo tiene que ceder, cede la foto.

   `svh` y no `vh`: en un móvil la barra del navegador aparece y desaparece, y
   con `vh` la sección se pasa de largo justo cuando la barra está visible. */
:root { --alto-util: calc(100svh - var(--alto-barra)); }

@media (min-width: 60rem) and (min-height: 40rem) {
  /* El aire entre secciones baja: con 144 px arriba y 224 abajo, el padding
     solo ya se comía media pantalla. */
  .seccion { padding-block: clamp(3rem, 5.5vw, 5.5rem) clamp(3.5rem, 6vw, 6rem); }

  /* El tablero: la foto del teléfono mandaba sobre la sección entera. */
  #tablero .figura-3x2,
  #tablero .figura { max-block-size: calc(var(--alto-util) * 0.52); }
  #tablero .figura img { block-size: 100%; object-fit: contain; }

  /* Los destacados son un carrusel horizontal: su altura la fija la tarjeta. */
  /* Ojo: la tarjeta traía `min-height: clamp(20rem, 66dvh, 44rem)`, y en CSS
     el mínimo gana al máximo. Sin tocar el mínimo, el límite no hacía nada. */
  .tarjeta { min-height: calc(var(--alto-util) * 0.52); max-block-size: calc(var(--alto-util) * 0.56); }
  .tarjeta .figura-tarjeta { max-block-size: calc(var(--alto-util) * 0.34); }


  /* Las fichas verticales: 744/904 es casi un retrato; a 3/4 caben. */
  .ficha-cuerpo { aspect-ratio: 4 / 3.4; }
}

/* --- 1a · El tablero, en dos columnas --------------------------------------
   La escena grande a la izquierda, el texto y las tres piezas a la derecha.
   Las piezas pasan de tarjeta con foto vertical a FILA con miniatura: la foto
   sigue estando, pero deja de mandar sobre la altura de la sección. */
.tablero-rejilla {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: var(--space-2xl);
  align-items: center;
}
.tablero-rejilla > .escena-grande { margin: 0; min-width: 0; }
.tablero-texto { min-width: 0; }
.tablero-texto .cabecera-seccion { margin-bottom: var(--space-xl); }
.escenas-lista {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--space-lg);
}
.escenas-lista .escena-pieza {
  display: grid;
  grid-template-columns: 4.5rem 1fr;
  gap: var(--space-lg);
  align-items: center;
  text-align: start;
}
.escenas-lista .escena-pieza .escena { margin: 0; }
.escenas-lista .escena-pieza img {
  inline-size: 4.5rem; block-size: 4.5rem;
  object-fit: cover; border-radius: calc(var(--radio-tarjeta) / 2.2);
}
.escenas-lista .escena-pieza h3 { margin: 0 0 0.15em; font-size: var(--ap-cuerpo); }
.escenas-lista .escena-pieza p  { margin: 0; font-size: var(--ap-cuerpo-menor); line-height: 1.4; }

@media (max-width: 60rem) {
  .tablero-rejilla { grid-template-columns: 1fr; gap: var(--space-xl); }
  .escenas-lista .escena-pieza { grid-template-columns: 3.5rem 1fr; gap: var(--space-md); }
  .escenas-lista .escena-pieza img { inline-size: 3.5rem; block-size: 3.5rem; }
}

/* --- 7 · La salida masiva, cortada por abajo -------------------------------
   El pelotón no entra en una caja: entra en la sección. Se sangra hasta los
   dos cantos, se escala por encima del ancho de la columna y lo corta el borde
   inferior, de modo que los corredores parecen seguir fuera de la página. El
   texto queda arriba a la izquierda, sobre el aire que deja el render.

   Requiere `overflow-x: clip` en la sección: sin él, 72vw sangrados abren
   barra horizontal en cuanto la ventana se estrecha. */
.compuesta-sangrada {
  position: relative;
  overflow-x: clip;
  align-items: center;
}
.compuesta-sangrada .compuesta-texto {
  position: relative;
  z-index: 1;
  padding-block-end: 0;
}
.compuesta-sangrada .compuesta-pieza { margin: 0; min-width: 0; }
/* El pelotón se ve ENTERO. Antes iba a 72vw y con margen negativo abajo: la
   idea era que la carrera siguiera fuera del encuadre, pero en la práctica lo
   que se lee es una imagen cortada, no una escena que continúa. Ancho completo
   de su columna y nada de recortes. */
.compuesta-sangrada .compuesta-pieza img {
  inline-size: 124%;
  max-inline-size: none;
  block-size: auto;
  filter: drop-shadow(0 22px 36px rgb(0 0 0 / 0.42));
}
@media (max-width: 60rem) {
  .compuesta-sangrada .compuesta-pieza img { inline-size: 100%; }
  .compuesta-sangrada .compuesta-texto { padding-block-end: var(--space-lg); }
}
/* El render sangrado no lleva caja: ni fondo, ni borde, ni esquinas. Sin esto
   asoma el `--color-paper-3` de `.figura` como un rectángulo más claro detrás
   del pelotón, y delata que hay una caja donde no debería haberla. */
.compuesta-sangrada :is(.figura, .fig, .compuesta-pieza) {
  background: transparent;
  border: 0;
  border-radius: 0;
  overflow: visible;
}

/* --- 4 · La banda del arco -------------------------------------------------
   Cuatro planos a una sola altura y anchos distintos (2 · 1 · 1,4 · 1),
   sangrados hasta los dos cantos. El ritmo irregular es lo que la separa de
   una cuadrícula: con cuatro columnas iguales esto sería un catálogo.

   La altura la fija la banda, no cada pieza, así que ninguna se corta por su
   cuenta ni se derrama sobre la sección siguiente — que es lo que pasaba con
   el tope de altura que llevaba la rejilla anterior. */
.banda {
  display: grid;
  grid-template-columns: 2fr 1fr 1.4fr 1fr;
  gap: var(--rule-2, 2px);
  margin-inline: calc(var(--sangria, 0px) * -1);
  margin-block-start: var(--space-xl);
  block-size: clamp(16rem, 42svh, 24rem);
  overflow: clip;
}
.banda-pieza { margin: 0; min-width: 0; position: relative; block-size: 100%; }
.banda-pieza :is(.fig, .figura) { block-size: 100%; margin: 0; border: 0; border-radius: 0; }
.banda-pieza :is(img, video) { inline-size: 100%; block-size: 100%; object-fit: cover; }
/* El pie de cada plano, abajo a la izquierda, sobre una sombra propia para que
   se lea encima de cualquier fotograma. */
.banda-pieza figcaption {
  position: absolute; inset-block-end: 0; inset-inline: 0;
  padding: var(--space-lg) var(--space-md) var(--space-md);
  font-size: var(--ap-cuerpo-menor); font-weight: 600; color: #fff;
  background: linear-gradient(to top, rgb(0 0 0 / 0.55), transparent);
}
@media (max-width: 60rem) {
  /* En vertical la banda se convierte en un carrete que se arrastra: cuatro
     columnas a 375 px darían cuatro rendijas. */
  .banda {
    grid-template-columns: repeat(4, 72vw);
    block-size: 32svh;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }
  .banda-pieza { scroll-snap-align: start; }
}

/* --- 1a · LA APP, CONTADA A SCROLL ----------------------------------------
   Tres pasos. En cada uno, la pantalla se queda pegada (`sticky`) mientras su
   texto pasa por al lado, y se va cuando entra la siguiente. Es el único sitio
   de la página donde una sección ocupa más de una pantalla a propósito: aquí
   el scroll no repite contenido, lo avanza.

   Sin JavaScript y sin líneas de tiempo de scroll: `position: sticky` lo
   entiende cualquier navegador desde 2017, y si algo falla el resultado es
   una lista de tres pantallas con su texto, que sigue leyéndose.

   OJO: la clase `.paso` ya existía en esta hoja (venía del flujo antiguo) y
   pintaba sus h3 en blanco. Por eso todo aquí lleva el prefijo `relato-`: dos
   componentes distintos con el mismo nombre de clase es un color heredado que
   aparece semanas después y cuesta media hora encontrar.

   Los pasos alternan lado —impar el teléfono a la izquierda, par a la
   derecha—: tres bloques idénticos en fila serían una plantilla. */
.relato { display: grid; gap: 0; }
.relato-paso {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2xl);
  align-items: start;
  min-block-size: min(70svh, 34rem);
  padding-block: var(--space-xl);
}
.relato-paso:nth-child(even) .relato-visual { order: 2; }
.relato-visual {
  position: sticky;
  /* Justo debajo de la barra, con aire. */
  top: calc(var(--alto-barra) + var(--space-xl));
  display: grid;
  place-items: center;
  block-size: fit-content;
}
.relato-visual .tel { margin: 0; inline-size: min(100%, 21rem); }
.relato-visual img {
  display: block; inline-size: 100%; block-size: auto;
  filter: drop-shadow(0 28px 38px rgb(0 0 0 / 0.40));
}
.relato-texto {
  align-self: center;
  max-inline-size: 34rem;
  padding-block: var(--space-2xl);
}
/* El número es la pieza gráfica del paso: grande, en oro, y detrás del titular
   como una marca de agua. Ni icono ni viñeta. */
.relato-num {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(3.5rem, 7vw, 6rem);
  font-weight: 600;
  line-height: 0.8;
  color: color-mix(in oklab, var(--color-accent) 42%, transparent);
  margin-bottom: var(--space-sm);
}
.relato-titular {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--ap-titular-seccion);
  line-height: 1.08;
  letter-spacing: -0.003em;
}
.relato-cuerpo { margin: 0; max-inline-size: 42ch; }

@media (max-width: 60rem) {
  /* En vertical el sticky se cancela: el teléfono va arriba de su texto y la
     sección se lee como tres bloques. Un sticky en una columna estrecha deja
     el texto tapado a medio scroll. */
  .relato-paso {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
    min-block-size: 0;
    padding-block: var(--space-xl) var(--space-2xl);
  }
  .relato-paso:nth-child(even) .relato-visual { order: 0; }
  .relato-visual { position: static; }
  .relato-visual .tel { inline-size: min(62vw, 14rem); }
  .relato-texto { padding-block: 0; }
}
/* El número del paso en oro puro sobre papel claro se lava (2,1:1). Mezclado
   con la tinta de la sección conserva el oro y gana cuerpo. Es decorativo
   —`aria-hidden`—, pero decorativo no es excusa para que no se vea. */
.seccion.clara .relato-num { color: color-mix(in oklab, var(--color-accent) 58%, var(--color-tinta-clara)); }

/* --- 6b · DOS VISTAS DE LO MISMO ------------------------------------------
   El arco desde el aire arriba a la izquierda, la pantalla donde eso aterriza
   abajo a la derecha, y el texto en el hueco que dejan. Se solapan: la mesa
   sube sobre el campo un 8 % para que la diagonal se lea como una sola idea
   en dos tiempos y no como dos capturas puestas en fila.

   Las dos piezas sangran, cada una por su canto. La rotación es de medio
   grado largo: lo justo para que no parezcan pegadas a la rejilla, no tanto
   como para que parezca un error. */
.dosvistas {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  align-items: start;
  margin-inline: calc(var(--sangria, 0px) * -1);
  /* `clip` sólo en X: en Y tiene que dejar salir el cenital hacia la sección
     de arriba. Hay que declarar el eje Y visible de forma explícita, o el
     navegador convierte el otro eje en `auto` y aparece scroll. */
  overflow-x: clip;
  overflow-y: visible;
}
.vista { margin: 0; position: relative; }
.vista img { display: block; inline-size: 100%; block-size: auto; }
.vista-campo {
  grid-column: 1 / 9;
  grid-row: 1;
  /* Corrido a la izquierda hasta que el CONTENIDO del render —no su caja—
     termina antes del teléfono. Medido sobre el propio PNG: la cuarta parte
     derecha de la imagen es aire, así que buena parte de este desplazamiento
     no se lleva nada por delante; lo que se pierde por el canto izquierdo es
     un trozo del primer corredor, y así la columna de la derecha queda sobre
     papel limpio en vez de sobre el arco. */
  margin-inline-start: -46%;
  /* NO sube a la sección de arriba. Con el render vacío daba igual —por esa
     franja no pasaba nada—, pero con los seis corredores dentro, el trozo que
     sobresalía caía sobre el marino de la sección anterior y los cortaba por
     la cintura. El render entero, dentro de su sección. */
  margin-block-start: 0;
  transform: rotate(-1.5deg);
  /* Sobre la sección que invade, pero POR DEBAJO de las cifras: el render
     pasa por detrás de las tarjetas en vez de chocar con ellas. */
  z-index: 1;
}
.vista-campo :is(.fig, .figura) { block-size: auto; margin: 0; }
/* El cenital es CUADRADO: al 100 % de su columna se iba a 1150 px de alto y
   la sección se comía dos pantallas y media. Se limita por ALTURA y se deja
   que el ancho se ajuste solo — así sigue viéndose entero, sin un recorte. */
.vista-campo img {
  block-size: auto;
  /* Más grande que su propia columna: lo que sobra se pierde por el canto.
     Mismo tamaño que tenía el render sin gente, a petición. */
  inline-size: 126%;
  max-inline-size: none;
  max-block-size: none;
  filter: drop-shadow(0 24px 34px rgb(0 0 0 / 0.20));
}
/* --- La pila de la derecha ------------------------------------------------
   Cuatro piezas, una debajo de otra, centradas contra el render: titular,
   aparatos, los tres tipos de salida y las dos garantías. Cada una dice una
   cosa y se acabó; el argumento lo lleva la imagen de al lado. */
.mesa-pila {
  grid-column: 7 / 13;
  grid-row: 1;
  /* Anclada ABAJO, no centrada. La mitad alta de esa columna la ocupa la
     antena del render y ahí el titular daba 2,55:1 contra el blanco del panel
     —por debajo del 3:1 que pide un texto grande—. Pegada al pie del render
     cae sobre papel limpio. */
  align-self: end;
  margin-block-end: var(--space-2xl);
  display: flex;
  flex-direction: column;
  gap: clamp(var(--space-sm), 1.6vh, var(--space-lg));
  z-index: 3;
  padding-inline-end: max(var(--space-lg), calc((100vw - var(--ancho)) / 2));
  padding-block: var(--space-lg);
}
/* Los bloques de TEXTO arrancan 150 px más a la derecha que los aparatos: por
   el canto izquierdo de esta columna sube la pata del tripié derecho del
   render, y ahí el titular caía sobre gris a 1,55:1. El portátil y el teléfono
   no se mueven —esos siguen donde estaban—; sólo el texto se aparta. */
.mesa-intro,
.tira,
.pares { margin-inline-start: clamp(0px, 10vw, 150px); }
.mesa-intro { display: block; }
.mesa-intro .bajada { max-inline-size: 40ch; margin-block-start: var(--space-sm); }

/* La tira de salidas y las dos garantías.
   Tercer intento y el que se queda: los tres tipos en UNA línea, como
   etiquetas separadas por puntos —ocupan una franja, no un bloque—, y todo el
   peso visual en las dos cifras, que es lo que de verdad hay que recordar.
   Antes fueron cajas con fondo y filetes de color; las dos versiones hacían
   competir a los tres nombres con los ceros, y los ceros son el argumento. */
.tira { display: grid; gap: var(--space-xs); }
.tira-rotulo,
.tira-pie { margin: 0; }
.tira-rotulo {
  font-family: var(--font-display);
  font-size: var(--ap-cuerpo-menor);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  /* A 14 px el oro de marca se queda en 4,2:1 y el mínimo para texto normal
     es 4,5; éste va un punto más oscuro. */
  color: #7A5D11;
}
.tira-piezas {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15em 0.55em;
  font-family: var(--font-display);
  font-size: var(--ap-tarjeta);
  line-height: 1.15;
  color: var(--color-tinta-clara);
}
/* El punto separador es decoración: se dibuja, no se escribe, para que un
   lector de pantalla lea tres nombres y no una frase con puntos sueltos. */
.tira-piezas li + li::before {
  content: "·";
  margin-inline-end: 0.55em;
  color: color-mix(in oklab, var(--color-tinta-clara) 45%, transparent);
}
.tira-pie {
  font-size: var(--ap-cuerpo-menor);
  line-height: 1.35;
  max-inline-size: 52ch;
  color: color-mix(in oklab, var(--color-tinta-clara) 74%, transparent);
}

/* Las dos garantías: el número a tamaño de titular y dos palabras debajo. */
.pares {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg);
}
.pares li {
  display: grid;
  /* el «+» pegado a su rótulo, no empujado al canto de la columna */
  grid-template-columns: auto auto;
  justify-content: start;
  align-items: center;
  column-gap: var(--space-sm);
}
.par-cifra {
  grid-column: 1 / -1;
  margin: 0 0 0.05em;
  font-family: var(--font-display);
  font-size: clamp(3rem, 4.6vw, 4.5rem);
  line-height: 0.8;
  color: var(--color-accent-tinta);
}
.par-titular {
  margin: 0;
  font-size: var(--ap-cuerpo);
  line-height: 1.25;
  font-weight: 400;
  color: var(--color-tinta-clara);
}
/* El «+» viene posicionado en absoluto de las tarjetas, donde flota sobre una
   caja con sitio de sobra. Aquí no hay caja: si se queda absoluto se planta
   encima del texto. Vuelve al flujo, en su propia columna. */
.pares .mas {
  position: static;
  inline-size: 1.75rem; block-size: 1.75rem;
  font-size: 1.1rem;
  align-self: center;
}

/* Los dos aparatos, EN FILA y sin solaparse. Montar el teléfono sobre la
   esquina del portátil los apelotonaba y obligaba a encoger los dos; así cada
   uno se ve entero, apoyados en la misma línea de base, como en una mesa. */
.vista-mesa {
  position: relative;
  perspective: 1600px;
  display: grid;
  grid-template-columns: 22% minmax(0, 1fr);
  align-items: end;
  column-gap: var(--space-lg);
  transform: none;
}
.vista-mesa > img:first-of-type {
  display: block;
  inline-size: 100%;
  transform: rotateY(-6deg) rotateX(2deg);
  transform-origin: 60% 70%;
  filter: drop-shadow(-14px 24px 36px rgb(0 0 0 / 0.26));
}
/* El teléfono del relevo, montado sobre la esquina del portátil.
   `.vista img` (0,1,1) le ganaba a `.vista-telefono` (0,1,0) y el teléfono se
   iba al 100 % del portátil: 1083 px en vez de 257. Con el padre delante, la
   cuenta se invierte. */
.vista-mesa .vista-telefono {
  /* Primera columna de la fila, no encima del portátil. */
  order: -1;
  position: static;
  inline-size: 100%;
  block-size: auto;
  transform: rotateY(6deg);
  transform-origin: 40% 70%;
  filter: drop-shadow(-8px 18px 24px rgb(0 0 0 / 0.26));
}
.vista-pie {
  position: absolute;
  inset-block-start: 100%;
  inset-inline-start: var(--space-md);
  margin-block-start: var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--color-tinta-clara) 62%, transparent);
}
/* El pie del portátil se posicionaba justo donde arranca el rótulo de las
   salidas y los dos se leían en la misma línea. Sube al canto superior de la
   figura, que ahí no hay nada. */
.vista-mesa .vista-pie {
  inset-block-start: auto;
  inset-block-end: calc(100% + var(--space-xs));
  inset-inline-start: auto;
  inset-inline-end: var(--space-xl);
  margin: 0;
}
/* El campo recorta por los cantos, así que su etiqueta va DENTRO: fuera se la
   comía el propio recorte. */
/* La etiqueta se ancla contra el canto de la PANTALLA, no contra el render:
   como el cenital sangra un 16 % hacia la izquierda, su esquina cae fuera y la
   etiqueta se perdía a medias por el borde. */
.vista-campo .vista-pie {
  inset-block-start: auto;
  inset-block-end: var(--space-md);
  /* La etiqueta se ancla contra el canto de la PANTALLA, no contra el render:
     la figura sangra un 34 % hacia la izquierda y con el pie pegado a ella se
     salía del cuadro («EN EL SUELO» se leía «SUELO»). */
  inset-inline-start: calc(46% + var(--space-lg));
  margin: 0;
  color: color-mix(in oklab, var(--color-tinta-clara) 72%, transparent);
}

@media (max-width: 60rem) {
  /* En vertical el solape se deshace: dos piezas montadas en 375 px tapan la
     una a la otra y no se entiende ninguna. */
  .dosvistas { grid-template-columns: 1fr; gap: var(--space-2xl); }
  /* En vertical la pila baja del render y todo va a una columna. */
  .mesa-pila { grid-column: 1; grid-row: auto; padding-inline: var(--space-lg); }
  .tira-piezas { grid-template-columns: 1fr; gap: var(--space-sm); }
  .pares { grid-template-columns: 1fr; gap: var(--space-md); }
  .vista-campo, .vista-mesa {
    grid-column: 1; grid-row: auto; margin-block-start: 0;
  }
  /* En una columna estrecha el teléfono al 22 % sale de sello de correos: se
     le da más sitio y el portátil se queda con el resto. */
  .vista-mesa { grid-template-columns: 27% minmax(0, 1fr); column-gap: var(--space-md); }
  .vista-mesa .vista-telefono { inline-size: 22%; left: 2%; bottom: -8%; }
  .vista-pie { font-size: 0.6875rem; }
}

/* --- 2 · La pulsera manda --------------------------------------------------
   Dos reglas del sistema contadas sobre el plano que faltaba: el contrapicado
   desde el suelo. El render es vertical y aquí eso es la gracia — ocupa la
   columna entera de arriba abajo y se corta por el canto derecho, así que la
   antena se lee como se ve desde donde pasa el corredor: desde abajo.

   Las reglas van numeradas con hairline y no con iconos: son normas, no
   funciones, y un icono aquí sólo añadiría ruido. */
.regla-seccion { overflow-x: clip; padding-block: 0; }
.regla-rejilla {
  display: grid;
  grid-template-columns: 1fr 46vw;
  align-items: center;
  gap: var(--space-2xl);
  min-block-size: calc(var(--alto-util) * 1.0);
}
.regla-texto {
  padding-inline-start: max(var(--space-xl), calc((100vw - var(--ancho)) / 2));
  padding-block: var(--space-2xl);
  max-inline-size: 40rem;
}
.reglas { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-xl); }
.regla { padding-block-start: var(--space-lg); border-block-start: var(--rule) solid var(--color-rule); }
.regla h3 {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display);
  font-size: var(--ap-antetitulo);
  font-weight: 600;
  line-height: 1.15;
  color: var(--color-ink);
}
.regla p { margin: 0; max-inline-size: 46ch; color: var(--color-ink-2); }
/* La pieza toca los dos bordes de la sección: arriba y abajo también. */
/* Mismo criterio que la vista aérea: la pieza manda sobre la rejilla. Sale un
   28 % por encima de su columna y lo que sobra se pierde por el canto derecho,
   que es el único recorte que vale — el del borde de la pantalla, no el de una
   caja que parte el objeto por la mitad. */
.regla-pieza {
  margin: 0; min-width: 0; overflow: clip;
  align-self: stretch;
  display: grid;
  align-content: center;
}
.regla-pieza :is(.fig, .figura) { margin: 0; }
.regla-pieza img {
  inline-size: 128%;
  max-inline-size: none;
  block-size: auto;
  object-fit: contain;
}

@media (max-width: 60rem) {
  .regla-rejilla { grid-template-columns: 1fr; min-block-size: 0; gap: var(--space-xl); }
  .regla-texto { padding-inline: var(--space-lg); padding-block: var(--space-2xl) 0; }
  .regla-pieza { block-size: 44svh; }
}

/* --- El clip con alfa de la escena de Blender ------------------------------
   Mismo encuadre que el render fijo, pero con el corredor cruzando. WebM/VP9
   con canal alfa: no lleva fondo, así que se apoya sobre el marino igual que
   un PNG. `contain` para que no se recorte nada — el vídeo es 16:9 y su hueco
   no siempre lo es.

   Reparto de papeles: el vídeo manda, la imagen quieta es el respaldo. Se
   intercambian cuando el sistema pide menos movimiento, no al revés. */
.clip-alfa,
.clip-alfa-quieto {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  object-position: center bottom;
}
.clip-alfa-quieto { display: none; }
@media (prefers-reduced-motion: reduce) {
  .clip-alfa { display: none; }
  .clip-alfa-quieto { display: block; }
}
/* En el servidor local el movimiento va forzado (ver portada.js), así que el
   clip se ve aunque el sistema pida quieto: es lo que permite revisarlo. */
html.movimiento-forzado .clip-alfa { display: block; }
html.movimiento-forzado .clip-alfa-quieto { display: none; }

/* --- El hueco del cenital: las dos cifras ---------------------------------
   La vista aérea ocupa la mitad izquierda y dejaba libre la derecha entera.
   Ahí van las dos cifras que antes tenían sección propia — hablan de lo que
   pasa en el suelo, que es lo que se está viendo al lado — y debajo, pequeña,
   la foto del cruce. Una sección menos y medio lienzo menos en blanco. */
/* La banda de garantías: las dos cifras y la foto del cruce en fila, debajo de
   las dos vistas. Sin tarjeta oscura — la cifra en oro ya es la pieza gráfica,
   y una caja sólo añadiría peso a lo que es letra pequeña del viaje. */
/* Las dos garantías van DEBAJO del portátil y el teléfono, dentro de su misma
   columna: son la letra pequeña de lo que acaba de enseñarse, no un bloque
   aparte a todo lo ancho. Dos columnas, hairline arriba para separarlas del
   aparato sin meter una caja. */
.hueco-cifras {
  margin-block-start: var(--space-lg);
  padding-block-start: var(--space-lg);
  border-block-start: var(--rule) solid color-mix(in oklab, var(--color-tinta-clara) 18%, transparent);
}
/* Las fichas dejan de ser tarjetas altas: aquí son dos bloques anchos y bajos,
   que es lo que cabe en una columna. */
/* `.fichas` traía `repeat(auto-fit, minmax(15rem, 1fr))`, que en esta columna
   mete las dos en fila y las deja de 15 rem: ilegibles. Aquí van APILADAS, una
   debajo de otra, y cada una con su pie dentro del bloque. */
/* NO `display: contents`: un elemento sin caja no intersecta nunca, así que el
   IntersectionObserver que enciende el escalonado no lo ve y sus fichas se
   quedan en `opacity: 0` para siempre. Rejilla normal de dos columnas. */
.fichas-hueco {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-xl);
}
.fichas-hueco .ficha { display: block; }
.fichas-hueco .ficha { margin: 0; }
.fichas-hueco .ficha-cuerpo {
  aspect-ratio: auto;
  min-block-size: 0;
  background: transparent;
  color: var(--color-tinta-clara);
  padding: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "cifra titular" "cifra mas";
  align-items: center;
  column-gap: var(--space-md);
  row-gap: 0.15em;
}
.fichas-hueco .ficha-icono { display: none; }
.fichas-hueco .ficha-cifra {
  grid-area: cifra;
  margin: 0;
  /* Oro de tinta, no oro de marca: estas cifras están sobre el papel claro de
     la mesa y el `--color-accent` normal se queda en 2.1:1. */
  color: var(--color-accent-tinta);
  font-size: clamp(2.5rem, 3.4vw, 3.25rem);
  line-height: 0.85;
}
.fichas-hueco .ficha-titular {
  grid-area: titular; align-self: end;
  font-size: var(--ap-cuerpo);
  color: var(--color-tinta-clara);
}
/* OJO con el color: `--color-ink-2` es la tinta clara, pensada para el marino.
   Aquí el pie va sobre papel claro y hay que usar la tinta oscura, o el texto
   queda en 1,5:1 y no se lee. Es el tercer sitio donde pasa lo mismo. */
.fichas-hueco .ficha-pie {
  margin: var(--space-sm) 0 0;
  font-size: var(--ap-cuerpo-menor);
  color: color-mix(in oklab, var(--color-tinta-clara) 76%, transparent);
  max-inline-size: 42ch;
}
.hueco-foto .ficha-pie { color: color-mix(in oklab, var(--color-tinta-clara) 76%, transparent); }
/* El «+» pasa a enlace de texto: un círculo flotando sobre una banda sin caja
   no tiene dónde apoyarse. */
.fichas-hueco .mas {
  position: static;
  grid-area: mas;
  justify-self: start;
  inline-size: auto; block-size: auto;
  padding: 0;
  background: none; border: 0;
  color: color-mix(in oklab, var(--color-tinta-clara) 86%, transparent);
  font-size: var(--ap-cuerpo-menor);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.fichas-hueco .mas { font-size: 0; }
.fichas-hueco .mas::after {
  content: "Saber más";
  font-size: var(--ap-cuerpo-menor);
}
/* La foto del cruce se queda en la columna de la vista aérea, donde sobra
   sitio, y se alinea abajo con la etiqueta «En el suelo». */
.hueco-foto {
  grid-column: 2 / 6;
  grid-row: 1;
  align-self: end;
  z-index: 4;
  max-inline-size: 17rem;
  display: grid;
  gap: var(--space-sm);
  align-content: start;   /* el pie se pega a su foto, no al fondo de la caja */
}
.hueco-foto :is(.fig, .figura) { margin: 0; }
.hueco-foto img { inline-size: 100%; block-size: auto; border-radius: var(--radio-tarjeta); }
.hueco-foto .ficha-pie { margin: 0; font-size: var(--ap-cuerpo-menor); }
.hueco-foto :is(.fig, .figura) { display: block; }

@media (max-width: 60rem) {
  .hueco-cifras {
    grid-column: 1; grid-row: auto;
    padding-inline: var(--space-lg); padding-block: var(--space-xl) 0;
  }
  .hueco-foto { max-inline-size: none; }
}

/* --- 6b · «Del suelo a tu mesa»: ajustes de la sección doble ---------------
   La sección tiene AHORA un propósito declarado en su titular —el viaje del
   dato, del arco a la PC— y las dos vistas son las dos puntas de ese viaje.
   Antes el único titular estaba en la fila de abajo y la de arriba no decía a
   qué venía. */
#plataforma > .cabecera-seccion { margin-bottom: var(--space-xl); }
/* El titular de la fila de abajo pasa a h3: informa, no compite. */
.dosvistas-titular {
  margin: 0 0 var(--space-sm);
  font-family: var(--font-display);
  font-size: var(--ap-antetitulo);
  font-weight: 600;
  line-height: 1.15;
  color: var(--color-tinta-clara);
}
/* Las etiquetas de cada punta son el hilo de la sección: se refuerzan con una
   hairline delante, para que se lean como dos estaciones y no como pies de
   foto sueltos. */
.vista-pie {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
}
.vista-pie::before {
  content: "";
  inline-size: 2.5rem;
  block-size: var(--rule-2);
  background: var(--color-accent);
}


/* --- CARRUSEL INFINITO DE DISCIPLINAS ---------------------------------------
   Sustituye a la banda fija de cuatro planos. El motivo no es el efecto: son
   seis piezas y en una banda fija sólo caben cuatro, así que dos se quedaban
   fuera o todas se estrechaban hasta ser rendijas. Una cinta que avanza enseña
   las seis sin pedir nada a quien mira.

   SIN JAVASCRIPT ESTO SIGUE FUNCIONANDO: es un carrete que se arrastra con el
   dedo o con la rueda (`overflow-x: auto`). El script sólo añade el avance solo,
   y cuando lo hace apaga el arrastre poniendo `data-andando` — si no, empujar a
   mano y que la cinta ande a la vez se pelean por la misma posición.

   Quien pidió menos movimiento nunca ve `con-movimiento`, así que para esa
   persona esto es exactamente el carrete de arrastrar, sin vídeo y sin avance. */
.carrusel {
  /* La velocidad de la cinta, en pixeles por segundo. Vive aqui y no en el
     script porque depende del diseno: en vertical las fichas ocupan mucho mas
     de la pantalla y los mismos pixeles por segundo se perciben mas rapidos. */
  --carrusel-vel: 64;
  margin-inline: calc(var(--sangria, 0px) * -1);
  margin-block-start: var(--space-xl);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  position: relative;
}
.carrusel::-webkit-scrollbar { display: none; }

/* `overflow-x: clip` y no `hidden`: `hidden` en un eje obliga al otro a
   desplazarse, y eso corta el pie de foto de las piezas. */
.con-movimiento .carrusel[data-andando] { overflow-x: clip; }

.carrusel-pista {
  display: flex;
  gap: var(--rule-2, 2px);
  inline-size: max-content;
  /* El alto manda: el ancho de cada pieza sale de el por la proporcion 3:2.
     Por eso tambien depende del ANCHO de la ventana (`30vw`) y no solo del
     alto: sin eso, al pasar de 960 px las piezas saltaban de 432 a 567 px y
     se veian MENOS piezas cuanto mas ancha era la pantalla, que es justo al
     reves de lo que uno espera. Con `min(42svh, 30vw)` los dos lados del
     punto de corte valen lo mismo y la fila crece de 1,7 a 3,3 piezas. */
  block-size: clamp(16rem, min(42svh, 30vw), 24rem);
  /* La cinta se mueve con `translate3d`, que va en el compositor: mover
     `scrollLeft` a 60 fotogramas por segundo repinta y con seis vídeos dentro
     se nota. */
  will-change: transform;
}

.carro-pieza {
  margin: 0;
  flex: 0 0 auto;
  block-size: 100%;
  /* El ancho NO se fija: lo marca la proporcion sobre el alto de la cinta.
     Con un ancho suelto las piezas salian casi cuadradas (370 x 384 px), y
     `object-fit: cover` sobre un origen de 1,85:1 dejaba ver solo el 52 %
     central del cuadro: en «A pie» desaparecian las dos antenas, que son
     justo lo que cuenta la toma. A 3:2 se ve el 81 %. */
  aspect-ratio: 3 / 2;
  position: relative;
}
.carro-pieza :is(.fig, .figura) { block-size: 100%; margin: 0; border: 0; border-radius: 0; }
.carro-pieza :is(img, video) { inline-size: 100%; block-size: 100%; object-fit: cover; }
.carro-pieza figcaption {
  position: absolute; inset-block-end: 0; inset-inline: 0;
  padding: var(--space-lg) var(--space-md) var(--space-md);
  font-size: var(--ap-cuerpo-menor); font-weight: 600; color: #fff;
  background: linear-gradient(to top, rgb(0 0 0 / 0.55), transparent);
}


@media (max-width: 60rem) {
  /* EN VERTICAL NO ES LA MISMA PIEZA ENCOGIDA: ES OTRA COSA.

     En escritorio la cinta es una franja a sangre, cortada por los dos cantos,
     sin aire y sin bordes: un tira de fotogramas. Eso en un telefono no
     funciona —a 390 px una franja de 32svh es una rendija— y encoger las piezas
     tampoco, porque entonces no se ve nada de lo que pasa dentro.

     Asi que en vertical las piezas se convierten en FICHAS que se solapan, como
     una baraja que alguien va pasando: cada una tapa un trozo de la anterior,
     con su sombra, y por eso se leen como objetos sueltos y no como una tira.
     El solapamiento hace ademas que quepan tres a la vez donde antes cabia una
     y media, que es lo que hace que la fila se entienda de un vistazo.

     El solape se hace con MARGEN NEGATIVO, no con `gap`. Por eso el script mide
     el paso como la distancia real entre dos piezas (`offsetLeft`) y no como
     «ancho mas hueco»: asi el reciclado cae en el sitio exacto igual con
     separacion que con solape.

     La proporcion se queda apaisada a proposito. La tentacion es ponerlas
     verticales «porque es un telefono», pero recortar 1,85:1 a 4:5 deja ver
     solo el 43 % central del cuadro, y en `antenas` eso se come las dos antenas,
     que estan una en cada borde. La pieza se adapta; el encuadre no se toca. */
  .carrusel { --carrusel-vel: 44; padding-block: var(--space-md); }
  .carrusel-pista {
    block-size: auto;
    align-items: center;
    padding-inline: var(--space-lg);
  }
  .carro-pieza {
    /* Con `88vw` a secas, en una tableta de 900 px la ficha salia de 792 px:
       una sola, gigante, y la baraja dejaba de leerse como baraja. El tope de
       27rem hace que de 360 px a 960 px la fila pase de ensenar 1,4 fichas a
       2,6 sin ningun punto de corte nuevo. */
    /* Tres topes, y cada uno atiende a un caso distinto:
       - `88vw`  manda en un telefono de pie: asoma el canto de la siguiente.
       - `27rem` manda en una tableta. Sin el, a 900 px la ficha salia de
         792 px: una sola, gigante, y la baraja dejaba de leerse como baraja.
       - `60svh * 1.5` manda con el telefono TUMBADO. Ahi la pantalla mide
         unos 390 px de alto y la ficha ocupaba 288, o sea tres cuartos de
         pantalla con la barra encima. El `* 1.5` es la proporcion 3:2: se
         limita el alto y se despeja el ancho. */
    inline-size: min(88vw, 27rem, calc(60svh * 1.5));
    block-size: auto;
    /* 3:2 y no algo mas vertical: recortar el 1,85:1 de origen a 3:2 deja ver
       el 81 % central del cuadro. A 4:5 se veria el 43 %, y en `antenas` eso se
       come las dos antenas, que estan una en cada borde. */
    aspect-ratio: 3 / 2;
    margin-inline-start: calc(min(18vw, 5.5rem) * -1);
    overflow: clip;
    /* CANTO RECTO, como todo en esta pagina (`--radius: 0` en `tokens.css` es
       una decision, no un descuido). Redondear estas fichas las convertiria en
       tarjetas de plantilla; con la esquina viva y el solape se leen como una
       PILA DE COPIAS, fotogramas impresos puestos uno encima de otro, que es
       justo de lo que va la seccion.

       Dos sombras y no una: la difusa despega la ficha del fondo, y la linea
       clara de 2 px marca el canto por el que tapa a la de debajo. Sin esa
       linea, dos planos de bosque uno sobre otro se funden en una mancha. */
    box-shadow:
      -0.5rem 0 0 0 color-mix(in oklab, var(--color-papel-claro, #EDF1F8) 88%, transparent),
      0 0.9rem 2.2rem rgb(0 0 0 / 0.42);
  }
  /* La primera no se solapa con nada, asi que su margen negativo solo serviria
     para meterla debajo del borde de la pantalla. */
  .carro-pieza:first-child { margin-inline-start: 0; }
  /* Una de cada dos, un poco mas baja: la fila deja de ser una linea recta y
     pasa a tener onda. Va por CLASE y no por `:nth-child()` a proposito: el
     script recicla piezas moviendolas al final, asi que la posicion en el DOM
     cambia sola y con `:nth-child()` las fichas cambiarian de tamano solas a
     mitad del recorrido. */
  .carro-pieza.carro-baja { inline-size: min(72vw, 22rem, calc(49svh * 1.5)); transform: translateY(7%); }
  .carro-pieza figcaption {
    padding: var(--space-xl) var(--space-sm) var(--space-sm);
    font-size: var(--ap-cuerpo-menor);
  }
}

/* --- EL RELOJ, CUANDO LO MUEVE EL VÍDEO ---------------------------------
   Con `reloj-atado` las cifras las pinta `portada.js` desde el `currentTime`
   del clip de detrás. Hay que apagar las animaciones de arriba porque tocan el
   MISMO `transform`: una por la línea de tiempo del scroll y otra por duración.
   Dos dueños para una propiedad no es un empate, es un parpadeo.

   Lleva `!important` a propósito y no por pereza: las reglas que apaga son más
   específicas (`html.con-movimiento.sin-linea-de-scroll .reloj-cifra.a-la-vista
   …`), y ganarles por especificidad obligaría a repetir esa cadena entera aquí,
   que se rompería a la primera que alguien tocara una de las dos. */
.reloj-atado .rodillo b:first-child { animation: none !important; }
/* Y NADA de transiciones en una cifra de reloj. La hoja tiene un `transition`
   corto y general; sobre esto hace que cada cifra repte hacia la siguiente en
   vez de saltar, y un cronometro que interpola entre el 3 y el 4 no es un
   cronometro. */
.reloj-atado .rodillo b { transition: none !important; }

/* El velo baja del 86 % al 80 %. Con un vuelo rasante detrás daba igual, pero
   ahora lo que hay es alguien cruzando y a 86 % se perdía: el reloj se paraba
   sin que se viera por qué. Comprobado que las cifras siguen leyendo. */
.reloj-lienzo::after {
  background: color-mix(in srgb, var(--color-paper) 80%, transparent);
}

