/* =============================================================================
   motion.css — functional motion only (UX spec §D + the brief's credibility
   rule): short (120–300ms) fades with small offsets, no bounce, no parallax, no
   loops. Transform and opacity only, never layout properties. Durations and
   easings come from the app.css tokens (--dur-*, --ease-*). Everything is off
   or instant under prefers-reduced-motion: entrances are gated by the media
   query or by html.js-motion (motion.js only sets it when motion is allowed),
   and app.css's global kill-switch flattens hover/press transitions.

   Opt-in hooks for page markup (nothing animates on entry unless marked):
     [data-reveal] / .reveal    fade this element in when it scrolls into view
     [data-reveal-group]        fade each direct child in, 40ms apart (max 3 steps)
     [data-countup]             count a headline number up once (e.g. "$27.6B");
                                plain-text content only
     [data-motion-seq]          load-time sequence for the element's children
                                (the home hero)
   Always on: HTMX dim + progress bar, details fade, globe pin panel in/out,
   action-card hover edge.
   State classes set by motion.js (don't style these elsewhere):
     html.js-motion, .motion-pending, .motion-in, .countup, .countup-run,
     .motion-loading (HTMX target during a request), .motion-progress (top bar)
   ========================================================================== */

:root {
    --motion-enter: var(--dur-slow, 300ms);   /* entrances: hero sequence, scroll reveals */
    --motion-rise: 8px;      /* entrance travel */
    --motion-stagger: 40ms;  /* per-item delay inside a group */
}

@keyframes motion-rise {
    from { opacity: 0; transform: translateY(var(--motion-rise)); }
}
@keyframes motion-fade {
    from { opacity: 0; }
}

@media (prefers-reduced-motion: no-preference) {
    /* ---- load sequence (home hero): kicker → h1 → lede → actions → provenance ----
       Pure CSS so it never depends on JS timing; "backwards" fill holds the
       from-state through each delay and leaves no transform behind. Done by ~460ms. */
    [data-motion-seq] > * {
        animation: motion-rise var(--motion-enter) var(--ease-out) backwards;
        &:nth-child(2) { animation-delay: 40ms; }
        &:nth-child(3) { animation-delay: 80ms; }
        &:nth-child(4) { animation-delay: 120ms; }
        &:nth-child(n+5) { animation-delay: 160ms; }
    }

    /* ---- disclosures: content fades in; Pico already rotates the chevron ---- */
    details[open] > :not(summary) {
        animation: motion-fade var(--dur-base) var(--ease-out) backwards;
    }

    /* ---- globe pin panel (spec D.7): fades in from its edge on open and out
       on close; the [hidden] toggle in globe.html stays the source of truth.
       Browsers without discrete display transitions just show/hide it. */
    #pin-panel {
        transition: opacity var(--dur-fast) var(--ease-in), transform var(--dur-fast) var(--ease-in),
                    display var(--dur-fast) allow-discrete;
        &[hidden] { opacity: 0; transform: translateX(12px); }
        &:not([hidden]) {
            transition-duration: var(--dur-base);
            transition-timing-function: var(--ease-out);
        }
        @starting-style {
            &:not([hidden]) { opacity: 0; transform: translateX(12px); }
        }
    }
    @media (max-width: 768px) {
        #pin-panel {
            &[hidden] { transform: translateY(12px); }
            @starting-style {
                &:not([hidden]) { transform: translateY(12px); }
            }
        }
    }
}

/* ---- scroll reveals (motion.js marks below-the-fold targets pending) ----- */
html.js-motion .motion-pending {
    opacity: 0;
    transform: translateY(var(--motion-rise));
}
html.js-motion .motion-pending.motion-in {
    opacity: 1;
    transform: none;
    transition: opacity var(--motion-enter) var(--ease-out),
                transform var(--motion-enter) var(--ease-out);
    transition-delay: calc(var(--motion-i, 0) * var(--motion-stagger));
}
@media print {
    html.js-motion .motion-pending { opacity: 1; transform: none; }
}

/* ---- count-up: the real text stays in the DOM (transparent) and keeps the
   box size; an aria-hidden overlay shows the running number. text-fill-color
   is used because page rules set `color` on stat values with higher specificity. ---- */
.countup { position: relative; -webkit-text-fill-color: transparent; }
.countup-run {
    position: absolute;
    inset: 0;
    padding: inherit;
    -webkit-text-fill-color: var(--countup-color);
    font-variant-numeric: tabular-nums lining-nums;
    pointer-events: none;
}

/* ---- HTMX: dim the region being replaced; for requests slower than 300ms a
   2px bar creeps toward the right (no loop) and completes on response. ---- */
.motion-loading {
    opacity: 0.55;
    transition: opacity var(--dur-base) var(--ease-out);
}
.motion-progress {
    position: fixed;
    inset: 0 0 auto;
    height: 2px;
    z-index: var(--z-overlay);
    background: var(--color-accent);
    transform: scaleX(0);
    transform-origin: left;
    opacity: 0;
    pointer-events: none;
}
.motion-progress.is-active {
    opacity: 1;
    transform: scaleX(0.85);
    transition: transform 4s cubic-bezier(0.1, 0.6, 0.2, 1), opacity var(--dur-fast) ease;
}
.motion-progress.is-done {
    opacity: 0;
    transform: scaleX(1);
    transition: transform var(--dur-fast) ease, opacity var(--dur-base) ease var(--dur-fast);
}

/* ---- micro-interactions not already in app.css ----
   (app.css owns: button press, .cta / .link-arrow arrow nudge,
   table-row tint, masthead link underline, header .is-scrolled) */

/* action card: its top edge turns teal on hover/focus; flat, no lift (spec D.5).
   Relies on position: relative, which editorial.css sets only under .page-home /
   .page-act (the pages that use action cards today); cards elsewhere need it too. */
.action-card::after {
    content: "";
    position: absolute;
    inset: -1px;
    border-top: 2px solid var(--color-accent);
    border-radius: inherit;
    opacity: 0;
    transition: opacity var(--dur-base) ease;
    pointer-events: none;
}
.action-card:is(:hover, :focus-within)::after { opacity: 1; }
