/* ============================================================
   Helpers: icons, Reveal, Counter, MagneticButton, parallax
   ============================================================ */
const { useState, useEffect, useRef, useCallback } = React;

/* ---- Icon set (inline, stroke-based) ---- */
const Icon = ({ name, ...p }) => {
  const paths = {
    arrow: <><line x1="5" y1="12" x2="19" y2="12" /><polyline points="12 5 19 12 12 19" /></>,
    phone: <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z" />,
    mail: <><rect x="2" y="4" width="20" height="16" rx="2" /><path d="m22 7-10 5L2 7" /></>,
    globe: <><circle cx="12" cy="12" r="10" /><path d="M2 12h20" /><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" /></>,
    star: <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" fill="currentColor" stroke="none" />,
    home: <><path d="M3 9.5 12 3l9 6.5" /><path d="M5 10v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V10" /><path d="M9 21v-6h6v6" /></>,
    building: <><rect x="4" y="3" width="16" height="18" rx="1" /><path d="M9 7h.01M9 11h.01M9 15h.01M15 7h.01M15 11h.01M15 15h.01" /></>,
    chef: <><path d="M6 13.87A4 4 0 0 1 7.41 6a5.11 5.11 0 0 1 1.05-1.54 5 5 0 0 1 7.08 0A5.11 5.11 0 0 1 16.59 6 4 4 0 0 1 18 13.87V21H6Z" /><line x1="6" y1="17" x2="18" y2="17" /></>,
    shield: <><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" /><path d="m9 12 2 2 4-4" /></>,
    clock: <><circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" /></>,
    handshake: <><path d="m11 17 2 2a1 1 0 1 0 3-3" /><path d="m14 14 2.5 2.5a1 1 0 1 0 3-3l-3.88-3.88a3 3 0 0 0-4.24 0l-.88.88a1 1 0 1 1-3-3l2.81-2.81a5.79 5.79 0 0 1 7.06-.87l.47.28a2 2 0 0 0 1.42.25L21 4" /><path d="m21 3 1 11h-2" /><path d="M3 3 2 14l6.5 6.5a1 1 0 1 0 3-3" /><path d="M3 4h8" /></>,
    sparkle: <path d="M12 2l1.8 6.2L20 10l-6.2 1.8L12 18l-1.8-6.2L4 10l6.2-1.8L12 2z" fill="currentColor" stroke="none" />,
    check: <polyline points="20 6 9 17 4 12" />,
    x: <><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></>,
    menu: <><line x1="3" y1="6" x2="21" y2="6" /><line x1="3" y1="12" x2="21" y2="12" /><line x1="3" y1="18" x2="21" y2="18" /></>,
    leaf: <><path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10z" /><path d="M2 21c0-3 1.85-5.36 5.08-6" /></>,
    pin: <><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0z" /><circle cx="12" cy="10" r="3" /></>,
    users: <><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /><circle cx="9" cy="7" r="4" /><path d="M22 21v-2a4 4 0 0 0-3-3.87" /><path d="M16 3.13a4 4 0 0 1 0 7.75" /></>,
    heart: <path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.51 4.04 3 5.5l7 7Z" />,
    target: <><circle cx="12" cy="12" r="10" /><circle cx="12" cy="12" r="6" /><circle cx="12" cy="12" r="2" /></>,
    chevron: <polyline points="6 9 12 15 18 9" />,
    whatsapp: <><path d="M12 2a10 10 0 0 0-8.6 15L2 22l5.1-1.3A10 10 0 1 0 12 2z" /><path d="M9.3 8c.2 0 .4 0 .5.4l.7 1.6c.1.2 0 .4-.1.5l-.6.7c.6 1.1 1.5 2 2.6 2.6l.7-.6c.1-.1.3-.2.5-.1l1.6.7c.4.1.4.3.4.5 0 1-1 1.9-2 2-1 0-3.2-.7-5-2.5S7.2 11.5 7.3 10.5c.1-1 .9-2.1 2-2.5z" /></>
  };
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}>
      {paths[name]}
    </svg>);

};

/* ---- Reveal manager: rect-based, no IntersectionObserver dependency ----
   Works in any browser (and snapshot/non-scrolling harnesses): an element
   reveals as soon as its top is within the viewport band, checked on scroll,
   resize, an initial rAF burst, and a final safety pass. */
