// shared.jsx — atoms, helpers, and hooks shared across sections
var useState = React.useState, useEffect = React.useEffect, useRef = React.useRef;

// Resolve a project-relative asset path to its inlined blob URL when the page
// has been bundled for offline use (window.__resources is keyed by path), and
// fall back to the relative path on the live site.
function assetUrl(p) {
  if (!p) return p;
  var R = (typeof window !== "undefined" && window.__resources) || {};
  return R[p] || p;
}

// --- Logo wordmark ---
function Logo({ height = 26, dark = false }) {
  // dark=true means we're sitting on a LIGHT background (use the dark-ink wordmark)
  var src = dark ? assetUrl("assets/logo-siteworks-light-t.png") : assetUrl("assets/logo-siteworks-dark.png");
  return <img src={src} alt="Siteworks" style={{ height, width: "auto", display: "block", transition: "opacity .2s" }} />;
}

// --- responsive: true when viewport is at/below the breakpoint ---
function useIsMobile(bp = 720) {
  const q = `(max-width: ${bp}px)`;
  const [m, setM] = useState(typeof window !== "undefined" && window.matchMedia(q).matches);
  useEffect(() => {
    const mq = window.matchMedia(q);
    const fn = (e) => setM(e.matches);
    setM(mq.matches);
    mq.addEventListener("change", fn);
    return () => mq.removeEventListener("change", fn);
  }, []);
  return m;
}

// --- scroll-reveal: adds .in/.seen when element enters viewport ---
// .in is also force-added by App's safety net (throttled/offscreen contexts), so it
// can't drive opacity/blur animations safely. .seen is added ONLY by a genuine
// in-viewport intersection (live timeline); .settled lands 1.4s later as a wall-clock
// guarantee. The premium card "materialize" keys off .seen / .settled so it can never
// stay stuck on its hidden 0% frame in throttled/capture contexts.
function useReveal(options = {}) {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let settleTimer;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          el.classList.add("in", "seen");
          settleTimer = setTimeout(() => el.classList.add("settled"), 1400);
          io.unobserve(el);
        }
      });
    }, { threshold: options.threshold ?? 0.18, rootMargin: options.rootMargin ?? "0px 0px -8% 0px" });
    io.observe(el);
    return () => { io.disconnect(); clearTimeout(settleTimer); };
  }, []);
  return ref;
}

// section header block (eyebrow + headline + optional lead)
function SectionHead({ eyebrow, children, lead, align = "left", maxWidth = 640, style }) {
  const ref = useReveal();
  return (
    <div ref={ref} className="sec-head" style={{ maxWidth, margin: align === "center" ? "0 auto" : undefined, textAlign: align, ...style }}>
      <div className="eyebrow" style={{ justifyContent: align === "center" ? "center" : "flex-start" }}>
        <span className="dot" />{eyebrow}
      </div>
      <h2 className="h-section">{children}</h2>
      {lead && <p className="p-lead">{lead}</p>}
    </div>
  );
}

// --- WordWaves: split text into words, fade each up in one of 3 random waves ---
function WordWaves({ text, tokens, base = 0.5, step = 0.12, jitter = 0.03 }) {
  const parts = React.useMemo(() => {
    const arr = tokens || String(text).split(/\s+/).filter(Boolean).map((w) => ({ w }));
    return arr.map((t) => ({ ...t, g: Math.floor(Math.random() * 3), j: (Math.random() * 2 - 1) * jitter }));
  }, []);
  return parts.map((t, i) => (
    <React.Fragment key={i}>
      <span className={"ld-word" + (t.gradient ? " gradient-text" : "")}
        style={{ animationDelay: (base + t.g * step + t.j).toFixed(3) + "s" }}>{t.w}</span>
      {" "}
    </React.Fragment>
  ));
}

// status pill
function Pill({ kind, children }) {
  return <span className={`pill pill-${kind}`}><span className="pdot" />{children}</span>;
}

// tool connection chip
function ToolChip({ icon, children }) {
  return <span className="tool-chip">{icon && <i className={icon} />}{children}</span>;
}

// glossy brand orb — the iconography system
function Orb({ icon, tone = "magenta", size = 48 }) {
  return (
    <span className={`orb orb-${tone}`} style={{ width: size, height: size }}>
      <i className={icon} style={{ fontSize: Math.round(size * 0.44) }} />
    </span>
  );
}

Object.assign(window, { assetUrl, Logo, useReveal, WordWaves, SectionHead, Pill, ToolChip, Orb });
