/**
 * Scroll scene: a section that pins to the screen while the visitor scrolls
 * and plays 2–4 steps (heading, text, optional button) one after another,
 * optionally over a photo that pushes in. When the last step has played the
 * pin lets go and the page continues. CSS scroll-driven animations, no
 * JavaScript; modelled on Dolly's pinned scenes (usedolly.dev, MIT).
 * One scene per page.
 *
 * globalClass: scroll-scene   (with a palette wrapper, e.g. wrapper-alternate-color;
 *                              not a color-section: its padding would shift the pin)
 *
 * Variants:
 *   scroll-scene--image   media is figure > img.scroll-scene-media inside the
 *                         pin, behind the steps with a darkening layer
 *   scroll-scene--zoom    with --image: the photo pushes in over the whole
 *                         scene (keyframes scroll-zoom in css/scroll-motion.css)
 *
 * Structure:
 *   .scroll-scene.gb-container.alignfull.wrapper-alternate-color
 *     .scroll-scene-pin.gb-container
 *       figure > img.scroll-scene-media                 (--image)
 *       .scroll-scene-step.gb-container   ×2–4          h2, p, buttons
 *
 * How it plays: the scene is steps × --scroll-scene-step-length plus one
 * screen tall; the pin sticks for the steps' share and each step owns an
 * equal slice of it (the steps are counted with :has(), nothing to set per
 * step). The first step is there when the scene arrives and then leaves,
 * middle steps arrive and leave, the last arrives and stays until the pin
 * lets go.
 *
 * Tuning:
 *   --scroll-scene-step-length   scroll per step, default 100svh
 *   --scroll-scene-top           pin offset from the viewport top: the admin
 *                                bar, plus --header-height (cover.js) while a
 *                                GP sticky header stays on screen
 *                                (.navigation-stick without auto-hide-sticky);
 *                                on a page with an anchor-nav, below the band
 *   --scroll-scene-overlay       darkening over the photo
 *   --scroll-zoom                --zoom end scale, default 1.12
 *
 * Without scroll-timeline support (Firefox before 159) and with reduced
 * motion the scene is an ordinary section: no pin, the steps one under
 * another over the photo. The editor shows the same: the pin and motion
 * rules use child selectors, which the editor's block wrappers do not match.
 *
 * Chain animations: none. The steps are the motion, and a chainAnimation on
 * a step would cancel it.
 */

:root {
    --scroll-scene-step-length: 100svh;
    --scroll-scene-overlay: color-mix(in srgb, var(--media-bg-clr) 45%, transparent);
}

.scroll-scene {
    --scroll-scene-top: var(--wp-admin--admin-bar--height, 0px);
    --scroll-scene-steps: 1;
    position: relative;
}

/* alignfull containers get the side gutter; the photo runs edge to edge and
   the pin keeps the gutter for the text */
.gb-container.scroll-scene {
    padding-left: 0;
    padding-right: 0;
}

/* A sticky header that stays on screen would cover the top of the pin.
   GP Premium marks the stuck bar with .navigation-stick; an auto-hiding bar
   leaves while the visitor scrolls down, so it needs no room. */
:root:has(.navigation-stick:not(.auto-hide-sticky)) .scroll-scene {
    --scroll-scene-top: calc(var(--wp-admin--admin-bar--height, 0px) + var(--header-height, 0px));
}

/* An anchor-nav band sticks for the whole page; --anchor-nav-top already
   holds whatever sits above the band (anchor-nav.css), so this rule wins
   over the header rule (same specificity, later). */
:root:has(.gb-container.anchor-nav) .scroll-scene {
    --scroll-scene-top: calc(var(--anchor-nav-top) + var(--anchor-nav-height));
}

.scroll-scene:has(.scroll-scene-step:nth-child(2 of .scroll-scene-step)) {
    --scroll-scene-steps: 2;
}

.scroll-scene:has(.scroll-scene-step:nth-child(3 of .scroll-scene-step)) {
    --scroll-scene-steps: 3;
}

