// Shared hooks + primitives
const { useState, useEffect, useRef, useMemo, useCallback, useLayoutEffect } = React;

// IntersectionObserver hook — fires once when element enters view
function useInView(options = { threshold: 0.15, rootMargin: "0px 0px -10% 0px" }) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const obs = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          setInView(true);
          obs.disconnect();
        }
      });
    }, options);
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, []);
  return [ref, inView];
}

// Tracks scrollY (throttled via rAF)
function useScrollY() {
  const [y, setY] = useState(0);
  useEffect(() => {
    let raf = 0;
    const onScroll = () => {
      if (raf) return;
      raf = requestAnimationFrame(() => {
        setY(window.scrollY);
        raf = 0;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => window.removeEventListener("scroll", onScroll);
  }, []);
  return y;
}

// Element-relative scroll progress: 0 before it enters, 1 after it exits
function useScrollProgress(ref) {
  const [p, setP] = useState(0);
  useEffect(() => {
    let raf = 0;
    const tick = () => {
      raf = 0;
      if (!ref.current) return;
      const r = ref.current.getBoundingClientRect();
      const vh = window.innerHeight;
      const total = r.height + vh;
      const scrolled = vh - r.top;
      setP(Math.max(0, Math.min(1, scrolled / total)));
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(tick); };
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    tick();
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
    };
  }, [ref]);
  return p;
}

// Reveal wrapper — slides up + fades in
function Reveal({ children, delay = 0, y = 24, as: As = "div", className = "", style = {}, ...rest }) {
  const [ref, vis] = useInView();
  return (
    <As
      ref={ref}
      className={className}
      style={{
        transform: vis ? "translateY(0)" : `translateY(${y}px)`,
        opacity: vis ? 1 : 0,
        transition: `transform 900ms cubic-bezier(.2,.7,.1,1) ${delay}ms, opacity 700ms ease ${delay}ms`,
        ...style,
      }}
      {...rest}
    >
      {children}
    </As>
  );
}

// Split each character of text for stagger
function SplitText({ text, delay = 0, stagger = 18, className = "", style = {} }) {
  const [ref, vis] = useInView();
  const words = text.split(" ");
  return (
    <span ref={ref} className={className} style={{ display: "inline-block", ...style }}>
      {words.map((w, wi) => (
        <span key={wi} style={{ display: "inline-block", whiteSpace: "nowrap", marginRight: "0.25em" }}>
          {w.split("").map((ch, ci) => {
            const order = words.slice(0, wi).reduce((a, x) => a + x.length, 0) + ci;
            return (
              <span
                key={ci}
                style={{
                  display: "inline-block",
                  transform: vis ? "translateY(0)" : "translateY(110%)",
                  opacity: vis ? 1 : 0,
                  transition: `transform 900ms cubic-bezier(.2,.75,.1,1) ${delay + order * stagger}ms, opacity 600ms ease ${delay + order * stagger}ms`,
                }}
              >
                {ch}
              </span>
            );
          })}
        </span>
      ))}
    </span>
  );
}

// Pill
function Pill({ children, color, style = {} }) {
  return (
    <span className="mono" style={{
      display: "inline-flex", alignItems: "center", gap: 8,
      fontSize: 11, textTransform: "uppercase", letterSpacing: "0.12em",
      color: color || "var(--ink-dim)",
      padding: "6px 10px",
      border: "1px solid var(--line-strong)",
      borderRadius: 999,
      background: "rgba(255,255,255,0.02)",
      ...style,
    }}>
      <span style={{
        width: 6, height: 6, borderRadius: 999,
        background: color || "var(--ink-dim)",
        boxShadow: color ? `0 0 8px ${color}` : "none",
      }} />
      {children}
    </span>
  );
}

// Big CTA button
function CTA({ children, onClick, accent = "var(--ink)", inverse = false, size = "md", style = {} }) {
  const [h, setH] = useState(false);
  const sizes = {
    sm: { px: 14, py: 8, fs: 13 },
    md: { px: 20, py: 12, fs: 14 },
    lg: { px: 26, py: 16, fs: 15 },
  };
  const s = sizes[size];
  const textColor = inverse ? "#0b0b0d" : "var(--bg)";
  const bg = inverse ? accent : "var(--ink)";
  return (
    <button
      onClick={onClick}
      onMouseEnter={() => setH(true)}
      onMouseLeave={() => setH(false)}
      style={{
        display: "inline-flex", alignItems: "center", gap: 10,
        padding: `${s.py}px ${s.px}px`,
        fontSize: s.fs, fontWeight: 500,
        color: textColor,
        background: bg,
        borderRadius: 999,
        transition: "transform 220ms ease, box-shadow 300ms ease",
        transform: h ? "translateY(-2px)" : "translateY(0)",
        boxShadow: h ? "0 14px 30px -12px rgba(20,20,26,0.35)" : "0 0 0 rgba(0,0,0,0)",
        ...style,
      }}
    >
      <span style={{
        position: "relative", display: "inline-block",
        height: s.fs * 1.15, overflow: "hidden",
        lineHeight: `${s.fs * 1.15}px`,
      }}>
        <span style={{
          display: "block", whiteSpace: "nowrap",
          transform: h ? `translateY(-${s.fs * 1.15}px)` : "translateY(0)",
          transition: "transform 360ms cubic-bezier(.6,.05,.2,1)",
        }}>{children}</span>
        <span style={{
          display: "block", whiteSpace: "nowrap",
          transform: h ? `translateY(-${s.fs * 1.15}px)` : "translateY(0)",
          transition: "transform 360ms cubic-bezier(.6,.05,.2,1)",
        }}>{children}</span>
      </span>
      <span style={{
        display: "inline-block", transition: "transform 280ms cubic-bezier(.6,.05,.2,1)",
        transform: h ? "translateX(4px) rotate(-45deg)" : "translateX(0) rotate(0)",
      }}>→</span>
    </button>
  );
}

function GhostCTA({ children, onClick, style = {} }) {
  const [h, setH] = useState(false);
  return (
    <button
      onClick={onClick}
      onMouseEnter={() => setH(true)}
      onMouseLeave={() => setH(false)}
      style={{
        display: "inline-flex", alignItems: "center", gap: 10,
        padding: "12px 20px",
        fontSize: 14, fontWeight: 500,
        color: "var(--ink)",
        background: h ? "rgba(255,255,255,0.06)" : "rgba(255,255,255,0.02)",
        border: "1px solid var(--line-strong)",
        borderRadius: 999,
        transition: "all 200ms ease",
        ...style,
      }}
    >
      {children}
      <span style={{ opacity: 0.6, transition: "transform 250ms", transform: h ? "translateX(3px)" : "none" }}>→</span>
    </button>
  );
}

// Section wrapper
function Section({ children, id, pad = "120px 0", style = {} }) {
  return (
    <section id={id} style={{ padding: pad, position: "relative", ...style }}>
      <div style={{ maxWidth: 1280, margin: "0 auto", padding: "0 32px" }}>
        {children}
      </div>
    </section>
  );
}

// eyebrow label
function Eyebrow({ children, color }) {
  return (
    <div className="mono" style={{
      fontSize: 11, textTransform: "uppercase", letterSpacing: "0.18em",
      color: color || "var(--ink-mute)",
      display: "inline-flex", alignItems: "center", gap: 10,
    }}>
      <span style={{ width: 18, height: 1, background: "currentColor", opacity: 0.6 }} />
      {children}
    </div>
  );
}

// Striped placeholder
function Placeholder({ label = "placeholder", h = 200, color = "var(--ink-dim)", style = {} }) {
  return (
    <div style={{
      height: h, borderRadius: 10, position: "relative", overflow: "hidden",
      background: `repeating-linear-gradient(135deg, rgba(255,255,255,0.03) 0 10px, rgba(255,255,255,0.01) 10px 20px)`,
      border: "1px dashed var(--line-strong)",
      display: "flex", alignItems: "center", justifyContent: "center",
      ...style,
    }}>
      <span className="mono" style={{ fontSize: 11, color, letterSpacing: "0.1em", textTransform: "uppercase" }}>
        {label}
      </span>
    </div>
  );
}

Object.assign(window, {
  useInView, useScrollY, useScrollProgress,
  Reveal, SplitText, Pill, CTA, GhostCTA, Section, Eyebrow, Placeholder,
});
