/* ===========================================================
   Shared UI components
   =========================================================== */

/* ---- line icons (simple, single-stroke) ---- */
const ICONS = {
  search: "M21 21l-4.3-4.3M11 19a8 8 0 110-16 8 8 0 010 16z",
  cart: "M3 4h2l2.4 12.2a2 2 0 002 1.6h8.7a2 2 0 002-1.6L23 8H6M9 22a1 1 0 100-2 1 1 0 000 2zm9 0a1 1 0 100-2 1 1 0 000 2z",
  quote: "M8 3h8a2 2 0 012 2v16l-6-3-6 3V5a2 2 0 012-2zM9 8h6M9 12h6",
  menu: "M3 6h18M3 12h18M3 18h18",
  close: "M6 6l12 12M18 6L6 18",
  chevron: "M9 6l6 6-6 6",
  chevdown: "M6 9l6 6 6-6",
  phone: "M5 4h3l2 5-2 1a12 12 0 006 6l1-2 5 2v3a2 2 0 01-2 2A16 16 0 013 6a2 2 0 012-2z",
  check: "M20 6L9 17l-5-5",
  plus: "M12 5v14M5 12h14",
  minus: "M5 12h14",
  arrow: "M5 12h14M13 6l6 6-6 6",
  pin: "M12 21s-7-6.2-7-11a7 7 0 1114 0c0 4.8-7 11-7 11zm0-8.5a2.5 2.5 0 100-5 2.5 2.5 0 000 5z",
  truck: "M3 6h11v9H3zM14 9h4l3 3v3h-7zM7 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm10 0a1.5 1.5 0 100-3 1.5 1.5 0 000 3z",
  clock: "M12 7v5l3 2M12 21a9 9 0 110-18 9 9 0 010 18z",
  shield: "M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6z",
  mail: "M3 5h18v14H3zM3 6l9 7 9-7",
  star: "M12 3l2.7 5.5 6 .9-4.3 4.2 1 6-5.4-2.8L6.6 19.6l1-6L3.3 9.4l6-.9z",
  spark: "M12 3v6M12 15v6M3 12h6M15 12h6",
  filter: "M3 5h18M6 12h12M10 19h4",
  user: "M12 12a4 4 0 100-8 4 4 0 000 8zm-7 8a7 7 0 0114 0z",
  lock: "M6 11h12v9H6zM8 11V8a4 4 0 018 0v3",
  wrench: "M14 7a3.5 3.5 0 01-4.6 4.6L5 16l3 3 4.4-4.4A3.5 3.5 0 0017 10l-1.5-1.5",
};
function Icon({ name, size = 20, stroke = 2, className, style }) {
  return React.createElement("svg", {
    width: size, height: size, viewBox: "0 0 24 24", fill: "none",
    stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", strokeLinejoin: "round",
    className, style, "aria-hidden": "true"
  }, React.createElement("path", { d: ICONS[name] || "" }));
}

/* ---- Logo: real shift-lever mark + wordmark ---- */
function Logo({ size = 34, light = false }) {
  return React.createElement(Link, { to: "/", className: "logo", "aria-label": "D&W Truck — home" },
    React.createElement("span", { className: "logo-mark", style: { width: size, height: size } },
      React.createElement("img", { src: "assets/logo.png", width: size, height: size, alt: "D&W Truck",
        style: { width: size, height: size, objectFit: "contain", display: "block" } })
    ),
    React.createElement("span", { className: "logo-text", style: { color: light ? "#fff" : "var(--ink)" } },
      React.createElement("strong", null, "DWTruck"),
      React.createElement("span", { className: "logo-sub" }, "SOLUTIONS")
    )
  );
}

/* ---- scroll reveal ---- */
function useReveal() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current; if (!el) return;
    if (!("IntersectionObserver" in window) || window.matchMedia("(prefers-reduced-motion: reduce)").matches) { el.classList.add("in"); return; }
    const io = new IntersectionObserver((ents) => {
      ents.forEach(e => { if (e.isIntersecting) { e.target.classList.add("in"); io.unobserve(e.target); } });
    }, { threshold: 0.08, rootMargin: "0px 0px -6% 0px" });
    io.observe(el);
    const t = setTimeout(() => { if (el && !el.classList.contains("in")) {
      const r = el.getBoundingClientRect();
      if (r.top < window.innerHeight + 80) el.classList.add("in");
    } }, 400);
    return () => { io.disconnect(); clearTimeout(t); };
  }, []);
  return ref;
}
function Reveal({ children, delay = 0, className = "", as = "div", style = {} }) {
  const ref = useReveal();
  return React.createElement(as, { ref, className: "reveal " + className, style: { transitionDelay: delay + "ms", ...style } }, children);
}

/* ---- placeholder image box ---- */
function PH({ label, ratio = "4/3", dark = false, className = "", style = {} }) {
  return React.createElement("div", {
    className: "ph " + (dark ? "ph-dark " : "") + className,
    "data-label": label, style: { aspectRatio: ratio, ...style }
  });
}

/* ---- real image with graceful placeholder fallback ---- */
function Img({ src, alt, ratio = "4/3", className = "", phLabel = "part photo" }) {
  const [err, setErr] = useState(false);
  if (!src || err) return React.createElement(PH, { label: phLabel, ratio, className });
  return React.createElement("img", {
    src, alt: alt || "", loading: "lazy", className: "img " + className,
    style: { aspectRatio: ratio, width: "100%", height: "100%", objectFit: "cover", display: "block" },
    onError: () => setErr(true)
  });
}