.scroll-scene:has(.scroll-scene-step:nth-child(4 of .scroll-scene-step)) {
    --scroll-scene-steps: 4;
}

.scroll-scene-step:nth-child(1 of .scroll-scene-step) {
    --scroll-scene-i: 0;
}

.scroll-scene-step:nth-child(2 of .scroll-scene-step) {
    --scroll-scene-i: 1;
}

.scroll-scene-step:nth-child(3 of .scroll-scene-step) {
    --scroll-scene-i: 2;
}

.scroll-scene-step:nth-child(4 of .scroll-scene-step) {
    --scroll-scene-i: 3;
}

/* Pin: an ordinary padded column; the motion block below makes it stick */
.scroll-scene-pin {
    position: relative;
    display: grid;
    place-items: center;
    row-gap: 48px;
    padding: var(--section-padding-y) var(--mobile-side-padding);
}

.scroll-scene-pin > .block-editor-inner-blocks {
    width: 100%;
}

.scroll-scene-step {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 760px;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
}

.scroll-scene-step > :last-child {
    margin-bottom: 0;
}

/* Media layer behind the steps. Found through img.scroll-scene-media; the
   editor's image wrapper is positioned the same way so the preview matches. */
.scroll-scene figure:has(> img.scroll-scene-media),
.scroll-scene [data-type="generateblocks/image"]:has(img.scroll-scene-media) {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    overflow: clip;
    z-index: 0;
}

.scroll-scene img.scroll-scene-media {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.scroll-scene figure:has(> img.scroll-scene-media)::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--scroll-scene-overlay);
}

@keyframes scroll-scene-step-first {
    0%, 80% { opacity: 1; translate: 0 0; }
    100%    { opacity: 0; translate: 0 -2rem; }
}

@keyframes scroll-scene-step {
    0%       { opacity: 0; translate: 0 2rem; }
    20%, 80% { opacity: 1; translate: 0 0; }
    100%     { opacity: 0; translate: 0 -2rem; }
}

@keyframes scroll-scene-step-last {
    0%        { opacity: 0; translate: 0 2rem; }
    20%, 100% { opacity: 1; translate: 0 0; }
}

@supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
        .scroll-scene:has(> .scroll-scene-pin) {
            min-height: calc(var(--scroll-scene-steps) * var(--scroll-scene-step-length) + 100svh);
            view-timeline-name: --scroll-scene;
            view-timeline-axis: block;
        }

        .scroll-scene > .scroll-scene-pin {
            position: sticky;
            top: var(--scroll-scene-top);
            height: calc(100svh - var(--scroll-scene-top));
            padding-top: 0;
            padding-bottom: 0;
            overflow: clip;
        }

        /* Every step shares the one grid cell and owns an equal slice of the
           pinned scroll (contain = the time the scene fills the screen). */
        .scroll-scene-pin > .scroll-scene-step {
            grid-area: 1 / 1;
            animation-name: scroll-scene-step;
            animation-timing-function: linear;
            animation-fill-mode: both;
            animation-timeline: --scroll-scene;
            animation-range:
                contain calc(var(--scroll-scene-i) / var(--scroll-scene-steps) * 100%)
                contain calc((var(--scroll-scene-i) + 1) / var(--scroll-scene-steps) * 100%);
        }

        .scroll-scene-pin > .scroll-scene-step:nth-child(1 of .scroll-scene-step) {
            animation-name: scroll-scene-step-first;
        }

        .scroll-scene-pin > .scroll-scene-step:nth-last-child(1 of .scroll-scene-step) {
            animation-name: scroll-scene-step-last;
        }

        .scroll-scene-pin > .scroll-scene-step:nth-child(1 of .scroll-scene-step):nth-last-child(1 of .scroll-scene-step) {
            animation-name: none;
        }

        .scroll-scene--zoom > .scroll-scene-pin > figure > img.scroll-scene-media {
            animation-name: scroll-zoom;
            animation-timing-function: linear;
            animation-fill-mode: both;
            animation-timeline: --scroll-scene;
            animation-range: contain 0% contain 100%;
        }
    }
}
