/* Shared atoms for Aspire Smiles: Btn, Stars, useReveal, useScrolled */
(function () {
  const { useState, useEffect } = React;
  const Icon = window.Icon;

  /* Button - Aspire vocabulary.
     variants:
       teal / gold  -> big rectangular CTA (.cta)
       navy / outline -> secondary pill (.pill)
       link -> teal text link with arrow (.tlink) */
  const Btn = ({ variant = "teal", size, block, href, onClick, children, type, arrow, onDark }) => {
    let cls, tail = null;
    if (variant === "link") {
      cls = "tlink";
      tail = arrow ? React.createElement(Icon, { name: "arrowR" }) : null;
    } else if (variant === "navy" || variant === "outline") {
      cls = ["pill", "pill--" + variant, onDark && "on-dark"].filter(Boolean).join(" ");
      tail = arrow ? React.createElement(Icon, { name: "arrowR" }) : null;
    } else {
      cls = ["cta", "cta--" + variant, size === "lg" && "cta--lg", block && "cta--block"].filter(Boolean).join(" ");
      tail = arrow ? React.createElement(Icon, { name: "arrowR" }) : null;
    }
    if (href) return React.createElement("a", { className: cls, href, onClick }, children, tail);
    return React.createElement("button", { className: cls, onClick, type: type || "button" }, children, tail);
  };

  const Stars = ({ n = 5, className }) =>
    React.createElement("span", { className: "stars " + (className || ""), "aria-label": n + " out of 5 stars" },
      Array.from({ length: n }, (_, i) =>
        React.createElement(Icon, { key: i, name: "star", style: { width: 17, height: 17, fill: "currentColor" } })));

  function useReveal() {
    useEffect(() => {
      const els = document.querySelectorAll(".reveal:not(.in)");
      if (!("IntersectionObserver" in window)) { els.forEach(e => e.classList.add("in")); return; }
      const io = new IntersectionObserver((entries) => {
        entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } });
      }, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" });
      els.forEach(e => io.observe(e));
      return () => io.disconnect();
    });
  }

  /* Restrained, GPU-composited scroll parallax for a full-width image.
     Desktop only (min-width:981px) and disabled under prefers-reduced-motion -
     both are re-checked live so resizing/toggling doesn't leave a stale transform. */
  function useParallax(ref, { differential = 0.12, enabled = true } = {}) {
    useEffect(() => {
      const el = ref.current;
      if (!el || !enabled) return;

      const mqDesktop = window.matchMedia("(min-width: 981px)");
      const mqReduced = window.matchMedia("(prefers-reduced-motion: reduce)");
      let ticking = false;
      let active = false;

      const apply = () => {
        ticking = false;
        if (!active) return;
        const rect = el.parentElement.getBoundingClientRect();
        const vh = window.innerHeight || document.documentElement.clientHeight;
        const progress = (rect.top + rect.height / 2 - vh / 2) / (vh + rect.height);
        const range = rect.height * differential;
        const y = Math.max(-range, Math.min(range, progress * range * -1));
        el.style.transform = "translate3d(0, " + y.toFixed(1) + "px, 0)";
      };

      const onScroll = () => {
        if (ticking) return;
        ticking = true;
        requestAnimationFrame(apply);
      };

      const sync = () => {
        const shouldRun = mqDesktop.matches && !mqReduced.matches;
        if (shouldRun && !active) {
          active = true;
          el.style.willChange = "transform";
          window.addEventListener("scroll", onScroll, { passive: true });
          window.addEventListener("resize", onScroll, { passive: true });
          onScroll();
        } else if (!shouldRun && active) {
          active = false;
          el.style.transform = "";
          el.style.willChange = "";
          window.removeEventListener("scroll", onScroll);
          window.removeEventListener("resize", onScroll);
        }
      };

      sync();
      mqDesktop.addEventListener("change", sync);
      mqReduced.addEventListener("change", sync);

      return () => {
        window.removeEventListener("scroll", onScroll);
        window.removeEventListener("resize", onScroll);
        mqDesktop.removeEventListener("change", sync);
        mqReduced.removeEventListener("change", sync);
      };
    }, [ref, differential, enabled]);
  }

  /* tracks whether the page has scrolled past `y` (for the frosted header /
     scroll-reveal sticky CTA). Reads both window and the scrolling element so it
     works whether the document or a scroll container moves. */
  function useScrolled(y = 60) {
    const [s, setS] = useState(false);
    useEffect(() => {
      const pos = () => Math.max(
        window.scrollY || 0,
        (document.scrollingElement && document.scrollingElement.scrollTop) || 0,
        document.documentElement.scrollTop || 0,
        document.body.scrollTop || 0
      );
      const on = () => setS(pos() > y);
      on();
      window.addEventListener("scroll", on, { passive: true });
      document.addEventListener("scroll", on, { passive: true, capture: true });
      return () => {
        window.removeEventListener("scroll", on);
        document.removeEventListener("scroll", on, { capture: true });
      };
    }, [y]);
    return s;
  }

  /* Global: flag the document once scrolled past ~520px (where the sticky mobile
     CTA appears) so the top header can hide itself on mobile. Runs once per page;
     harmless on pages with no .site-header (e.g. thank-you pages). */
  (function () {
    var THRESH = 520;
    function pos() {
      return Math.max(window.scrollY || 0,
        (document.scrollingElement && document.scrollingElement.scrollTop) || 0,
        document.documentElement.scrollTop || 0, document.body.scrollTop || 0);
    }
    function on() { document.documentElement.classList.toggle("is-scrolled-past", pos() > THRESH); }
    on();
    window.addEventListener("scroll", on, { passive: true });
    document.addEventListener("scroll", on, { passive: true, capture: true });
  })();

  Object.assign(window, { Btn, Stars, useReveal, useScrolled, useParallax });
})();
