/* Shared motion layer of the V2 pages (contract: storage/app/motion-review/CONTRACT.md, script: motion-v2.js).
 * Linked after the page stylesheet by the V2 layouts; scoped to html.v2m plus data-v2-* / is-v2-* hooks.
 * Motion only under reduced-motion no-preference, fill-mode backwards (no transform left); nothing hidden without JS.
 * Rules enforced by tests/e2e/motion-v2/static-check.php. */

/* ===== v2m:tokens ===== */
html.v2m {
    --v2-m-fast: 160ms;
    --v2-m-base: 320ms;
    --v2-m-slow: 720ms;
    --v2-m-intro: 700ms;
    --v2-m-out: cubic-bezier(.16, 1, .3, 1);
    --v2-m-io: cubic-bezier(.4, 0, .2, 1);
    --v2-m-rise: 24px;
    --v2-m-rise-hero: 20px;
    --v2-m-step: 80ms;
    --v2-m-shadow: 0 18px 40px -20px rgba(21, 23, 28, .25);
}
@media not all and (min-width: 601px) {
    html.v2m { --v2-m-slow: 600ms; --v2-m-rise: 16px; --v2-m-rise-hero: 14px; }
}

/* ===== v2m:reveal ===== */
/* Failsafe: hidden states (.is-v2-pending, .is-v2-loading) show after 6 s if scripts stop; a live motion-v2.js swaps
 * .is-v2-beat every 2 s, which restarts the delay. Forwards is safe: the class is removed on reveal. */
@media (prefers-reduced-motion: no-preference) {
    html.v2m [data-v2-reveal].is-v2-pending { opacity: 0; animation: v2m-show 320ms ease 6s forwards; }
    html.v2m [data-v2-reveal].is-v2-pending.is-v2-beat { animation-name: v2m-show-beat; }
    html.v2m [data-v2-reveal="fade"].is-v2-pending { animation-name: v2m-show-fade; }
    html.v2m [data-v2-reveal="fade"].is-v2-pending.is-v2-beat { animation-name: v2m-show-fade-beat; }
    html.v2m [data-v2-reveal]:not([data-v2-reveal="fade"]).is-v2-pending { transform: translate3d(0, var(--v2-m-rise), 0); }
    html.v2m [data-v2-reveal].is-v2-anim {
        transition: opacity var(--v2-m-slow) var(--v2-m-out), transform var(--v2-m-slow) var(--v2-m-out);
        transition-delay: calc(var(--v2-i, 0) * var(--v2-m-step));
    }
    html.v2m [data-v2-reveal="fade"].is-v2-anim { transition-property: opacity; }
    html.v2m [data-v2-reveal].is-v2-now,
    html.v2m img[data-v2-img].is-v2-now { transition: none; }
}
/* Twin keyframes with the same frames: swapping the name restarts the animation delay. */
@keyframes v2m-show { to { opacity: 1; transform: none; } }
@keyframes v2m-show-beat { to { opacity: 1; transform: none; } }
@keyframes v2m-show-fade { to { opacity: 1; } }
@keyframes v2m-show-fade-beat { to { opacity: 1; } }

/* ===== v2m:intro ===== */
/* CSS only (plays without JS); longhands so the delays below are never reset. */
@media (prefers-reduced-motion: no-preference) {
    html.v2m [data-v2-intro-scope].is-active [data-v2-intro],
    html.v2m [data-v2-intro-scope="static"] [data-v2-intro] {
        animation-name: v2m-intro;
        animation-duration: var(--v2-m-intro);
        animation-timing-function: var(--v2-m-out);
        animation-fill-mode: backwards;
    }
    html.v2m [data-v2-intro-scope] [data-v2-intro="2"] { animation-delay: 100ms; }
    html.v2m [data-v2-intro-scope] [data-v2-intro="3"] { animation-delay: 200ms; }
}
@keyframes v2m-intro { from { opacity: 0; transform: translate3d(0, var(--v2-m-rise-hero), 0); } }

