/**
 * Page transition — reproduces the react-src effect in a multi-page (PHP)
 * context via Swup. Two layered animations play in parallel:
 *
 *   1. Content slides: the #swup-main container slides up on exit and up
 *      from below on enter (1.3s each, cubic-bezier(.26,1.04,.54,1)).
 *   2. Black curtain overlay rises from the bottom, holds across the swap,
 *      then slides off the top (2.6s, cubic-bezier(.165,.84,.44,1)).
 *
 * Swup toggles .is-leaving / .is-rendering on <html> to drive the content
 * slides. The curtain is driven by a class toggle from JS so it can be
 * restarted on every visit (including the initial page load).
 */

/* Curtain + loader sit under the WP admin bar so editors see the bar stay
 * in place during page transitions. `--site-nav-admin-bar` is defined in
 * site-nav.css (0px by default, 32/46px when body.admin-bar is present).
 * z-index is kept under #wpadminbar's 99999. */
.site-curtain {
    position: fixed;
    inset: 0;
    top: var(--site-nav-admin-bar, 0);
    z-index: 99998;
    background-color: #000;
    transform: translateY(100vh);
    pointer-events: none;
    will-change: transform;
}

/**
 * First-paint loader: white overlay with the wordmark fading in. Sits below
 * the curtain (z-index wise) so the curtain takes over visually once it
 * rises. JS removes it shortly after the curtain has fully covered.
 *
 * The fade-in lives on the wordmark (not the container) so the white panel
 * is opaque from the very first paint. If the animation were on the whole
 * loader, `animation-fill-mode: both` would make it render at opacity 0
 * before the animation starts — and the user would briefly see the page
 * content behind it on load, which reads as a cheap fade-out.
 */
.site-loader {
    position: fixed;
    inset: 0;
    top: var(--site-nav-admin-bar, 0);
    z-index: 99997;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #fff;
    color: #000;
    pointer-events: none;
}

.site-loader > svg {
    width: 70%;
    height: auto;
    animation: site-loader-fade-in 0.5s cubic-bezier(.165, .84, .44, 1) both;
}

@media (min-width: 768px) {
    .site-loader > svg {
        width: 25%;
    }
}

@keyframes site-loader-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.site-curtain--active {
    animation: site-curtain-reveal 2.6s cubic-bezier(.165, .84, .44, 1);
}

/**
 * First load: hold the white loader + wordmark visible for 1s before the
 * curtain starts rising. Without this delay the curtain covers the logo
 * almost immediately and reads as a fade-out.
 */
html.is-initial-load .site-curtain--active {
    animation-delay: 1s;
}

@keyframes site-curtain-reveal {
    0%   { transform: translateY(100vh); }
    35%  { transform: translateY(0); }
    65%  { transform: translateY(0); }
    100% { transform: translateY(-100vh); }
}

/* `will-change: transform` is applied ONLY while a transition is running.
 * Setting it permanently would make #swup-main a containing block for any
 * descendant with `position: fixed` (CSS Containment spec), which breaks
 * fixed elements that should anchor to the viewport — notably the prev/
 * next side rails on single Work pages. The hint is only useful right
 * before the animation starts, so we attach it to the same classes that
 * drive the animation. */
html.is-leaving #swup-main,
html.is-rendering #swup-main,
html.is-initial-load #swup-main {
    will-change: transform;
}

html.is-leaving #swup-main,
html.is-leaving .home-logo {
    animation: site-page-exit 1.3s cubic-bezier(.26, 1.04, .54, 1) forwards;
}

html.is-rendering #swup-main,
html.is-rendering .home-logo {
    animation: site-page-enter 1.3s cubic-bezier(.26, 1.04, .54, 1);
}

html.is-initial-load #swup-main {
    /* Shifted by +1s to match the delayed curtain (hold phase lands during
       content-enter, so the swap is covered). `backwards` (not `both`)
       applies the `from` state during the delay but leaves the final
       transform unset — same reason as enter above. */
    animation: site-page-enter 1.3s cubic-bezier(.26, 1.04, .54, 1) 2.3s backwards;
}

/* The .home-logo rides the same slide on initial load BUT via a dedicated
 * keyframe with no `visibility: hidden`. Reusing site-page-enter for both
 * elements caused the compositor to skip the slide on #swup-main (likely a
 * race when two animations share keyframes with both fill-mode + visibility
 * during the 2.3s delay). The loader (z 99997) and the curtain (z 99998)
 * already hide the wordmark during the delay, so we don't need visibility
 * in the keyframe. */
@keyframes site-home-logo-initial-enter {
    from { transform: translate3d(0, 50vh, 0); }
    to   { transform: translate3d(0, 0, 0); }
}

html.is-initial-load .home-logo {
    animation: site-home-logo-initial-enter 1.3s cubic-bezier(.26, 1.04, .54, 1) 2.3s both;
}

@keyframes site-page-exit {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(0, -50vh, 0); }
}

@keyframes site-page-enter {
    from { transform: translate3d(0, 50vh, 0); visibility: hidden; }
    to   { transform: translate3d(0, 0, 0); visibility: visible; }
}

/* Block interactions with stale content while a transition is running. */
html.is-animating #swup-main {
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .site-curtain,
    .site-curtain--active,
    html.is-leaving #swup-main,
    html.is-leaving .home-logo,
    html.is-rendering #swup-main,
    html.is-rendering .home-logo,
    html.is-initial-load #swup-main,
    html.is-initial-load .home-logo,
    .site-loader,
    .site-loader > svg {
        animation: none !important;
        transform: none !important;
    }
    .site-loader { display: none !important; }
}
