/*
 * parallax-init — synchronous pre-Blazor primer for ParallaxImage.
 *
 * Why this exists (the Server→WASM "position pop"):
 *   App.razor uses InteractiveAuto. On a cold WASM cache the page renders
 *   server-side, the Server circuit hydrates and parallax.js register()s
 *   (setting data-parallax-active, which cancels the CSS view() animation),
 *   then WASM takes over: Blazor disposes the Server component → DisposeAsync
 *   → unregister() → data-parallax-active is REMOVED. For the multi-frame gap
 *   until WASM's new instance re-register()s (its IntersectionObserver fires
 *   asynchronously), the CSS animation resumes and drives background-position-y
 *   to its own view()-timeline value, which differs from the JS math — that
 *   brief reversion is the visible pop.
 *
 *   This script runs ONCE, synchronously, after the DOM is parsed but before
 *   Blazor boots, and sets data-parallax-active on every parallax window. That
 *   attribute is never tied to a component instance, so it survives the
 *   Server→WASM handoff — the CSS animation stays cancelled the whole time and
 *   parallax.js remains the sole writer of background-position-y across both
 *   render modes. register()/unregister() lifecycle is unchanged; on genuine
 *   navigation the element leaves the DOM entirely, so a stale attribute is moot.
 *
 * Why plain JS, not TypeScript:
 *   A synchronous pre-Blazor primer must be a classic <script> (no module
 *   graph, no async import). The RCL's TS pipeline emits ESNext modules, which
 *   are deferred — too late to beat the handoff. This file is therefore a
 *   hand-authored static asset, deliberately outside Interop/.
 *
 * Math parity with parallax.ts applyParallax():
 *   speed and direction are recovered from the inline custom properties the
 *   component already sets (--parallax-from / --parallax-to encode
 *   ParallaxSpeed and InvertDirection), then the SAME progress→position formula
 *   is applied. Any divergence here would itself be a pop, so the two must stay
 *   in lockstep — change one, change the other.
 */
(function () {
    'use strict';

    function clamp(value, min, max) {
        return Math.max(min, Math.min(max, value));
    }

    function prime(win) {
        var styles = getComputedStyle(win);
        var from = parseFloat(styles.getPropertyValue('--parallax-from')) || 0;
        var to = parseFloat(styles.getPropertyValue('--parallax-to')) || 0;

        // Component encodes: non-inverted → from:0, to:end; inverted → from:end, to:0.
        // Recover the original inputs from whichever endpoint carries the magnitude.
        var invert = from > to;
        var speed = clamp(Math.max(from, to) / 100, 0, 1);

        var rect = win.getBoundingClientRect();
        var viewportH = window.innerHeight;

        var progress = invert ? rect.top / viewportH : 1 - rect.top / viewportH;
        progress = clamp(progress, 0, 1);

        var pos = progress * speed * 100;

        var layers = win.querySelectorAll(':scope > .layer');
        for (var i = 0; i < layers.length; i++) {
            layers[i].style.backgroundPositionY = pos + '%';
        }

        // Cancel the CSS animation and adopt the JS value atomically.
        win.setAttribute('data-parallax-active', '');
    }

    function primeAll() {
        // Match parallax.ts: under reduced motion the module skips its scroll
        // listener and never sets data-parallax-active, leaving the layer at
        // --parallax-from (CSS animation is already `none` via media query).
        // Do the same here so the two paths stay consistent.
        if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
            return;
        }

        var windows = document.querySelectorAll('.parallax-window');
        for (var i = 0; i < windows.length; i++) {
            prime(windows[i]);
        }
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', primeAll);
    } else {
        primeAll();
    }
})();