/* ---- price block ---- */
function Price({ variant, size = "md" }) {
  if (variant.price === null || variant.price === undefined)
    return React.createElement(Link, { to: "/quote", className: "price-call price-quote-link",
      onClick: (e) => e.stopPropagation() }, "Request a quote →");
  return React.createElement("span", { className: "price price-" + size },
    variant.compare_at_price ? React.createElement("span", { className: "price-was" }, money(variant.compare_at_price)) : null,
    React.createElement("span", { className: "price-now" }, money(variant.price)),
    variant.core_charge ? React.createElement("span", { className: "price-core" }, "+ " + money(variant.core_charge) + " core") : null
  );
}

/* ---- Add to quote button (used everywhere) ---- */
function AddToQuoteBtn({ product, variant, size = "sm", block = false, label = "Add to quote" }) {
  const quote = useQuote(); const toast = useToast();
  const onClick = (e) => {
    e.preventDefault(); e.stopPropagation();
    quote.addItem({ variant_id: variant.id, sku: variant.sku, name: product.name, product_slug: product.slug,
      price: variant.price, core_charge: variant.core_charge, image: product.images[0],
      attributes: variant.attributes, part_numbers: variant.part_numbers });
    toast.push("Added to quote", { icon: "quote", action: { to: "/quote", label: "View quote" } });
  };
  return React.createElement("button", {
    className: "btn btn-ghost btn-" + size + (block ? " btn-block" : "") + " atq",
    onClick
  }, React.createElement(Icon, { name: "quote", size: 16 }), label);
}

/* ---- Product card ---- */
function ProductCard({ product }) {
  const v = product.variants[0];
  const { navigate } = useRouter();
  const orderable = product.is_online_orderable && v.price !== null;
  return React.createElement("article", {
    className: "card pcard", tabIndex: 0,
    onClick: () => navigate("/p/" + product.slug),
    onKeyDown: (e) => { if (e.key === "Enter") navigate("/p/" + product.slug); }
  },
    React.createElement("div", { className: "pcard-media" },
      React.createElement(Img, { src: (product.images && product.images[0]) ? product.images[0].url : "", alt: product.name, ratio: "4/3" }),
      React.createElement("div", { className: "pcard-badges" },
        product.is_reman ? React.createElement("span", { className: "badge badge-reman" }, "Reman") : React.createElement("span", { className: "badge badge-oem" }, "New"),
        !orderable ? React.createElement("span", { className: "badge badge-call" }, "Call") : null
      )
    ),
    React.createElement("div", { className: "pcard-body" },
      React.createElement("div", { className: "pcard-group" }, product.grouping_label),
      React.createElement("h3", { className: "pcard-title" }, product.name),
      React.createElement("div", { className: "pcard-sku mono" }, v.sku),
      React.createElement("div", { className: "pcard-foot" },
        React.createElement(Price, { variant: v, size: "sm" }),
        React.createElement(AddToQuoteBtn, { product, variant: v, label: "Quote" })
      )
    )
  );
}

/* ---- breadcrumbs ---- */
function Crumbs({ items }) {
  return React.createElement("nav", { className: "crumbs", "aria-label": "Breadcrumb" },
    items.map((it, i) => React.createElement(React.Fragment, { key: i },
      i > 0 ? React.createElement(Icon, { name: "chevron", size: 13, className: "crumb-sep" }) : null,
      it.to ? React.createElement(Link, { to: it.to, className: "crumb" }, it.label)
            : React.createElement("span", { className: "crumb crumb-cur" }, it.label)
    ))
  );
}

/* ---- qty stepper ---- */
function Stepper({ value, onChange, min = 1 }) {
  return React.createElement("div", { className: "stepper" },
    React.createElement("button", { onClick: () => onChange(Math.max(min, value - 1)), "aria-label": "Decrease" }, React.createElement(Icon, { name: "minus", size: 15 })),
    React.createElement("input", { type: "text", value, inputMode: "numeric", onChange: e => { const n = parseInt(e.target.value.replace(/\D/g, "")) || min; onChange(Math.max(min, n)); }, "aria-label": "Quantity" }),
    React.createElement("button", { onClick: () => onChange(value + 1), "aria-label": "Increase" }, React.createElement(Icon, { name: "plus", size: 15 }))
  );
}

/* ---- skeleton grid ---- */
function SkeletonCard() {
  return React.createElement("div", { className: "card pcard" },
    React.createElement("div", { className: "sk", style: { aspectRatio: "4/3" } }),
    React.createElement("div", { className: "pcard-body" },
      React.createElement("div", { className: "sk", style: { height: 10, width: "40%", marginBottom: 10 } }),
      React.createElement("div", { className: "sk", style: { height: 16, width: "85%", marginBottom: 8 } }),
      React.createElement("div", { className: "sk", style: { height: 12, width: "55%" } })
    )
  );
}

Object.assign(window, { Icon, Logo, useReveal, Reveal, PH, Img, Price, AddToQuoteBtn, ProductCard, Crumbs, Stepper, SkeletonCard });
