/* Noxta · movimiento "Pantalla de recinto" con la foto y los titulares
   de "Imprenta" · 2026-10-06
   ------------------------------------------------------------------
   La base sigue siendo la pantalla del festival: el tablero de la
   entrada, la pantalla LED junto al escenario, el panel de producción.
   De "Imprenta" entran dos piezas: la foto que se revela con trama de
   semitono y el titular con las planchas de color corridas que se
   alinean. Cada tipo de elemento tiene su propia manera de entrar:

     Titulares grandes  registro de planchas: el texto aparece con la
                        plancha terracota y la gris corridas y las tres
                        convergen sobre la tinta final. Sin giro y sin
                        ninguna línea sobre las letras.
     Relojes y          tablero split-flap: cada ficha gira con pasos
     timecodes          mecánicos y se asienta. Las letras quedan limpias.
     Bandas sólidas     se encienden de izquierda a derecha por segmentos.
     Fotos              trama de semitono: una barra terracota baja por
                        filas imprimiendo la foto en puntos, y los puntos
                        crecen hasta fundirse en la imagen limpia.
     Teléfonos          una mano los levanta y la pantalla despierta.
     Listas y tablas    las filas se encienden en secuencia, con un
                        destello terracota antes de quedar fijas.
     Textos             se imprimen por bloques de líneas, de arriba abajo.
     Tickets y pases    salen de la impresora, de arriba abajo.
     Secciones          cambio de diapositiva: una cortina del color de
                        la página anterior se retira por columnas.
     Profundidad        paralaje en tres velocidades en todo el sitio.

   Regla de los rangos ligados al scroll: toda entrada termina, como
   máximo, en "entry 100%" (el elemento ya entró completo) o en
   "cover 30%" (lleva un tercio de su recorrido). Así, si la persona se
   detiene con el elemento en pantalla, nada queda a medias. El paralaje
   es la única animación que recorre todo el "cover", porque no es una
   entrada sino una posición.

   Sin JS. Se enlaza después de estilos.css. Todo vive dentro de
   prefers-reduced-motion: no-preference; lo ligado al scroll, dentro de
   @supports (animation-timeline: view()). Sin soporte, todo queda
   visible y quieto.
   ------------------------------------------------------------------ */

/* Única regla fuera de la media query de movimiento: la cinta de
   recinto es un letrero decorativo que solo tiene sentido en movimiento.
   Si la persona pide menos movimiento, no se muestra. */
.cinta-recinto { display: none; }

/* El tamaño del punto de la trama tiene que ser animable: se registra
   como propiedad tipada. Es un registro, no un estilo: por sí solo no
   mueve nada, y tiene que declararse en el nivel superior de la hoja. */
