// landing-motion.jsx — scroll-reveal (IntersectionObserver + safety fallback) + hero phone tilt.
(function () {
  var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  function revealAll() {
    document.querySelectorAll('.reveal').forEach(function (el) { el.classList.add('in'); });
  }

  // Frozen-clock fallback: cancel stuck (possibly delayed) transitions and
  // force the visible end-state. Removing .anim-ok alone does NOT cancel an
  // already-running delayed transition, so we inject transition:none here.
  function forceVisible(root) {
    root.classList.remove('anim-ok');
    if (!document.getElementById('pote-force-visible')) {
      var s = document.createElement('style');
      s.id = 'pote-force-visible';
      s.textContent = '.reveal{opacity:1 !important;transform:none !important;transition:none !important;}'
        + '.hero-phone-tilt{transition:none !important;}'
        + '.float-a,.float-b,.float-c,.kick-dot{animation:none !important;}';
      document.head.appendChild(s);
    }
    revealAll();
  }

  function start() {
    if (reduce) { revealAll(); setTimeout(revealAll, 400); return; }

    // Opt into the animated/hidden state. If the animation clock turns out to
    // be frozen (offscreen/preview iframe where rAF never fires and CSS
    // transitions stick at their start value), back out so content shows.
    var root = document.documentElement;
    root.classList.add('anim-ok');
    var rafWorks = false;
    if (window.requestAnimationFrame) requestAnimationFrame(function () { rafWorks = true; });
    setTimeout(function () { if (!rafWorks) { forceVisible(root); } }, 250);

    var ioFired = false;

    if ('IntersectionObserver' in window) {
      var io = new IntersectionObserver(function (entries) {
        ioFired = true;
        entries.forEach(function (e) {
          if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); }
        });
      }, { threshold: 0.12, rootMargin: '0px 0px -7% 0px' });

      var observeAll = function () {
        document.querySelectorAll('.reveal:not(.in)').forEach(function (el) { io.observe(el); });
      };
      observeAll();
      // React 18 time-slices the initial render — pick up late nodes.
      setTimeout(observeAll, 250);
      setTimeout(observeAll, 700);

      // If IO never delivered a callback (offscreen/preview iframe), drop the
      // animated state so the default-visible styles apply, and show content.
      setTimeout(function () { if (!ioFired) { forceVisible(root); } }, 1300);
    } else {
      revealAll();
    }

    // Header: transparent over the hero, solid once scrolled past it.
    var header = document.querySelector('.pote-header');
    var hero = document.querySelector('.hero-immersive');
    if (header) {
      var ticking = false;
      var apply = function () {
        ticking = false;
        var h = hero ? hero.offsetHeight : 600;
        if ((window.scrollY || 0) > h - 80) header.classList.add('solid');
        else header.classList.remove('solid');
      };
      window.addEventListener('scroll', function () { if (!ticking) { ticking = true; apply(); setTimeout(apply, 60); } }, { passive: true });
      window.addEventListener('resize', apply, { passive: true });
      apply();
    }
  }

  var tries = 0;
  (function wait() {
    if (document.querySelector('.hero-immersive') || tries > 50) { start(); return; }
    tries++; setTimeout(wait, 80);
  })();
})();
