/* ====================== shared components ====================== */
const { useState, useEffect, useRef, useCallback } = React;

/* simple stroke icons — geometric, minimal */
function Icon({ name, size = 26 }) {
  const s = { width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: "currentColor", strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round" };
  const P = {
    house:  <g><path d="M3 11 12 3l9 8" /><path d="M5 10v10h14V10" /><path d="M10 20v-5h4v5" /></g>,
    box:    <g><path d="M3 7l9-4 9 4-9 4-9-4Z" /><path d="M3 7v10l9 4 9-4V7" /><path d="M12 11v10" /></g>,
    loupe:  <g><circle cx="10.5" cy="10.5" r="6.5" /><path d="M15.5 15.5 21 21" /></g>,
    lamp:   <g><path d="M8 3h8l3 7H5l3-7Z" /><path d="M12 10v8" /><path d="M8 21h8" /></g>,
    screen: <g><rect x="3" y="4" width="18" height="12" rx="1" /><path d="M8 20h8" /><path d="M12 16v4" /></g>,
    heart:  <g><path d="M12 20s-7-4.4-9-8.5C1.5 8 3 4.5 6.5 4.5c2 0 3.2 1.2 4 2.3 .8-1.1 2-2.3 4-2.3C18 4.5 19.5 8 18 11.5 16 15.6 12 20 12 20Z" /></g>,
    phone:  <g><path d="M5 3h3l1.6 5-2 1.4a12 12 0 0 0 5 5l1.4-2L19 16v3a2 2 0 0 1-2 2A15 15 0 0 1 4 8a2 2 0 0 1 1-5Z" /></g>,
    mail:   <g><rect x="3" y="5" width="18" height="14" rx="1" /><path d="m3 7 9 6 9-6" /></g>,
    pin:    <g><path d="M12 21s-6-5.3-6-10a6 6 0 0 1 12 0c0 4.7-6 10-6 10Z" /><circle cx="12" cy="11" r="2.2" /></g>,
    star:   <g><path d="M12 3.5 14.3 9l5.7.5-4.3 3.8 1.3 5.6L12 16l-5 2.9 1.3-5.6L4 9.5 9.7 9 12 3.5Z" /></g>,
    cart:   <g><circle cx="9" cy="20" r="1.4" /><circle cx="18" cy="20" r="1.4" /><path d="M2 3h3l2.4 12.5h10.2L20 7H6.5" /></g>,
    arrow:  <g><path d="M5 12h14" /><path d="m13 6 6 6-6 6" /></g>,
    check:  <g><path d="m4 12 5 5L20 6" /></g>,
    clock:  <g><circle cx="12" cy="12" r="8.5" /><path d="M12 7v5l3.5 2" /></g>,
    cal:    <g><rect x="3" y="5" width="18" height="16" rx="1" /><path d="M3 9h18M8 3v4M16 3v4" /></g>,
  };
  return <svg {...s} aria-hidden="true">{P[name] || null}</svg>;
}

/* striped placeholder image with mono label */
function Placeholder({ label, tone = "", style, className = "", labelPos = "bl" }) {
  return (
    <div className={`ph ${tone} ${className}`} style={style}>
      {label && <span className="ph-label">{label}</span>}
    </div>
  );
}

/* filled facebook glyph (Icon set is stroke-based; this one is filled) */
function FacebookIcon({ size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M13.5 21v-7h2.35l.45-3H13.5V9.05c0-.87.27-1.46 1.5-1.46h1.45V5.06A20 20 0 0 0 13.9 5C11.6 5 10 6.4 10 8.74V11H7.5v3H10v7h3.5z" />
    </svg>
  );
}

/* user-fillable image slot (drag-drop real photos; persists). `src` = free-to-use default. */
function Slot({ id, label, tone = "", shape = "rect", radius = 0, fit = "cover", src, style }) {
  const t = tone.replace("tone-", "");
  const props = {
    id, shape, radius: String(radius), fit,
    placeholder: label || "Drop a photo",
    "data-tone": t,
    style: { width: "100%", height: "100%", display: "block", ...style },
  };
  if (src) props.src = src;
  return <image-slot {...props}></image-slot>;
}

/* DEDICATED LOGO — vintage seal / maker's mark */
/* DEDICATED LOGO — Dollye Deals emblem (user-supplied, transparent PNG) */
function LogoSeal({ size = 120, className = "" }) {
  return (
    <img className={`seal ${className}`} src="assets/dollye-deals-logo.png"
         width={size} height={size}
         alt="Dollye Deals — Estate Sales" />
  );
}

function SectionHead({ eyebrow, eyebrowTone, title, lede, id }) {
  return (
    <div className="section-head reveal" id={id}>
      {eyebrow && <div className={`eyebrow ${eyebrowTone || ""}`}>{eyebrow}</div>}
      <h2 className="display">{title}</h2>
      {lede && <p className="lede">{lede}</p>}
    </div>
  );
}

function Stamp({ children, icon }) {
  return <span className="stamp">{icon && <Icon name={icon} size={14} />}{children}</span>;
}

/* IntersectionObserver reveal — re-scans on DOM changes so filtered/re-mounted
   items (gallery, sales, shop) also reveal, not just the ones present at mount */
function useReveals() {
  useEffect(() => {
    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 -8% 0px" });
    const scan = () => document.querySelectorAll(".reveal:not(.in)").forEach((el) => io.observe(el));
    scan();
    const mo = new MutationObserver(scan);
    mo.observe(document.body, { childList: true, subtree: true });
    return () => { io.disconnect(); mo.disconnect(); };
  }, []);
}

Object.assign(window, { Icon, FacebookIcon, Placeholder, Slot, LogoSeal, SectionHead, Stamp, useReveals, BIZ, SERVICES, SALES, GALLERY, GALLERY_CATS, SHOP, SHOP_CATS, FAQS, STATS });