@property --trama {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

@media (prefers-reduced-motion: no-preference) {

  :root {
    --salida: cubic-bezier(0.23, 1, 0.32, 1);
    /* Las planchas convergen con una curva más pareja: con la salida
       fuerte se alinean en el primer tercio y no se alcanza a ver. */
    --salida-plancha: cubic-bezier(0.35, 0, 0.3, 1);
    --salida-trama: cubic-bezier(0.25, 0, 0.45, 1);
    --amp-frente: 72px;
    --amp-banda: 26px;
    --amp-img: 16.6%;
    --paso: 1%;
    --fondo-trama: rgb(var(--ink-900));
    --plancha-a: var(--accent);
    --plancha-b: rgb(var(--fog-400) / 0.85);
  }
  .papel {
    --fondo-trama: var(--papel);
    --plancha-a: var(--acento-papel);
    --plancha-b: rgb(var(--ink-400) / 0.8);
  }
  /* Piezas oscuras dentro de páginas de papel. */
  .panel, .crew, .pantalla {
    --plancha-a: var(--accent);
    --plancha-b: rgb(var(--fog-400) / 0.85);
  }
  /* Tinta oscura sobre banda terracota. */
  .portada-banda2,
  .o-portada-titulo .acento-banda,
  .n03-respuesta .titular .flap {
    --plancha-a: rgb(var(--ink-900));
    --plancha-b: rgb(var(--fog-100) / 0.7);
  }
  /* Objetos claros dentro de páginas oscuras. */
  .objeto-entrada {
    --plancha-a: var(--acento-papel);
    --plancha-b: rgb(var(--ink-400) / 0.8);
  }

  /* ================================================================
     FOTOGRAMAS
     ================================================================ */

  /* Tablero split-flap: entra girando, se detiene, sigue girando hacia
     afuera (como si pasara otra ficha) y vuelve a entrar para asentarse. */
  @keyframes flap {
    0%     { transform: perspective(1400px) rotateX(-90deg); }
    32%    { transform: perspective(1400px) rotateX(0deg); }
    46%    { transform: perspective(1400px) rotateX(0deg); }
    68%    { transform: perspective(1400px) rotateX(90deg); }
    68.01% { transform: perspective(1400px) rotateX(-90deg); }
    100%   { transform: perspective(1400px) rotateX(0deg); }
  }

  /* Rasqueta: el titular se revela en diagonal. El polígono sobra por
     los cuatro lados para no cortar las planchas corridas. */
  @keyframes rasqueta {
    from { clip-path: polygon(-30% -12%, -8% -12%, -30% 112%, -52% 112%); }
    to   { clip-path: polygon(-30% -12%, 132% -12%, 110% 112%, -52% 112%); }
  }

  /* Registro de planchas: la terracota y la gris entran corridas y
     convergen sobre la tinta final. */
  @keyframes planchas {
    from {
      text-shadow:
        0.07em 0.05em 0 var(--plancha-a),
        -0.05em -0.035em 0 var(--plancha-b);
    }
    to {
      text-shadow:
        0 0 0 transparent,
        0 0 0 transparent;
    }
  }

  /* Texto impreso por bloques de líneas. */
  @keyframes imprime {
    from { clip-path: inset(-8% 0 108% 0); }
    to   { clip-path: inset(-8% 0 -8% 0); }
  }

  /* Ticket que sale de la impresora. Las muescas quedan fuera del cuadro,
     por eso los márgenes negativos. */
  @keyframes tiquet {
    from { clip-path: inset(-12px -12px 100% -12px); }
    to   { clip-path: inset(-12px -12px -12px -12px); }
  }

  /* Banda que se enciende de izquierda a derecha por segmentos. */
  @keyframes banda {
    from { clip-path: inset(0 100% 0 0); }
    to   { clip-path: inset(0 0 0 0); }
  }

  /* Fila de tablero: apagada, destello terracota, fija. */
  /* El destello solo existe en el fotograma del medio: al terminar, cada
     elemento recupera su propia sombra o fondo. */
  @keyframes fila {
    0%   { opacity: 0; }
    50%  { opacity: 1; box-shadow: inset 0 0 0 100vmax rgb(var(--accent-rgb) / 0.22); }
    100% { opacity: 1; }
  }
  @keyframes fila-tr {
    0%   { opacity: 0; }
    50%  { opacity: 1; background-color: rgb(var(--accent-rgb) / 0.22); }
    100% { opacity: 1; }
  }

  /* Teléfono: una mano lo levanta. */
  /* Teléfono de portada: sube desde abajo cuando el texto ya terminó. */
  @keyframes sube-tel {
    from { transform: translateY(260px); opacity: 0; }
    to   { transform: none; opacity: 1; }
  }
  /* La app carga: cada bloque aparece en orden, de arriba abajo. */
  @keyframes carga-app {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes levantar {
    from { transform: translateY(150px); }
    to   { transform: none; }
  }

  /* La pantalla despierta: apagada, destello claro corto, normal. */
  @keyframes encender {
    0%   { filter: brightness(0); }
    70%  { filter: brightness(0); }
    71%  { filter: brightness(1.45) contrast(0.85); }
    100% { filter: none; }
  }

  /* Trama de semitono: los puntos transparentes crecen hasta fundirse.
     A 9.3 px el punto ya cubre la esquina de la celda de 13 px: desde ahí
     la foto está limpia y el resto es solo apagar la capa. */
  @keyframes trama {
    0%   { --trama: 1.5px; opacity: 1; }
    50%  { --trama: 7.4px; opacity: 1; }
    76%  { --trama: 9.3px; opacity: 1; }
    100% { --trama: 9.9px; opacity: 0; }
  }

  /* Filas que se imprimen: la capa sólida del color de la página se
     retira de arriba abajo detrás de la barra, en 16 pasos. */
  @keyframes filas-imprimen {
    from { background-size: 100% 100%, 13px 13px; }
    to   { background-size: 100% 0%, 13px 13px; }
  }

  /* La barra terracota baja por la foto. */
  @keyframes led-barra {
    from { top: 0%; }
    to   { top: 100%; }
  }
  /* Pantalla LED: la foto se llena por filas (de Pantalla de recinto). */
  @keyframes led-filas {
    from { clip-path: inset(0 0 100% 0); }
    to   { clip-path: inset(0 0 0 0); }
  }
  @keyframes apagar {
    from { opacity: 1; }
    to   { opacity: 0; }
  }

  /* Línea de folio que se dibuja por segmentos. */
  @keyframes linea {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }

  /* Cambio de diapositiva: la cortina del color anterior se retira por
     columnas, de izquierda a derecha, mientras la sección entra. */
  @keyframes diapo {
    from { clip-path: inset(0 0 0 0); }
    to   { clip-path: inset(0 0 0 100%); }
  }

  /* Paralaje en tres velocidades. */
  @keyframes paralaje-frente {
    from { translate: 0 var(--amp-frente); }
    to   { translate: 0 calc(var(--amp-frente) * -1); }
  }
  @keyframes paralaje-banda {
    from { translate: 0 calc(var(--amp-banda) * -1); }
    to   { translate: 0 var(--amp-banda); }
  }
  @keyframes paralaje-img {
    from { translate: 0 calc(var(--amp-img) * -1); }
    to   { translate: 0 0; }
  }

  /* Cintas y relojes. */
  @keyframes cinta {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
  }
  @keyframes rollo {
    from { transform: translateY(0); }
    to   { transform: translateY(-75%); }
  }
  @keyframes regla-corre {
    from { background-position-x: 0; }
    to   { background-position-x: 18px; }
  }
  @keyframes ahora-avanza {
    from { left: 56%; }
    to   { left: 72%; }
  }

  /* ================================================================
     ESTRUCTURA DE LAS PIEZAS NUEVAS
     ================================================================ */

  /* Fichas del tablero y planchas del titular: la misma caja. Sin
     ninguna costura ni línea encima de las letras. */
  .flap {
    display: inline-block;
    vertical-align: top;
    position: relative;
    backface-visibility: hidden;
    --i: 0;
  }
  .flap:nth-of-type(2) { --i: 1; }
  .flap:nth-of-type(3) { --i: 2; }
  .flap:nth-of-type(4) { --i: 3; }
  .flap:nth-of-type(5) { --i: 4; }
  .flap:nth-of-type(6) { --i: 5; }
  .flap:nth-of-type(7) { --i: 6; }
  .timecode .hora { display: inline-flex; }

  /* Escalonado: cada hijo recibe su índice. */
  .escalona > *, .secuencia > * { --i: 0; }
  .escalona > :nth-child(2),  .secuencia > :nth-child(2)  { --i: 1; }
  .escalona > :nth-child(3),  .secuencia > :nth-child(3)  { --i: 2; }
  .escalona > :nth-child(4),  .secuencia > :nth-child(4)  { --i: 3; }
  .escalona > :nth-child(5),  .secuencia > :nth-child(5)  { --i: 4; }
  .escalona > :nth-child(6),  .secuencia > :nth-child(6)  { --i: 5; }
  .escalona > :nth-child(7),  .secuencia > :nth-child(7)  { --i: 6; }
  .escalona > :nth-child(8),  .secuencia > :nth-child(8)  { --i: 7; }
  .escalona > :nth-child(9),  .secuencia > :nth-child(9)  { --i: 8; }
  .escalona > :nth-child(10), .secuencia > :nth-child(10) { --i: 9; }
  .escalona > :nth-child(11), .secuencia > :nth-child(11) { --i: 10; }
  .escalona > :nth-child(n + 12), .secuencia > :nth-child(n + 12) { --i: 10; }
  /* Filas en horizontal: el escalón es más largo porque entran juntas. */
  .secuencia-h { --paso: 3%; }
  /* Rejillas de cuatro columnas: el índice es la columna. */
  .secuencia-4 > :nth-child(4n + 1) { --i: 0; }
  .secuencia-4 > :nth-child(4n + 2) { --i: 1; }
  .secuencia-4 > :nth-child(4n + 3) { --i: 2; }
  .secuencia-4 > :nth-child(4n)     { --i: 3; }
  .secuencia-4 { --paso: 3%; }

  /* Foto de pantalla: contenedor con la trama y la barra.
     ::before es la trama (capa sólida del color de la página que se
     retira por filas, y debajo los puntos que crecen). Fuera de la
     animación la trama no existe: la foto queda limpia.
     ::after es la barra terracota que imprime. */
  .led { position: relative; }
  .led::before,
  .led::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    pointer-events: none;
  }
  .led::before {
    top: 0;
    bottom: 0;
    z-index: 2;
    background:
      repeating-linear-gradient(90deg, rgb(var(--ink-900)) 0 1px, transparent 1px 5px),
      repeating-linear-gradient(0deg, rgb(var(--ink-900)) 0 1px, transparent 1px 5px);
  }
  .led::after {
    top: 0;
    height: 3px;
    z-index: 3;
    background: var(--accent);
    translate: 0 -100%;
  }
  .led .etiqueta { position: relative; z-index: 4; }

  /* Folio: la línea se dibuja. El del pie del sitio no, porque la página
     termina antes de que su rango de scroll se complete. */
  .folio-pagina:not(.pie-sitio .folio-pagina) { position: relative; border-top-color: transparent; }
  .folio-pagina:not(.pie-sitio .folio-pagina)::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: -1px;
    height: 1px;
    background: currentColor;
    transform-origin: left center;
  }

  /* Cortina de cambio de diapositiva. */
  .diapo { position: relative; }
  .diapo::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: min(100vh, 100%);
    z-index: 10;
    pointer-events: none;
    background: var(--diapo-color);
  }
  .diapo-tinta { --diapo-color: rgb(var(--ink-900)); }
  .diapo-papel { --diapo-color: var(--papel); }

  /* Cinta de recinto: letrero con reloj y horarios. */
  .cinta-recinto {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: stretch;
    border-top: 1px solid rgb(var(--ink-500));
    border-bottom: 1px solid rgb(var(--ink-500));
    background: rgb(var(--ink-800));
    color: rgb(var(--fog-300));
    font-family: var(--mono);
    font-size: 12px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    overflow: clip;
  }
  .cinta-etiqueta {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 32ch;
    padding: 0 20px 0 var(--borde);
    border-right: 1px solid rgb(var(--ink-500));
    background: rgb(var(--ink-800));
    color: rgb(var(--fog-100));
    white-space: nowrap;
    position: relative;
    z-index: 1;
  }
  /* contain: inline-size evita que la pista, más ancha que la página,
     empuje el ancho de su contenedor. */
  .cinta-ventana { min-width: 0; overflow: clip; contain: inline-size; }
  .cinta-etiqueta::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: rgb(var(--ok));
    flex: none;
    animation: latido 1.8s ease-in-out infinite;
  }
  .cinta-reel { height: 18px; line-height: 18px; overflow: clip; }
  .cinta-rollo { animation: rollo 15s steps(3, end) infinite; }
  .cinta-rollo span { display: block; height: 18px; }
  .cinta-pista {
    display: flex;
    width: max-content;
    animation: cinta 84s linear infinite;
  }
  .cinta-lista { display: flex; flex: none; }
  .cinta-lista li {
    padding: 0 28px;
    line-height: 46px;
    white-space: nowrap;
    border-right: 1px dashed rgb(var(--ink-500));
  }
  .cinta-vivo { color: var(--accent-text); }
  .cinta-lista b { color: rgb(var(--fog-100)); font-weight: 500; }

  /* Ticker de la pantalla del recinto: continuo y lento. */
  .ticker span { animation: none; }
  .ticker { contain: inline-size; overflow: clip; }
  .ticker-pista {
    display: flex;
    width: max-content;
    animation: cinta 44s linear infinite;
  }
  .ticker-pista span { padding-right: 64px; white-space: nowrap; }

  /* Reglas y relojes que siguen corriendo. */
  .timecode .regla {
    background-size: 18px 100%;
    animation: regla-corre 6s linear infinite;
  }
  .app-ahora { animation: ahora-avanza 90s linear infinite; }

  /* ================================================================
     PORTADAS: secuencia de encendido por tiempo (están a la vista al
     cargar, así que no dependen del scroll)
     ================================================================ */

  /* Las dos fotos de portada: la barra imprime las filas en 1,4 s y la
     trama termina de fundirse a los 2,8 s. */
  .portada-foto.led,
  .o-portada-foto.led {
    overflow: clip;
    animation: led-filas 1.5s steps(16, end) 0.2s both;
  }
  .portada-foto.led::after,
  .o-portada-foto.led::after {
    animation: led-barra 1.5s steps(16, end) 0.2s both, apagar 0.1s steps(1, end) 1.7s both;
  }
  .portada-foto.led::before,
  .o-portada-foto.led::before {
    animation: apagar 0.9s steps(3, end) 1.8s both;
  }

  /* Home */
  .portada-banda { animation: banda 0.9s steps(12, end) 0.5s both; }
  .portada-banda .flap {
    animation: rasqueta 0.9s var(--salida) both, planchas 1.7s var(--salida-plancha) both;
    animation-delay: calc(1s + var(--i) * 0.3s), calc(1s + var(--i) * 0.3s);
  }
  .portada-banda2 { animation: banda 0.8s steps(12, end) 1.5s both; }
  .portada-banda2 .flap {
    animation: rasqueta 0.8s var(--salida) 1.9s both, planchas 1.5s var(--salida-plancha) 1.9s both;
  }
  .portada-etiqueta { animation: fila 0.6s steps(1, end) 2.5s both; }
  .portada-tel { animation: sube-tel 0.9s var(--salida) 1.6s both; }
  .portada-tel .app-tope,
  .portada-tel .app-regla,
  .portada-tel .app-estado,
  .portada-tel .app-dias,
  .portada-tel .app-dia-titulo,
  .portada-tel .app-cuenta,
  .portada-tel .app-set,
  .portada-tel .app-tabs { animation: carga-app 0.15s var(--salida) both; }
  .portada-tel .app-tope { animation-delay: 2.9s; }
  .portada-tel .app-regla,
  .portada-tel .app-estado { animation-delay: 2.92s; }
  .portada-tel .app-dias { animation-delay: 2.94s; }
  .portada-tel .app-dia-titulo,
  .portada-tel .app-cuenta { animation-delay: 2.96s; }
  .portada-tel .app-set:nth-of-type(1) { animation-delay: 2.98s; }
  .portada-tel .app-set:nth-of-type(2) { animation-delay: 3.0s; }
  .portada-tel .app-set:nth-of-type(3) { animation-delay: 3.02s; }
  .portada-tel .app-set:nth-of-type(4) { animation-delay: 3.04s; }
  .portada-tel .app-tabs { animation-delay: 3.06s; }
  /* Pantalla de inicio: el logo de Noxta mientras el teléfono sube;
     se va y recién ahí carga la app. */
  @keyframes splash-sale {
    from { opacity: 1; }
    to   { opacity: 0; visibility: hidden; }
  }
  .portada-tel .app { position: relative; }
  .portada-tel .app::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 5;
    background: url("img/noxta-logo-cream.svg") center / 92px auto no-repeat, rgb(var(--ink-900));
    animation: splash-sale 0.2s var(--salida) 2.7s both;
    pointer-events: none;
  }
  /* La línea vertical de la agenda aparece con el primer set. */
  .portada-tel .app-linea::before { animation: carga-app 0.15s var(--salida) 2.98s both; }
  .portada-pie .bajada { animation: imprime 1s steps(8, end) 2.3s both; }
  .portada-pie .ctas-col > :nth-child(1) { animation: fila 0.6s steps(1, end) 2.9s both; }
  .portada-pie .ctas-col > :nth-child(2) { animation: fila 0.6s steps(1, end) 3.15s both; }

  /* Cómo funciona */
  .o-portada-titulo .flap {
    animation: rasqueta 0.9s var(--salida) both, planchas 1.6s var(--salida-plancha) both;
    animation-delay: calc(0.8s + var(--i) * 0.3s), calc(0.8s + var(--i) * 0.3s);
  }
  .o-portada-bajada p { animation: imprime 1s steps(8, end) 2.2s both; }
  .o-portada-bajada .ctas > :nth-child(1) { animation: fila 0.6s steps(1, end) 2.8s both; }
  .o-portada-bajada .ctas > :nth-child(2) { animation: fila 0.6s steps(1, end) 3.05s both; }
  .o-portada-tape > * {
    animation: fila 0.6s steps(1, end) both;
    animation-delay: calc(2.4s + var(--i) * 0.26s);
  }
  .o-portada-tape > :nth-child(1) { --i: 0; }
  .o-portada-tape > :nth-child(2) { --i: 1; }
  .o-portada-tape > :nth-child(3) { --i: 2; }
  .o-portada-tape > :nth-child(4) { --i: 3; }
  .o-portada-tape > :nth-child(5) { --i: 4; }
  .o-portada-tape > :nth-child(6) { --i: 5; }

  /* ================================================================
     LIGADO AL SCROLL
     Todos los rangos de entrada terminan en "cover 30%" o antes, salvo
     las fotos, que terminan en "entry 100%" (ya entraron completas) y
     están limpias desde "entry 76%".
     ================================================================ */
  @supports (animation-timeline: view()) {

    /* overflow: hidden en un ancestro rompe view(); clip no. Con clip el
       tamaño mínimo automático vuelve a depender del contenido, por eso
       min-width: 0 (con hidden ya era 0). */
    .n01, .n03 { overflow: visible; overflow-x: clip; }
    .n01-foto, .n03-foto, .m5-foto, .portada-foto, .o-portada-foto,
    .panel, .crew, .pantalla, .pase, .tape, .objeto-entrada, .ticker,
    .app, .app-cuerpo, .app-mapa, .app-mini, .app-chips, .app-dias { overflow: clip; min-width: 0; }

    /* La animación "entra" de estilos.css se reemplaza por las de aquí. */
    .entra { animation: none; }

    /* ---------- Titulares: registro de planchas ---------- */
    .flap {
      animation: rasqueta var(--salida) both, planchas var(--salida-plancha) both;
      animation-timeline: view(), view();
      animation-range:
        cover calc(10% + var(--i) * var(--pf, 2%)) cover calc(30% + var(--i) * var(--pf, 2%)),
        cover calc(10% + var(--i) * var(--pf, 2%)) cover calc(50% + var(--i) * var(--pf, 2%));
    }
    .planes thead th:nth-child(2) .flap { --i: 0; }
    .planes thead th:nth-child(3) .flap { --i: 1; }
    .planes thead th:nth-child(4) .flap { --i: 2; }
    .planes thead th:nth-child(5) .flap { --i: 3; }

    /* ---------- Relojes y timecodes: fichas que giran ---------- */
    .timecode .dia,
    .timecode .hora .flap,
    .pantalla-reloj .flap,
    .crew-input .flap {
      animation: flap steps(4, end) both;
      animation-timeline: view();
      animation-range: cover calc(2% + var(--i) * var(--pf, 2%)) cover calc(16% + var(--i) * var(--pf, 2%));
    }

    /* ---------- Textos: impresos ---------- */
    .indice-cabeza p,
    .n01-texto p,
    .n02-cabeza .entrada p,
    .n03-cabeza h2,
    .n03-respuesta p,
    .n04-texto .lead,
    .contra-bajada p,
    .momento-texto p,
    .bloque-cabeza p,
    .planes-nota p,
    .objeto-bio,
    .pie,
    .nota-honesta {
      animation: imprime steps(8, end) both;
      animation-timeline: view();
      animation-range: cover calc(2% + var(--i, 0) * var(--paso)) cover calc(24% + var(--i, 0) * var(--paso));
    }
    .objeto-qr .qr {
      animation: imprime steps(7, end) both;
      animation-timeline: view();
      animation-range: cover 4% cover 26%;
    }

    /* ---------- Bandas ---------- */
    .objeto-pulsera {
      animation: banda steps(12, end) both;
      animation-timeline: view();
      animation-range: cover 0% cover 22%;
    }

    /* ---------- Filas que se encienden ---------- */
    .secuencia > *,
    .num,
    .etiqueta:not(.portada-etiqueta),
    .panel-barra,
    .pantalla-cabeza,
    .flecha-grande,
    .n03-preguntas .mono,
    .planes-nota .boton {
      animation: fila steps(1, end) both;
      animation-timeline: view();
      animation-range: cover calc(2% + var(--i, 0) * var(--paso)) cover calc(18% + var(--i, 0) * var(--paso));
    }
    .secuencia > tr { animation-name: fila-tr; }

    /* ---------- Tickets y pases ---------- */
    .indice-lista .stub,
    .n03-stubs .stub,
    .pase,
    .objeto-entrada {
      animation: tiquet steps(12, end) both;
      animation-timeline: view();
      animation-range: cover calc(2% + var(--i, 0) * var(--paso)) cover calc(22% + var(--i, 0) * var(--paso));
    }
    .indice-lista, .n03-stubs { --paso: 2.5%; }

    /* ---------- Teléfonos ---------- */
    .telefono {
      animation: levantar var(--salida) both, paralaje-frente linear both;
      animation-timeline: view(), view();
      animation-range: cover calc(var(--i, 0) * 2%) cover calc(24% + var(--i, 0) * 2%), cover 0% cover 100%;
    }
    .telefono .app {
      animation: encender steps(1, end) both;
      animation-timeline: view();
      animation-range: cover calc(12% + var(--i, 0) * 2%) cover calc(24% + var(--i, 0) * 2%);
    }
    /* Las portadas conservan su secuencia por tiempo y suman el paralaje. */
    .portada-tel {
      animation: sube-tel 0.9s var(--salida) 1.6s both, paralaje-frente linear both;
      animation-timeline: auto, view();
      animation-range: normal, cover 0% cover 100%;
    }

    /* ---------- Fotos: trama de semitono ----------
       La barra imprime las filas mientras la foto entra (entry 0 a 55%)
       y los puntos crecen hasta que la foto entró completa (entry 100%);
       la imagen ya está limpia en entry 76%. */
    .led { view-timeline: --led block; overflow: clip; }
    .led:not(.portada-foto):not(.o-portada-foto) {
      animation: led-filas steps(16, end) both;
      animation-timeline: --led;
      animation-range: cover 0vh cover 34vh;
    }
    .led:not(.portada-foto):not(.o-portada-foto)::after {
      animation: led-barra steps(16, end) both, apagar steps(1, end) both;
      animation-timeline: --led, --led;
      animation-range: cover 0vh cover 34vh, cover 34vh cover 36vh;
    }
    .led:not(.portada-foto):not(.o-portada-foto)::before {
      animation: apagar steps(3, end) both;
      animation-timeline: --led;
      animation-range: cover 24vh cover 48vh;
    }
    /* Paralaje de fondo: la foto es más alta que su marco y se desplaza
       más lento que la página. */
    .led img {
      height: 120%;
      width: 100%;
      object-fit: cover;
      animation: paralaje-img linear both;
      animation-timeline: --led;
      animation-range: cover 0% cover 100%;
    }

    /* ---------- Folios ---------- */
    .folio-pagina:not(.pie-sitio .folio-pagina)::before {
      animation: linea steps(24, end) both;
      animation-timeline: view();
      animation-range: cover 0% cover 24%;
    }

    /* ---------- Cambio de diapositiva ---------- */
    .diapo::before {
      animation: diapo steps(12, end) both;
      animation-timeline: view();
      animation-range: cover 0vh cover 28vh;
    }

    /* ---------- Paralaje: tres velocidades ---------- */
    .portada-banda,
    .portada-banda2,
    .o-portada-titulo,
    .indice-cabeza h2,
    .n01-texto h2,
    .n02-cabeza h2,
    .n03-preguntas,
    .n03-respuesta,
    .n04-titulo,
    .contra-titulo,
    .timecode,
    .momento-texto h2,
    .bloque-cabeza h2,
    .no-es h2,
    .planilla {
      animation: paralaje-banda linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    .portada-banda { animation: banda 0.9s steps(12, end) 0.5s both, paralaje-banda linear both; animation-timeline: auto, view(); animation-range: normal, cover 0% cover 100%; }
    .portada-banda2 { animation: banda 0.8s steps(12, end) 1.5s both, paralaje-banda linear both; animation-timeline: auto, view(); animation-range: normal, cover 0% cover 100%; }
    .panel,
    .crew,
    .pantalla,
    .pase,
    .indice-lista > :nth-child(even),
    .n03-stubs,
    .m6-visual {
      animation: paralaje-frente linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    .pase {
      animation: tiquet steps(12, end) both, paralaje-frente linear both;
      animation-timeline: view(), view();
      animation-range: cover 2% cover 22%, cover 0% cover 100%;
    }
    .objeto-entrada {
      animation: tiquet steps(12, end) both, paralaje-banda linear both;
      animation-timeline: view(), view();
      animation-range: cover 2% cover 22%, cover 0% cover 100%;
    }
    /* Los cuatro soportes del código: cada uno con su entrada y su velocidad. */
    .m2-objetos .objeto-pulsera {
      animation: banda steps(12, end) both, paralaje-frente linear both;
      animation-timeline: view(), view();
      animation-range: cover 0% cover 22%, cover 0% cover 100%;
      --amp-frente: 40px;
    }
    .m2-objetos .objeto-bio {
      animation: imprime steps(8, end) both, paralaje-banda linear both;
      animation-timeline: view(), view();
      animation-range: cover 2% cover 24%, cover 0% cover 100%;
    }
    .m2-objetos .objeto-qr {
      animation: paralaje-frente linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
      --amp-frente: 48px;
    }
    .crew { --amp-frente: 44px; }
    .panel { --amp-frente: 56px; }
    .m6-visual, .n03-stubs { --amp-frente: 40px; }
    .indice-lista > :nth-child(even) { --amp-frente: 32px; }
    .n02-spread > :nth-child(2) { --amp-frente: 36px; }
    .n02-spread > :nth-child(3) { --amp-frente: 56px; }

    /* ---------- Celular y tablet ---------- */
    @media (max-width: 960px) {
      :root { --amp-frente: 36px; --amp-banda: 14px; --amp-img: 10%; }
      /* Dentro de una fila con desplazamiento propio, view() mide contra
         esa fila y no contra la página: ahí todo queda quieto. */
      .n02-spread .telefono, .n02-spread .app, .n02-spread .pie,
      .planes-marco .flap, .planes-marco tr, .planes-marco .secuencia > * { animation: none; }
      .cinta-etiqueta { width: auto; padding-right: 16px; }
    }
    @media (max-width: 480px) {
      .cinta-etiqueta { display: none; }
    }
  }

  /* ================================================================
     HOVERS: rápidos, solo con puntero fino
     ================================================================ */
  @media (hover: hover) and (pointer: fine) {
    .boton { transition-duration: 120ms, 120ms, 120ms; transition-timing-function: var(--salida); }
    .boton .flecha { transition: translate 140ms var(--salida); }
    .boton:hover .flecha { translate: 5px 0; }
    .indice-lista .stub { transition-duration: 160ms, 160ms; transition-timing-function: var(--salida); }
    .tape > * { transition-duration: 120ms, 120ms; }
    .nav a:not(.boton) { transition: color 120ms var(--salida), border-color 120ms var(--salida); }
    .pie-rejilla a { transition: color 120ms var(--salida); }
    .cinta-recinto:hover .cinta-pista,
    .ticker:hover .ticker-pista { animation-play-state: paused; }
  }
}