const RevealMgr = (() => {
  const items = new Set();
  let raf = 0;
  const band = () => (window.innerHeight || document.documentElement.clientHeight || 800) * 0.92;
  const check = () => {
    const limit = band();
    for (const it of [...items]) {
      const el = it.el;
      if (!el || !el.isConnected) {items.delete(it);continue;}
      const r = el.getBoundingClientRect();
      if (r.top < limit && r.bottom > -80) {it.cb();items.delete(it);}
    }
  };
  const schedule = () => {if (raf) return;raf = requestAnimationFrame(() => {raf = 0;check();});};
  if (typeof window !== "undefined" && !window.__revealMgrInit) {
    window.__revealMgrInit = true;
    window.addEventListener("scroll", schedule, { passive: true });
    window.addEventListener("resize", schedule);
    // initial burst to catch fonts/layout settling
    let n = 0;
    (function burst() {check();if (n++ < 90) requestAnimationFrame(burst);})();
    // safety net: never leave content permanently hidden
    setTimeout(() => {for (const it of [...items]) {it.cb();items.delete(it);}}, 3500);
  }
  return { add(el, cb) {items.add({ el, cb });schedule();} };
})();

const Reveal = ({ children, delay = 0, as: Tag = "div", className = "", ...rest }) => {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    RevealMgr.add(el, () => setSeen(true));
  }, []);
  const d = delay ? ` d${delay}` : "";
  return <Tag ref={ref} className={`reveal${d} ${seen ? "in" : ""} ${className}`} {...rest}>{children}</Tag>;
};

/* ---- Count-up number ---- */
const Counter = ({ to, suffix = "", prefix = "", dur = 1600, decimals = 0 }) => {
  const ref = useRef(null);
  const [val, setVal] = useState(0);
  const started = useRef(false);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    RevealMgr.add(el, () => {
      if (started.current) return;
      started.current = true;
      const t0 = performance.now();
      const tick = (t) => {
        const p = Math.min((t - t0) / dur, 1);
        const eased = 1 - Math.pow(1 - p, 3);
        setVal(to * eased);
        if (p < 1) requestAnimationFrame(tick);
      };
      requestAnimationFrame(tick);
    });
  }, [to, dur]);
  const display = decimals ? val.toFixed(decimals) : Math.round(val).toString();
  return <span ref={ref}>{prefix}{display}{suffix}</span>;
};

/* ---- Magnetic button wrapper ---- */
const Magnetic = ({ children, strength = 0.32, className = "", ...rest }) => {
  const ref = useRef(null);
  const onMove = useCallback((e) => {
    const el = ref.current;if (!el) return;
    const r = el.getBoundingClientRect();
    const x = (e.clientX - r.left - r.width / 2) * strength;
    const y = (e.clientY - r.top - r.height / 2) * strength;
    el.style.transform = `translate(${x}px, ${y}px)`;
  }, [strength]);
  const reset = useCallback(() => {if (ref.current) ref.current.style.transform = "";}, []);
  return (
    <span ref={ref} onMouseMove={onMove} onMouseLeave={reset}
    style={{ display: "inline-flex", transition: "transform .4s cubic-bezier(.2,.7,.2,1)" }} className={className} {...rest}>
      {children}
    </span>);

};

/* ---- Parallax-on-scroll wrapper ---- */
const Parallax = ({ children, speed = 0.12, className = "", style = {} }) => {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;if (!el) return;
    let raf = 0;
    const onScroll = () => {
      cancelAnimationFrame(raf);
      raf = requestAnimationFrame(() => {
        const r = el.getBoundingClientRect();
        const center = r.top + r.height / 2 - window.innerHeight / 2;
        el.style.transform = `translateY(${center * -speed}px)`;
      });
    };
    window.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => {window.removeEventListener("scroll", onScroll);cancelAnimationFrame(raf);};
  }, [speed]);
  return <div ref={ref} className={className} style={{ willChange: "transform", ...style }}>{children}</div>;
};

const Stars = ({ n = 5 }) =>
<span className="stars">{Array.from({ length: n }).map((_, i) => <Icon key={i} name="star" />)}</span>;


const Placeholder = ({ label, dark = false }) =>
<div className={`ph ${dark ? "dark" : ""}`}><span className="ph-tag">{label}</span></div>;


/* ---- PhotoSlot: drag-and-drop, user-fillable image (persists) ---- */
const UNSPLASH = "https://images.unsplash.com/";
const photoUrl = (p, w = 1400) => `${UNSPLASH}${p}?fm=jpg&q=75&w=${w}&auto=format&fit=crop`;

const PhotoSlot = ({ id, label, photo, w = 1400, fit = "cover" }) =>
<image-slot
  id={id}
  placeholder={label}
  fit={fit}
  shape="rect"
  {...photo ? { src: photoUrl(photo, w) } : {}}
  style={{ display: "block", width: "100%", height: "100%" }}>
</image-slot>;


Object.assign(window, { Icon, Reveal, Counter, Magnetic, Parallax, Stars, Placeholder, PhotoSlot });