/* =========================================================================
   GLOBAL SECTION: Motion System
   ========================================================================= */

/* =========================================================================
   CITEM — Motion System: revelado en scroll
   SYNC DS §5.4: implementa el "block reveal" que el manual pedía desde el
   principio. Lo que había era un fadeUp genérico —justo lo que §5.4 descarta.

   Contrato (una sola clase base + variantes):

     .reveal                elemento revelable. Por defecto sube y aparece.
     .reveal--wipe          barrido de borde recto (clip-path)
     .reveal--curtain       un bloque de color macizo se retira y deja ver
     .reveal--mask          el texto sube desde detrás de una máscara
     .reveal--slide         solo transform, la opacidad nunca baja (LCP)
     .reveal--from-left     entra desde la izquierda en vez de desde abajo
     .reveal-group          contenedor: escalona a sus .reveal descendientes
     .is-inview             estado, lo pone js/reveal.js

   Variables por elemento: --reveal-shift, --reveal-curtain-color, --reveal-i.

   Decisiones y alternativas descartadas: docs/architecture/arquitectura.md
   §Motion System. Las reglas de marca del movimiento: BRAND_MANUAL.md §5.4.
   ========================================================================= */

/* El retardo sale del índice que reparte el JS dentro de cada .reveal-group.
   Vive fuera del gate porque es aritmética, no estado: no oculta nada. */
.reveal {
    --reveal-delay: min(
        calc(var(--reveal-i, 0) * var(--reveal-stagger)),
        var(--reveal-stagger-max)
    );
}

/* ─────────────────────────────────────────────────────────────────────────
   Gate de seguridad — TODO lo que oculta contenido vive aquí dentro.

   `scripting: enabled` solo casa cuando el navegador declara que ejecuta
   scripts. Un rastreador sin JS, o un navegador sin soporte de la media
   query, descarta el bloque entero y ve la página completa: el contenido
   nunca depende de que un observer llegue a ejecutarse.

   Esto es lo que arregla el motivo por el que la home no se animaba (ver
   PLAN §3.1). No mover estas reglas fuera del gate.

   No se usa el patrón habitual del <script> en línea que marca <html>:
   web/_headers declara `script-src 'self'` sin 'unsafe-inline', así que ese
   script no se ejecutaría — y obligaría a repetirlo en cada página nueva.
   ───────────────────────────────────────────────────────────────────────── */