/* ===== v2m:cue ===== */
/* 3 x 1.6 s = 4.8 s: under the 5 s limit of WCAG 2.2.2. */
@media (prefers-reduced-motion: no-preference) {
    html.v2m [data-v2-cue] svg { animation: v2m-cue 1.6s ease-in-out 3; }
    html.v2m [data-v2-cue] svg + svg { animation-delay: .25s; }
    html.v2m [data-v2-cue]:hover svg,
    html.v2m [data-v2-cue]:focus-visible svg { animation: none; }
}
@keyframes v2m-cue { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }

/* ===== v2m:tabs ===== */
/* motion-v2.js sets --v2-pill-* and .is-v2-pill; the selected tab's own background is cleared (0,5,1) for the pill. */
html.v2m [data-v2-pill].is-v2-pill { position: relative; }
html.v2m [data-v2-pill].is-v2-pill::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: var(--v2-pill-w, 0);
    height: var(--v2-pill-h, 0);
    border-radius: var(--v2-pill-radius, 999px);
    background: var(--v2-pill-bg, #fff);
    box-shadow: var(--v2-pill-shadow, 0 1px 2px rgba(21, 23, 28, .08), 0 4px 12px -4px rgba(21, 23, 28, .16));
    transform: translate3d(var(--v2-pill-x, 0), var(--v2-pill-y, 0), 0);
    pointer-events: none;
}
html.v2m [data-v2-pill].is-v2-pill [role="tab"] { position: relative; z-index: 1; }
html.v2m [data-v2-pill].is-v2-pill [role="tab"][aria-selected="true"] { background-color: transparent; box-shadow: none; }
@media (prefers-reduced-motion: no-preference) {
    html.v2m [data-v2-pill].is-v2-pill-ready::before {
        transition: transform var(--v2-m-base) var(--v2-m-out), width var(--v2-m-base) var(--v2-m-out), height var(--v2-m-base) var(--v2-m-out);
    }
    html.v2m [data-v2-panel]:not([hidden]) { animation: v2m-panel-in 280ms var(--v2-m-out) backwards; }
}
@keyframes v2m-panel-in { from { opacity: 0; transform: translate3d(0, 8px, 0); } }

/* ===== v2m:card ===== */
/* The card needs no transform of its own and no data-v2-reveal: reveal the wrapper, lift the card. */
@media (hover: hover) and (pointer: fine) {
    html.v2m [data-v2-card]:hover { box-shadow: var(--v2-m-shadow); }
}
@media (prefers-reduced-motion: no-preference) {
    @media (hover: hover) and (pointer: fine) {
        html.v2m [data-v2-card] { transition: transform var(--v2-m-base) var(--v2-m-out), box-shadow var(--v2-m-base) var(--v2-m-io); }
        html.v2m [data-v2-card]:hover { transform: translate3d(0, -4px, 0); }
        html.v2m [data-v2-card] [data-v2-zoom] { transition: transform var(--v2-m-slow) var(--v2-m-out); }
        html.v2m [data-v2-card]:hover [data-v2-zoom] { transform: scale(1.03); }
        html.v2m [data-v2-card] [data-v2-lift] { transition: transform 400ms var(--v2-m-out); }
        html.v2m [data-v2-card]:hover [data-v2-lift] { transform: translate3d(0, -12px, 0); }
    }
}
html.v2m [data-v2-card]:focus-visible { box-shadow: var(--v2-m-shadow); }

/* ===== v2m:link ===== */
/* The page keeps links distinct from body text without hover (WCAG 1.4.1). */
@media (prefers-reduced-motion: no-preference) {
    @media (hover: hover) and (pointer: fine) {
        html.v2m [data-v2-nudge] svg { transition: transform var(--v2-m-fast) var(--v2-m-io); }
        html.v2m [data-v2-nudge]:hover svg { transform: translate3d(3px, 0, 0); }
    }
    html.v2m [data-v2-underline] { transition: background-size var(--v2-m-base) var(--v2-m-out); }
}
html.v2m [data-v2-underline] {
    background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px no-repeat;
    text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
    html.v2m [data-v2-underline]:hover { background-size: 100% 1px; }
}
html.v2m [data-v2-underline]:focus-visible { background-size: 100% 1px; }

