/* helpers.jsx — shared primitives: Placeholder, line Icons, useReveal */
const { useState, useEffect, useRef, useCallback } = React;

/* Reveal-on-scroll: adds .in when element enters viewport.
   Uses a scroll/resize check (robust across iframes & offscreen previews). */
function useReveal() {
  useEffect(() => {
    document.documentElement.classList.add("js-reveal");
    let raf = 0;
    const check = () => {
      raf = 0;
      const vh = window.innerHeight || document.documentElement.clientHeight;
      document.querySelectorAll(".reveal:not(.in)").forEach((el) => {
        const r = el.getBoundingClientRect();
        // reveal once the element's top crosses ~88% of the viewport
        if (r.top < vh * 0.88 && r.bottom > 0) el.classList.add("in");
      });
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(check); };
    // initial passes (let layout + fonts settle)
    check();
    requestAnimationFrame(check);
    const t1 = setTimeout(check, 250);
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      clearTimeout(t1);
      if (raf) cancelAnimationFrame(raf);
    };
  }, []);
}

/* Marked image placeholder */
function Placeholder({ label, sub, dark, style, className = "" }) {
  return (
    <div className={`ph ${dark ? "on-dark" : ""} ${className}`} style={style}>
      <div className="ph-label">
        [ {label} ]
        {sub && <><br /><span style={{ opacity: 0.7, fontSize: "10px" }}>{sub}</span></>}
      </div>
    </div>
  );
}

/* Minimal stroke icons (line-art, medical-tech) */
function Icon({ name, size = 26, stroke = 1.6 }) {
  const common = {
    width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round",
  };
  const paths = {
    scan: <><path d="M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2" /><path d="M7 12h10" /></>,
    layers: <><path d="M12 3 3 8l9 5 9-5-9-5Z" /><path d="m3 13 9 5 9-5M3 18l9 5 9-5" /></>,
    cpu: <><rect x="6" y="6" width="12" height="12" rx="2" /><path d="M9 1v3M15 1v3M9 20v3M15 20v3M1 9h3M1 15h3M20 9h3M20 15h3" /><rect x="10" y="10" width="4" height="4" /></>,
    target: <><circle cx="12" cy="12" r="9" /><circle cx="12" cy="12" r="4.5" /><circle cx="12" cy="12" r="0.6" /></>,
    shield: <><path d="M12 3 4 6v6c0 5 3.5 7.5 8 9 4.5-1.5 8-4 8-9V6l-8-3Z" /><path d="m9 12 2 2 4-4" /></>,
    pulse: <><path d="M3 12h4l2.5-7 5 14L17 12h4" /></>,
    tooth: <><path d="M12 3c-2.5 0-3.5 1.2-5 1.2C5.3 4.2 4 5.6 4 8c0 2 .6 3.5 1.2 6 .5 2 .6 5 1.8 5 1.4 0 1.2-3.5 2-5.5.4-1 1.2-1 1.5 0 .8 2 .6 5.5 2 5.5 1.2 0 1.3-3 1.8-5C19.4 11.5 20 10 20 8c0-2.4-1.3-3.8-3-3.8-1.5 0-2.5-1.2-5-1.2Z" /></>,
    chart: <><path d="M3 3v18h18" /><path d="M7 14l3-4 3 2 4-6" /></>,
    award: <><circle cx="12" cy="9" r="6" /><path d="M9 14.5 7 22l5-3 5 3-2-7.5" /></>,
    book: <><path d="M4 5a2 2 0 0 1 2-2h13v16H6a2 2 0 0 0-2 2V5Z" /><path d="M4 19a2 2 0 0 0 2 2h13" /></>,
    globe: <><circle cx="12" cy="12" r="9" /><path d="M3 12h18M12 3c3 3.5 3 14.5 0 18M12 3c-3 3.5-3 14.5 0 18" /></>,
    arrow: <path d="M5 12h14M13 6l6 6-6 6" />,
    check: <path d="M5 12.5 10 17l9-10" />,
    play: <path d="M8 5v14l11-7L8 5Z" />,
    plus: <path d="M12 5v14M5 12h14" />,
    quote: <><path d="M9 7H5v6h4v-2H7c0-1.5.5-2.5 2-3V7ZM19 7h-4v6h4v-2h-2c0-1.5.5-2.5 2-3V7Z" /></>,
    phone: <path d="M5 4h4l2 5-2.5 1.5a11 11 0 0 0 5 5L15 13l5 2v4a2 2 0 0 1-2 2A16 16 0 0 1 3 6a2 2 0 0 1 2-2Z" />,
    mail: <><rect x="3" y="5" width="18" height="14" rx="2" /><path d="m3 7 9 6 9-6" /></>,
    pin: <><path d="M12 21s7-5.5 7-11a7 7 0 0 0-14 0c0 5.5 7 11 7 11Z" /><circle cx="12" cy="10" r="2.5" /></>,
    instagram: <><rect x="3" y="3" width="18" height="18" rx="5" /><circle cx="12" cy="12" r="4" /><circle cx="17.5" cy="6.5" r="0.6" fill="currentColor" stroke="none" /></>,
    card: <><rect x="2.5" y="5" width="19" height="14" rx="2.5" /><path d="M2.5 9.5h19" /><path d="M6 14.5h4" /></>,
    search: <><circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" /></>,
  };
  return <svg {...common} aria-hidden="true">{paths[name] || null}</svg>;
}

Object.assign(window, { useReveal, Placeholder, Icon });