@media (scripting: enabled) {

    /* ── Base: sube y aparece ── */
    .reveal {
        opacity: 0;
        transform: translate3d(var(--reveal-x, 0px), var(--reveal-y, var(--reveal-shift)), 0);
        transition:
            opacity var(--dur-reveal) var(--ease-blockout) var(--reveal-delay),
            transform var(--dur-reveal) var(--ease-blockout) var(--reveal-delay);
    }

    .reveal.is-inview {
        opacity: 1;
        transform: translate3d(0, 0, 0);
    }

    /* ── Dirección: entra de lado en vez de desde abajo ── */
    .reveal.reveal--from-left {
        --reveal-x: calc(var(--reveal-shift) * -1);
        --reveal-y: 0px;
    }

    /* ── slide: solo transform ──
       Un elemento en opacity 0 no cuenta como pintado, así que animar la
       opacidad de lo que marca el LCP retrasa la métrica tanto como dure la
       animación. Esta variante entra desplazada pero pintada desde el primer
       frame. Es la obligatoria para el <h1> de un hero. */
    .reveal.reveal--slide {
        opacity: 1;
        transition: transform var(--dur-reveal) var(--ease-blockout) var(--reveal-delay);
    }

    /* ── wipe: barrido de borde recto ──
       clip-path recorta también la sombra, así que esta variante es para
       texto, reglas y bloques sin sombra blockout. Para tarjetas con sombra,
       usar .reveal o .reveal--curtain. */
    .reveal.reveal--wipe {
        opacity: 1;
        transform: none;
        clip-path: inset(0 100% 0 0);
        transition: clip-path var(--dur-reveal) var(--ease-wipe) var(--reveal-delay);
    }

    .reveal.reveal--wipe.is-inview {
        clip-path: inset(0 0 0 0);
    }

    /* ── curtain: el bloque de color de §5.4 ──
       El contenido nunca se oculta: lo tapa un rectángulo opaco que luego se
       retira. Por eso funciona con imágenes y texto por igual, y por eso el
       texto sigue siendo texto pintado mientras dura el gesto.

       `inset: 0` se resuelve contra la caja de padding, así que el borde
       blockout del elemento queda fuera de la cortina y se ve desde el
       principio: primero el marco, después el contenido. */
    .reveal.reveal--curtain {
        opacity: 1;
        transform: none;
        transition: none;
        position: relative;
        overflow: hidden;
    }

    .reveal--curtain::after {
        content: "";
        position: absolute;
        inset: 0;
        z-index: 3;
        pointer-events: none;
        background-color: var(--reveal-curtain-color, var(--c-coral));
        transform: translate3d(0, 0, 0);
        transition: transform var(--dur-reveal) var(--ease-wipe) var(--reveal-delay);
    }

    .reveal--curtain.is-inview::after {
        transform: translate3d(101%, 0, 0);
    }

    /* ── mask: el texto sube desde detrás de un borde ──
       Requiere un hijo que envuelva el texto:
         <h2><span class="reveal reveal--mask"><span>TITULAR</span></span></h2>

       El padding + margen negativo del mismo valor deja el hueco donde caben
       tildes y colas sin mover el layout. Con --leading-display (1.3, medido)
       el sobre de tinta de Gobold llega a 1.31em, así que `overflow: hidden`
       aún puede rozar É y cola de Q por ~0.01em: el hueco se queda. */
    .reveal.reveal--mask {
        opacity: 1;
        transform: none;
        transition: none;
        display: block;
        overflow: hidden;
        padding: 0.14em 0.1em 0.2em;
        margin: -0.14em -0.1em -0.2em;
    }

    .reveal--mask > * {
        display: block;
        transform: translate3d(0, 110%, 0);
        transition: transform var(--dur-reveal) var(--ease-blockout) var(--reveal-delay);
    }

    .reveal--mask.is-inview > * {
        transform: translate3d(0, 0, 0);
    }
}

/* Nota — parallax y salida ligados al scroll (`animation-timeline: view()`):
   se escribieron y se retiraron sin llegar a entrar. No se pudo comprobar que
   la timeline llegue a activarse en este sitio: `body` lleva `overflow-x:
   hidden`, y aunque el desbordamiento se propaga al viewport —`scrollingElement`
   es HTML—, la timeline daba `progress: null` en todas las posiciones de
   scroll. Sin poder distinguir si era eso o el entorno de prueba, se deja
   fuera: el revelado no lo necesita, y CSS muerto "por si acaso" es peor que
   no tenerlo. Candidato a volver cuando se pueda mirar en un navegador real. */

/* ─────────────────────────────────────────────────────────────────────────
   Accesibilidad e impresión — SYNC DS §5.10: guard obligatorio.

   El reset global deja las duraciones en 0.01ms, pero eso por sí solo no
   basta: .reveal sigue partiendo de opacity 0 y esperaría igualmente a que
   el JS le pusiera .is-inview. Aquí se revela todo de entrada, y js/reveal.js
   hace lo propio sin registrar ningún observer.

   `print` entra en la misma lista porque el problema es el mismo —contenido
   que no debe depender de un observer— y la respuesta también. Al imprimir no
   hay scroll: lo que el lector no hubiera recorrido saldría en blanco sobre el
   papel. La especificación deja `scripting` en `initial-only` para documentos
   impresos, lo que ya bastaría, pero eso no se ha podido comprobar aquí y una
   hoja en blanco no es un fallo que se descubra a tiempo.
   ───────────────────────────────────────────────────────────────────────── */
@media print, (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .reveal,
    .reveal--mask > * {
        opacity: 1 !important;
        transform: none !important;
        clip-path: none !important;
    }

    .reveal--curtain::after {
        display: none !important;
    }
}

/* Ticker / Marquesina infinita */
@keyframes ticker {
    0% {
        transform: translate3d(0, 0, 0);
    }
    100% {
        transform: translate3d(-100%, 0, 0);
    }
}

/* Ticker inverso: empieza con contenido ya visible */
@keyframes ticker-reverse {
    0% {
        transform: translate3d(-50%, 0, 0);
    }
    100% {
        transform: translate3d(0, 0, 0);
    }
}

