/* =========================================================================
   Motion system.

   The handoff defines three motion levels — Cinematic (default), Subtle and
   Off. Cinematic is built here; `prefers-reduced-motion` is the graceful
   reduction at the bottom of this file.

   Everything shares one easing curve. Reveal *state* lives in CSS; JavaScript
   only decides WHEN an element becomes visible, never how it looks.
   ========================================================================= */

@keyframes fade-up {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
}

@keyframes pop-in {
    from { opacity: 0; transform: translateY(16px) scale(.985); }
    to   { opacity: 1; transform: none; }
}

@keyframes veil-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes bar-in {
    from { transform: translateY(100%); }
    to   { transform: none; }
}

@keyframes word-in {
    from { opacity: 0; transform: translateY(14px); filter: blur(12px); }
    to   { opacity: 1; transform: none; filter: none; }
}

/* -------------------------------------------------------------------------
   Hero headline — split into words, each on its own stagger step.

   Pure CSS: the words are real elements in the markup, so this runs without
   JavaScript and never reflows the headline.
   ------------------------------------------------------------------------- */

.hero__word {
    display: inline-block;
    animation: word-in 780ms var(--ease) both;
    animation-delay: calc(120ms + var(--word-index, 0) * 40ms);
}

/* -------------------------------------------------------------------------
   Section reveals.

   Gated behind `.js` on the root element, which a tiny inline script sets
   before first paint. Without JavaScript nothing is ever hidden.
   ------------------------------------------------------------------------- */

.js [data-reveal] {
    opacity: 0;
    transform: translateY(var(--reveal-distance)) scale(var(--reveal-scale));
    filter: blur(var(--reveal-blur));
    transition:
        opacity var(--reveal-duration) var(--ease),
        transform var(--reveal-duration) var(--ease),
        filter var(--reveal-duration) ease;
    transition-delay: var(--reveal-delay, 0ms);
    will-change: opacity, transform, filter;
}

/* Photography resolves from soft focus more slowly than text. */
.js [data-reveal="media"] {
    filter: blur(var(--reveal-blur-media));
    transition-duration: var(--reveal-duration-media);
}

.js [data-reveal].is-revealed {
    opacity: 1;
    transform: none;
    filter: none;
}

/* Once the reveal has played, drop the compositing hints and the filter so
   long pages don't carry hundreds of promoted layers. */
.js [data-reveal].is-settled {
    transition: none;
    transition-delay: 0ms;
    will-change: auto;
    filter: none;
}

/* -------------------------------------------------------------------------
   Reduced motion.

   An explicit design decision: keep the fades, drop everything else. This is
   not a full static fallback — the page still resolves in, just without
   travel, scale or blur.
   ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        animation-duration: .25s !important;
        animation-delay: 0ms !important;
        transition-duration: .25s !important;
    }

    .js [data-reveal] {
        transform: none !important;
        filter: none !important;
        transition-property: opacity !important;
        transition-delay: 0ms !important;
    }

    .hero__word {
        animation-name: veil-in;
    }

    /* Format-card depth scroll is disabled in JS; make sure no stale inline
       transform survives. */
    .format-card {
        transform: none !important;
        opacity: 1 !important;
    }
}
