/* StackCard — applies the pilot's "deck stacking" effect to each section.

   Why we can't just use `position: sticky` on the wrap (as the pilot does):
   ISV / Projects / Process each use their OWN internal sticky scroll-jacking
   for their scroll-driven animations. Making the parent wrap sticky breaks
   those inner stickies (rect.top stops changing → progress freezes).

   So instead we keep the wrap in normal flow and FAKE the deck behaviour
   from scroll position alone:
     1. Each wrap has heavy negative margin-top so consecutive cards overlap
        deeply — at any moment two or more cards co-exist in the viewport.
     2. Cards have ascending z-index → newer cards naturally paint on top.
     3. As the *next* card slides up to cover this one, we apply the pilot's
        peek-back transform: lift Y, scale down, dim, blur.
     4. Depth accumulates across all later cards (sum of each later card's
        "landing progress") so cards deeper in the stack recede further.

   Perf: ONE shared scroll listener updates ALL registered cards per frame.
   Previously each card had its own listener that ran querySelectorAll +
   N getBoundingClientRect on every scroll event — 7 cards = 7× the layout
   thrashing. Now reads are batched into a single forced-layout pass. */

(function () {
  const registry = [];
  let raf = 0;
  let mounted = false;

  const readVar = (name, fallback) => {
    const v = parseFloat(getComputedStyle(document.documentElement).getPropertyValue(name));
    return Number.isFinite(v) ? v : fallback;
  };

  const updateAll = () => {
    const n = registry.length;
    if (!n) return;
    const vh = window.innerHeight;
    const stickyTopPx = readVar('--stack-peek-top', 6) * vh / 100;
    const peekY     = readVar('--stack-peek-y', 24);
    const peekScale = readVar('--stack-peek-scale', 0.085);
    const peekDim   = readVar('--stack-peek-dim', 0.45);
    const peekBlur  = readVar('--stack-peek-blur', 10);
    const denom = Math.max(1, vh - stickyTopPx);

    // One forced-layout pass: read all rect.tops up front.
    const tops = new Array(n);
    for (let i = 0; i < n; i++) tops[i] = registry[i].getBoundingClientRect().top;

    // Then write transforms from the precomputed array (no further reads).
    for (let i = 0; i < n; i++) {
      let depth = 0;
      for (let j = i + 1; j < n; j++) {
        const t = (vh - tops[j]) / denom;
        depth += t < 0 ? 0 : t > 1 ? 1 : t;
      }
      const ty    = -depth * peekY;
      const scale = Math.max(0.5, 1 - depth * peekScale);
      const dim   = Math.max(0.25, 1 - depth * peekDim);
      const blur  = depth * peekBlur;
      const el = registry[i];
      el.style.transform = `translate3d(0, ${ty.toFixed(2)}px, 0) scale(${scale.toFixed(4)})`;
      el.style.opacity   = dim.toFixed(3);
      el.style.filter    = blur > 0.05 ? `blur(${blur.toFixed(2)}px)` : '';
    }
  };

  const onScroll = () => {
    if (raf) return;
    raf = requestAnimationFrame(() => { raf = 0; updateAll(); });
  };

  const ensureMounted = () => {
    if (mounted) return;
    mounted = true;
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    window.addEventListener('scroll', onScroll, { passive: true });
    window.addEventListener('resize', updateAll);
  };

  const sortRegistry = () => {
    registry.sort((a, b) => {
      const pos = a.compareDocumentPosition(b);
      if (pos & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
      if (pos & Node.DOCUMENT_POSITION_PRECEDING) return 1;
      return 0;
    });
  };

  window.__stackRegister = (el) => {
    ensureMounted();
    registry.push(el);
    sortRegistry();
    if (raf) cancelAnimationFrame(raf);
    raf = requestAnimationFrame(() => { raf = 0; updateAll(); });
  };

  window.__stackUnregister = (el) => {
    const i = registry.indexOf(el);
    if (i >= 0) registry.splice(i, 1);
  };
})();

function StackCard({ children, index = 0, tone = 'auto', first = false, last = false }) {
  const wrapRef = React.useRef(null);

  React.useEffect(() => {
    const el = wrapRef.current;
    if (!el) return;
    window.__stackRegister(el);
    return () => window.__stackUnregister(el);
  }, []);

  const cls = [
    'stack-card-wrap',
    `stack-card-wrap--${tone}`,
    first ? 'stack-card-wrap--first' : '',
    last  ? 'stack-card-wrap--last'  : '',
  ].filter(Boolean).join(' ');

  return (
    <div
      ref={wrapRef}
      className={cls}
      data-stack-index={index}
      style={{
        zIndex: 10 + index,
        transformOrigin: 'top center',
        willChange: 'transform, opacity, filter',
      }}
    >
      {children}
    </div>
  );
}

Object.assign(window, { StackCard });