/* ===== v2m:press ===== */
/* Replaces the button's own transition, so its colour / border / shadow properties are listed too. */
@media (prefers-reduced-motion: no-preference) {
    html.v2m [data-v2-press] {
        transition-property: background-color, border-color, color, box-shadow, transform;
        transition-duration: var(--v2-m-fast);
        transition-timing-function: var(--v2-m-io);
    }
    html.v2m [data-v2-press]:active { transform: scale(.97); }
}

/* ===== v2m:modal ===== */
/* No close animation (focus returns at once), no backdrop-filter (heavy paint on phones). */
@media (prefers-reduced-motion: no-preference) {
    html.v2m [data-v2-modal]:not([hidden]) { animation: v2m-fade 200ms ease backwards; }
    html.v2m [data-v2-modal]:not([hidden]) [data-v2-modal-panel] { animation: v2m-pop 250ms cubic-bezier(.2, .8, .2, 1) backwards; }
}
@keyframes v2m-fade { from { opacity: 0; } }
@keyframes v2m-pop { from { opacity: 0; transform: translate3d(0, 16px, 0) scale(.98); } }

/* ===== v2m:image ===== */
/* Lazy images below the fold only, never the LCP image. */
@media (prefers-reduced-motion: no-preference) {
    html.v2m img[data-v2-img] { transition: opacity var(--v2-m-base) var(--v2-m-io); }
    html.v2m img[data-v2-img].is-v2-loading { opacity: 0; animation: v2m-show-fade 320ms ease 6s forwards; }
    html.v2m img[data-v2-img].is-v2-loading.is-v2-beat { animation-name: v2m-show-fade-beat; }
}

/* ===== v2m:swap ===== */
/* A page crossfade on the image keeps the opacity (a transition outranks an animation). */
@media (prefers-reduced-motion: no-preference) {
    html.v2m [data-v2-swap-img].is-v2-settle { animation: v2m-settle 900ms var(--v2-m-out) backwards; }
}
@keyframes v2m-settle { from { opacity: 0; transform: scale(1.04); } }

/* ===== v2m:count ===== */
html.v2m [data-v2-count] { font-variant-numeric: tabular-nums; }

/* ===== v2m:marquee ===== */
/* Pause toggle (WCAG 2.2.2): printed with the hidden attribute, shown by motion-v2.js while motion is allowed. */
html.v2m [data-v2-marquee].is-v2-paused [data-v2-marquee-track],
html.v2m [data-v2-marquee].is-v2-offscreen [data-v2-marquee-track] { animation-play-state: paused; }
html.v2m [data-v2-marquee-toggle][hidden] { display: none !important; }

/* ===== v2m:view-transition ===== */
/* v2-swap: the view transition started by window.v2Motion.swap(). */
@media (prefers-reduced-motion: no-preference) {
    html.v2m::view-transition-group(v2-swap) { animation-duration: var(--v2-m-base); animation-timing-function: var(--v2-m-out); }
    html.v2m::view-transition-old(v2-swap),
    html.v2m::view-transition-new(v2-swap) { animation-duration: 200ms; }
}
@media (prefers-reduced-motion: reduce) {
    html.v2m::view-transition-group(*),
    html.v2m::view-transition-old(*),
    html.v2m::view-transition-new(*) { animation: none; }
}

/* ===== v2m:print ===== */
/* Same specificity as the hidden states, later in the file. */
@media print {
    html.v2m [data-v2-reveal].is-v2-pending { opacity: 1; }
    html.v2m [data-v2-reveal]:not([data-v2-reveal="fade"]).is-v2-pending { transform: none; }
    html.v2m img[data-v2-img].is-v2-loading { opacity: 1; }
    /* Switching to print media must not start the image fade. */
    @media (prefers-reduced-motion: no-preference) {
        html.v2m img[data-v2-img] { transition: none; }
    }
    html.v2m [data-v2-marquee] [data-v2-marquee-toggle] { display: none; }
}
