/* ============================================================
   Carzello — shared primitives, icons, formatters, hooks
   ============================================================ */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ---- formatters ---- */
const fmtUSD = (n) => "$" + Number(Math.round(n || 0)).toLocaleString("en-US");
const fmtUSDc = (n) => "$" + Number(n || 0).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const fmtMiles = (n) => Number(n).toLocaleString("en-US") + " mi";
function fmtRemaining(ms) {
  if (ms <= 0) return "Ended";
  const s = Math.floor(ms / 1000);
  const d = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60;
  if (d > 0) return `${d}d ${h}h`;
  if (h > 0) return `${h}:${String(m).padStart(2, "0")}:${String(sec).padStart(2, "0")}`;
  return `${m}:${String(sec).padStart(2, "0")}`;
}
function fmtClock(d) {
  const p = (n) => String(n).padStart(2, "0");
  return `${p(d.getUTCHours())}:${p(d.getUTCMinutes())}:${p(d.getUTCSeconds())}`;
}
function timeAgo(ts) {
  const s = Math.floor((Date.now() - ts) / 1000);
  if (s < 5) return "just now";
  if (s < 60) return s + "s ago";
  const m = Math.floor(s / 60);
  if (m < 60) return m + "m ago";
  const h = Math.floor(m / 60);
  if (h < 24) return h + "h ago";
  return Math.floor(h / 24) + "d ago";
}

/* ---- icons ---- */
const I = {
  search:  (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" {...p}><circle cx="7" cy="7" r="4.5"/><path d="M10.5 10.5 14 14"/></svg>,
  gavel:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" {...p}><path d="M3 11 7 7M5 5l6 6M8 4l4 4M11 1l4 4M2 15h7"/></svg>,
  star:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="m8 1.5 1.9 4.2 4.6.5-3.4 3.1.9 4.6L8 11.6l-4 2.3.9-4.6L1.5 6.2l4.6-.5z"/></svg>,
  starF:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor" {...p}><path d="m8 1.5 1.9 4.2 4.6.5-3.4 3.1.9 4.6L8 11.6l-4 2.3.9-4.6L1.5 6.2l4.6-.5z"/></svg>,
  bell:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M4 7a4 4 0 0 1 8 0v3l1 2H3l1-2zM6.5 13a1.5 1.5 0 0 0 3 0"/></svg>,
  sliders: (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" {...p}><path d="M2 4h7M11 4h3M2 8h3M7 8h7M2 12h9M13 12h1"/><circle cx="10" cy="4" r="1.6"/><circle cx="6" cy="8" r="1.6"/><circle cx="12" cy="12" r="1.6"/></svg>,
  chevron: (p) => <svg aria-hidden="true" className="ic-dir" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" {...p}><path d="M6 4l4 4-4 4"/></svg>,
  chevL:   (p) => <svg aria-hidden="true" className="ic-dir" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" {...p}><path d="M10 4 6 8l4 4"/></svg>,
  chevD:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" {...p}><path d="M4 6l4 4 4-4"/></svg>,
  x:       (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.7" {...p}><path d="M4 4l8 8M12 4l-8 8"/></svg>,
  check:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" {...p}><path d="m3 8 3.5 3.5L13 5"/></svg>,
  truck:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M1 4h8v7H1zM9 7h4l2 2v2h-6zM4 14a1.2 1.2 0 1 0 0-2.4A1.2 1.2 0 0 0 4 14zM12 14a1.2 1.2 0 1 0 0-2.4A1.2 1.2 0 0 0 12 14z"/></svg>,
  doc:     (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M3 1h7l3 3v11H3zM10 1v3h3M5.5 7h5M5.5 9.5h5M5.5 12h3"/></svg>,
  shield:  (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M8 1 2 3v5c0 4 2.5 6 6 7 3.5-1 6-3 6-7V3z"/></svg>,
  clock:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><circle cx="8" cy="8" r="6.5"/><path d="M8 4.5V8l2.5 1.5"/></svg>,
  pin:     (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M8 1c-2.5 0-4.5 2-4.5 4.5C3.5 9 8 15 8 15s4.5-6 4.5-9.5C12.5 3 10.5 1 8 1zM8 7.5a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></svg>,
  car:     (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M2 10v3h2M14 10v3h-2M3 10l1.5-4h7L13 10M3 10h10M5 12h.01M11 12h.01"/></svg>,
  grid:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><rect x="2" y="2" width="5" height="5"/><rect x="9" y="2" width="5" height="5"/><rect x="2" y="9" width="5" height="5"/><rect x="9" y="9" width="5" height="5"/></svg>,
  list:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M5 4h9M5 8h9M5 12h9M2 4h.01M2 8h.01M2 12h.01"/></svg>,
  plus:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.7" {...p}><path d="M8 3v10M3 8h10"/></svg>,
  user:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><circle cx="8" cy="5" r="3"/><path d="M2.5 14c.6-3 3-4.5 5.5-4.5S13 11 13.5 14"/></svg>,
  bolt:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor" {...p}><path d="M9 1 3 9h4l-1 6 6-8H8z"/></svg>,
  tag:     (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M2 2h5l7 7-5 5-7-7zM5 5h.01"/></svg>,
  camera:  (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M2 5h2.5L6 3h4l1.5 2H14v8H2zM8 11a2.3 2.3 0 1 0 0-4.6A2.3 2.3 0 0 0 8 11z"/></svg>,
  alert:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M8 2 1 14h14zM8 7v3M8 12h.01"/></svg>,
  info:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><circle cx="8" cy="8" r="6.5"/><path d="M8 7.5v4M8 5h.01"/></svg>,
  eye:     (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M1 8s2.5-5 7-5 7 5 7 5-2.5 5-7 5-7-5-7-5z"/><circle cx="8" cy="8" r="2"/></svg>,
  back:    (p) => <svg aria-hidden="true" className="ic-dir" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" {...p}><path d="M13 8H3M7 4 3 8l4 4"/></svg>,
  upload:  (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M8 11V2M5 5l3-3 3 3M2 12v2h12v-2"/></svg>,
  cog:     (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><circle cx="8" cy="8" r="2"/><path d="M8 1v2M8 13v2M1 8h2M13 8h2M3 3l1.4 1.4M11.6 11.6 13 13M3 13l1.4-1.4M11.6 4.4 13 3"/></svg>,
  globe:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><circle cx="8" cy="8" r="6.5"/><path d="M1.5 8h13M8 1.5c2 2 2 11 0 13M8 1.5c-2 2-2 11 0 13"/></svg>,
  offer:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><path d="M2 7l3-3 4 4 5-4M9 8l2 2 3-3M2 7v5h4"/></svg>,
  trend:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" {...p}><path d="M1 11l4-4 3 3 6-6M10 4h4v4"/></svg>,
  store:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><path d="M2 6.5 3 2.5h10l1 4M2 6.5h12M2 6.5v7h12v-7M2 6.5a2 2 0 0 0 4 0 2 2 0 0 0 4 0 2 2 0 0 0 4 0M6 13.5v-3h4v3"/></svg>,
  mail:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><rect x="1.5" y="3" width="13" height="10" rx="1"/><path d="m2 4 6 4.5L14 4"/></svg>,
  phone:   (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><path d="M3 2h3l1.5 3.5L6 7a8 8 0 0 0 3 3l1.5-1.5L14 10v3a1 1 0 0 1-1 1A11 11 0 0 1 2 3a1 1 0 0 1 1-1z"/></svg>,
  copy:    (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><rect x="5" y="5" width="9" height="9" rx="1"/><path d="M3 11V3a1 1 0 0 1 1-1h7"/></svg>,
  key:     (p) => <svg aria-hidden="true" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" {...p}><circle cx="5" cy="5" r="3"/><path d="m7 7 6 6M11 11l1.5-1.5M13 13l1.5-1.5"/></svg>,
};

/* ---- hooks ---- */
// Re-render every `ms` so countdowns advance. (Store also ticks, but this
// keeps standalone countdowns smooth even on screens not reading the store.)
function useTick(ms = 1000) {
  const [, set] = useState(0);
  useEffect(() => { const t = setInterval(() => set(n => n + 1), ms); return () => clearInterval(t); }, [ms]);
}
function useServerClock() {
  useTick(1000);
  return new Date();
}
// Navigation (hash router)
function useRoute() {
  const parse = () => {
    const h = (window.location.hash || "#/browse").replace(/^#/, "");
    const parts = h.split("/").filter(Boolean);
    return { name: parts[0] || "browse", param: parts[1] || null, sub: parts[2] || null, parts };
  };
  const [route, setRoute] = useState(parse);
  useEffect(() => {
    const on = () => setRoute(parse());
    window.addEventListener("hashchange", on);
    return () => window.removeEventListener("hashchange", on);
  }, []);
  return route;
}
function navigate(path) { window.location.hash = path; }

// Accessible dialog: move focus in, trap Tab, Escape to close, restore focus on close.
function useFocusTrap(onClose) {
  const ref = useRef(null);
  useEffect(() => {
    const node = ref.current; if (!node) return;
    const prev = document.activeElement;
    const sel = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
    const focusables = () => Array.from(node.querySelectorAll(sel)).filter(el => el.offsetParent !== null);
    (focusables()[0] || node).focus();
    function onKey(e) {
      if (e.key === "Escape") { e.preventDefault(); onClose && onClose(); return; }
      if (e.key !== "Tab") return;
      const f = focusables(); if (!f.length) return;
      const a = f[0], b = f[f.length - 1];
      if (e.shiftKey && document.activeElement === a) { e.preventDefault(); b.focus(); }
      else if (!e.shiftKey && document.activeElement === b) { e.preventDefault(); a.focus(); }
    }
    node.addEventListener("keydown", onKey);
    return () => { node.removeEventListener("keydown", onKey); if (prev && prev.focus) prev.focus(); };
  }, []);
  return ref;
}

// Spread onto a non-button element to make it a keyboard-operable control.
function clickable(onClick, label) {
  return {
    role: "button", tabIndex: 0, "aria-label": label,
    onClick,
    onKeyDown: (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); onClick(e); } },
  };
}

/* ---- AutoGrade badge ---- */
function AutoGrade({ score, size, showLabel }) {
  const pct = (score / 5) * 100;
  const c = gradeColor(score);
  const cls = "autograde " + (size === "sm" ? "sm" : size === "lg" ? "lg" : "");
  return (
    <span className="row gap-8">
      <span className={cls} style={{ "--pct": pct, "--c": c }}>
        <span className="val tnum">{score.toFixed(1)}</span>
      </span>
      {showLabel && <span className="col"><b style={{ fontSize: 13 }}>AutoGrade</b><span className="muted" style={{ fontSize: 12 }}>{gradeLabel(score)}</span></span>}
    </span>
  );
}
function GradeChip({ score }) {
  return <span className="gradechip"><span className="num" style={{ background: gradeColor(score) }}>{score.toFixed(1)}</span>{gradeLabel(score)}</span>;
}

/* ---- Pill ---- */
function Pill({ kind, dot, children, style }) {
  return <span className={"pill " + (kind || "")} style={style}>{dot && <span className="dot" />}{children}</span>;
}

/* ---- Photo placeholder ---- */
function Photo({ label, count, className, style, hue = 210, src, ...rest }) {
  if (src) {
    return (
      <div className={"photo " + (className || "")} style={{ background: "#e8ebee", ...style }} {...rest}>
        <img src={src} alt={label || "Vehicle photo"} style={{ position: "absolute", inset: 0, width: "100%", height: "100%", objectFit: "cover" }} loading="lazy" />
        {label && <span className="ph-label">{label}</span>}
        {count != null && <span className="ph-count">{count}</span>}
      </div>
    );
  }
  return (
    <div className={"photo " + (className || "")} style={{ background: `linear-gradient(135deg, hsl(${hue},22%,90%), hsl(${hue + 10},26%,82%))`, ...style }} {...rest}>
      <I.car className="ph-ic" width="34" height="34" aria-hidden="true" />
      {label && <span className="ph-label">{label}</span>}
      {count != null && <span className="ph-count">{count}</span>}
    </div>
  );
}

/* ---- Countdown ---- */
function Countdown({ to, className = "", prefix }) {
  useTick(1000);
  const ms = to - Date.now();
  const danger = ms > 0 && ms < 60000;
  const warn = ms > 0 && ms < 300000;
  return <span className={`countdown ${danger ? "danger" : warn ? "warn" : ""} ${className}`}>{prefix}{fmtRemaining(ms)}</span>;
}

/* ---- Watch (star) button ---- */
function WatchBtn({ id, className = "watch" }) {
  const s = useStore();
  const on = s.watchlist.has(id);
  return (
    <button className={className + (on ? " on" : "")} title={on ? "Watching" : "Watch"}
      aria-label={on ? "Remove from watchlist" : "Add to watchlist"} aria-pressed={on}
      onClick={(e) => { e.stopPropagation(); requireAuth(() => Engine.toggleWatch(id)); }}>
      {on ? <I.starF width="15" height="15" /> : <I.star width="15" height="15" />}
    </button>
  );
}

/* ---- NAAA sale light ---- */
function SaleLight({ lot, full }) {
  const sl = saleLight(lot);
  const color = sl.light === "green" ? "var(--green)" : sl.light === "yellow" ? "var(--amber)" : "var(--red)";
  return (
    <span className="pill" title={sl.desc} style={{ gap: 6 }}>
      <span aria-hidden="true" style={{ width: 9, height: 9, borderRadius: "50%", background: color, boxShadow: `0 0 0 2px ${color}33` }} />
      <span className="sr-only">{sl.light} light —</span>{sl.label}{full ? "" : ""}
    </span>
  );
}

/* ---- Market-value badge (good-buy signal) ---- */
function MarketBadge({ lot, full }) {
  const { t } = useT();
  const ms = marketSignal(lot.highBid, lot.marketValue);
  if (!ms) return null;
  const key = ms.pct >= 0.10 ? "mkt.greatBuy" : ms.kind === "green" ? "mkt.below" : ms.kind === "amber" ? "mkt.at" : "mkt.above";
  return (
    <Pill kind={ms.kind} style={{ gap: 5 }}>
      <I.trend width="11" height="11" />{t(key)}
      {full && ms.save > 0 ? ` · ${t("mkt.save")} ${fmtUSD(ms.save)}` : ""}
    </Pill>
  );
}

/* ---- Market estimate (Sayarah estimate + sold comps) ---- */
function MarketEstimate({ lot }) {
  const { t } = useT();
  const [open, setOpen] = useState(false);
  const est = estimateFromComps(lot);
  return (
    <div style={{ padding: "10px 0", borderTop: "1px solid var(--border)", borderBottom: "1px solid var(--border)" }}>
      <div className="row gap-8">
        <div>
          <div className="l" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: ".08em", color: "var(--fg-3)", fontWeight: 700 }}>{t("mkt.estimate")}</div>
          <div className="tnum" style={{ fontWeight: 800, fontSize: 17 }}>{fmtUSD(lot.marketValue)}</div>
          {est && <div className="muted" style={{ fontSize: 11.5 }}>{fmtUSD(est.low)}–{fmtUSD(est.high)} · {est.n} {t("mkt.sold")}</div>}
        </div>
        <span className="spacer" />
        <MarketBadge lot={lot} full />
      </div>
      {est && <button className="btn ghost sm" style={{ padding: "5px 0", marginTop: 2, alignSelf: "flex-start" }} onClick={() => setOpen(o => !o)}>{t("mkt.recent")} <I.chevD width="11" height="11" style={{ transform: open ? "rotate(180deg)" : "none", transition: ".2s" }} /></button>}
      {est && open && (
        <div className="col fadein" style={{ marginTop: 2 }}>
          {est.comps.slice(0, 4).map((c, i) => (
            <div key={i} className="row gap-8" style={{ padding: "6px 0", borderTop: "1px solid var(--border)", fontSize: 12 }}>
              <span style={{ fontWeight: 600 }}>{c.year} {c.make} {c.model}</span>
              <span className="muted">{c.grade.toFixed(1)} · {c.dest} · {c.daysAgo}d</span>
              <span className="spacer" />
              <b className="tnum">{fmtUSD(c.final)}</b>
            </div>
          ))}
          <div className="muted" style={{ fontSize: 10.5, marginTop: 5 }}>{t("mkt.disclaimer")}</div>
        </div>
      )}
    </div>
  );
}

/* ---- Listing card (responsive grid item) ---- */
function ListingCard({ lot }) {
  const { t } = useT();
  const mine = lot.highBidder === "you";
  const youBid = lot.yourMax != null;
  const cls = "lcard " + (mine ? "winning " : youBid ? "outbid " : "");
  const titleStatus = lot.title === "Clean" ? "green" : lot.title === "Branded" ? "amber" : "red";
  const open = () => navigate(`/lot/${lot.id}`);
  return (
    <div className={cls} onClick={open} style={{ cursor: "pointer" }}>
      <div className="hero">
        <Photo className="photo" src={lot.photoUrls && lot.photoUrls[0]} hue={lot.id.charCodeAt(5) * 6} />
        <div className="toptags">
          {lot.status === "scheduled" ? <Pill kind="blue">LANE {lot.lane}</Pill> : lot.saleType === "live" && <Pill kind="live" dot>LIVE</Pill>}
          {(lot.tags || []).slice(0, 1).map((t, i) => <Pill key={i} kind={t.kind}>{t.label}</Pill>)}
        </div>
        <span className={"src" + (lot.owned ? " own" : "")}>{lot.owned ? t("tag.owned") : t("tag.consigned")}</span>
        <WatchBtn id={lot.id} />
        <span className="pc"><I.camera width="11" height="11" /> {lot.photos}</span>
      </div>
      <div className="body">
        <div className="title">
          <button className="cardlink" onClick={(e) => { e.stopPropagation(); open(); }}>{lot.year} {lot.make} {lot.model}</button>
          <span className="autograde sm" style={{ "--pct": (lot.autograde / 5) * 100, "--c": gradeColor(lot.autograde) }}><span className="val tnum">{lot.autograde.toFixed(1)}</span></span>
        </div>
        <div className="trim">{lot.trim}</div>
        <div className="specs">
          <span>{fmtMiles(lot.mileage)}</span>
          <span>{lot.drivetrain}</span>
          <span>{lot.transmission}</span>
          <span><Pill kind={titleStatus} style={{ padding: "1px 7px", fontSize: 10.5 }}>{lot.title}</Pill></span>
          <span><SaleLight lot={lot} /></span>
        </div>
        <div className="loc"><I.pin width="11" height="11" /> {lot.location} · {lot.seller}</div>
        <div style={{ marginTop: 9 }}><MarketBadge lot={lot} /></div>
      </div>
      <div className="foot">
        <div>
          <div className="l">{mine ? "Your bid · winning" : youBid ? "High bid · outbid" : `High bid · ${lot.bidCount}`}</div>
          <div className={"bid tnum " + (mine ? "winning" : "")}>{fmtUSD(lot.highBid)}</div>
        </div>
        <div style={{ textAlign: "right" }}>
          <div className="l">{lot.status === "ended" ? "Status" : lot.status === "scheduled" ? "Opens in" : "Ends in"}</div>
          {lot.status === "ended"
            ? <div className="time">{lot.result === "won" ? "Won" : "Ended"}</div>
            : lot.status === "scheduled"
              ? <Countdown to={lot.startsAt} className="time" />
              : <Countdown to={lot.endsAt} className={"time " + (lot.endsAt - Date.now() < 600000 ? "ending" : "")} />}
        </div>
      </div>
    </div>
  );
}

/* ---- Modal + Sheet ---- */
function Modal({ children, onClose, label }) {
  const ref = useFocusTrap(onClose);
  return (
    <div className="modal-back" onClick={onClose}>
      <div className="modal" role="dialog" aria-modal="true" aria-label={label || "Dialog"} tabIndex={-1} ref={ref} onClick={(e) => e.stopPropagation()}>{children}</div>
    </div>
  );
}
function Sheet({ children, onClose, title }) {
  const ref = useFocusTrap(onClose);
  return (
    <>
      <div className="sheet-back" onClick={onClose} />
      <div className="sheet" role="dialog" aria-modal="true" aria-label={title || "Sheet"} tabIndex={-1} ref={ref}>
        <div className="grab" />
        <div className="shead"><b style={{ fontSize: 16 }}>{title}</b><button className="iconbtn" aria-label="Close" style={{ marginLeft: "auto", width: 32, height: 32 }} onClick={onClose}><I.x width="14" height="14" /></button></div>
        {children}
      </div>
    </>
  );
}

/* ---- Toasts ---- */
function ToastHost() {
  const s = useStore();
  useEffect(() => {
    const timers = s.toasts.map(t => setTimeout(() => Engine.dismissToast(t.id), 5200));
    return () => timers.forEach(clearTimeout);
  }, [s.toasts]);
  const cls = (k) => k === "win" || k === "buynow" ? "win" : k === "outbid" || k === "snipe" ? "outbid" : k === "lost" ? "lost" : "";
  const ic = (k) => k === "win" || k === "buynow" ? <I.check width="16" height="16" /> : k === "outbid" ? <I.alert width="16" height="16" /> : k === "lost" ? <I.x width="16" height="16" /> : k === "snipe" ? <I.clock width="16" height="16" /> : <I.gavel width="16" height="16" />;
  return (
    <div className="toast-wrap">
      {s.toasts.map(t => (
        <div key={t.id} className={"toast " + cls(t.kind)} onClick={() => t.lotId && navigate(`/lot/${t.lotId}`)} style={{ cursor: t.lotId ? "pointer" : "default" }}>
          <div className="tic">{ic(t.kind)}</div>
          <div style={{ flex: 1 }}><div className="tt">{t.title}</div><div className="tb">{t.body}</div></div>
          <button className="iconbtn" aria-label="Dismiss notification" style={{ width: 26, height: 26, border: 0 }} onClick={(e) => { e.stopPropagation(); Engine.dismissToast(t.id); }}><I.x width="12" height="12" /></button>
        </div>
      ))}
    </div>
  );
}

/* ---- Printable document (invoice / statement / gate pass) ----
   Renders in a modal; window.print() prints only .print-doc via print CSS. */
function PrintDoc({ title, subtitle, children, onClose }) {
  return (
    <Modal onClose={onClose} label={title}>
      <div className="print-doc">
        <div style={{ padding: "22px 24px", borderBottom: "3px solid var(--brand)" }}>
          <div className="row gap-10">
            <div><img src="assets/carzello-logo.svg" alt="Carzello" style={{ height: 24, display: "block", marginBottom: 4 }} /><div className="muted" style={{ fontSize: 11 }}>A Sayarah Inc. brand · Dubai · Dallas</div></div>
            <span className="spacer" />
            <div style={{ textAlign: "right" }}><b style={{ fontSize: 15, textTransform: "uppercase" }}>{title}</b>{subtitle && <div className="muted" style={{ fontSize: 11.5 }}>{subtitle}</div>}</div>
          </div>
        </div>
        <div style={{ padding: "18px 24px", maxHeight: "56vh", overflowY: "auto" }}>{children}</div>
        <div className="muted" style={{ padding: "10px 24px", borderTop: "1px solid var(--border)", fontSize: 10.5 }}>Generated {new Date().toLocaleString()} · Carzello · A Sayarah Inc. brand</div>
      </div>
      <div className="mfoot no-print">
        <button className="btn outline" style={{ flex: 1 }} onClick={onClose}>Close</button>
        <button className="btn primary" style={{ flex: 2 }} onClick={() => window.print()}><I.doc width="13" height="13" /> Print / Save PDF</button>
      </div>
    </Modal>
  );
}

/* ---- Empty state ---- */
function Empty({ icon, title, sub, action }) {
  return (
    <div className="empty">
      <div className="ic">{icon || <I.car width="26" height="26" />}</div>
      <h3>{title}</h3>
      <div style={{ maxWidth: 380, margin: "0 auto" }}>{sub}</div>
      {action && <div style={{ marginTop: 16 }}>{action}</div>}
    </div>
  );
}

/* ---- Real authentication (Firebase Auth) ---- */
function useAuthUser() {
  const [user, setUser] = useState(() => (FB.enabled ? FB.currentUser() : null));
  useEffect(() => (FB.enabled ? FB.onAuth(setUser) : undefined), []);
  return user;
}

/* Run `action` if signed in; otherwise open the sign-in modal. */
function requireAuth(action) {
  if (FB.enabled && !FB.currentUser()) { window.dispatchEvent(new CustomEvent("carzello:auth")); return false; }
  if (action) action();
  return true;
}

function AuthModal({ onClose }) {
  const [mode, setMode] = useState("signin"); // signin | signup | reset
  const [email, setEmail] = useState("");
  const [pw, setPw] = useState("");
  const [name, setName] = useState("");
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState(null);
  const [ok, setOk] = useState(null);

  function submit(e) {
    e.preventDefault();
    if (busy) return;
    setErr(null); setOk(null); setBusy(true);
    const enter = () => FB.adoptAccountState().then(() => location.reload());
    const p = mode === "signin" ? FB.signIn(email, pw).then(enter)
      : mode === "signup" ? FB.signUp(email, pw, name).then(enter)
      : FB.resetPassword(email).then(() => { setOk("Password reset email sent — check your inbox."); setBusy(false); });
    p.catch((er) => { setErr(er.message); setBusy(false); });
  }

  const title = mode === "signin" ? "Sign in" : mode === "signup" ? "Create your account" : "Reset password";
  return (
    <Modal onClose={onClose} label={title}>
      <div className="mhead">
        <span className="iconbtn sm" style={{ background: "var(--brand-soft)", color: "var(--brand)", border: 0 }}><I.user width="15" height="15" /></span>
        <b style={{ fontSize: 16 }}>{title}</b>
        <button className="iconbtn sm" aria-label="Close" style={{ marginInlineStart: "auto" }} onClick={onClose}><I.x width="14" height="14" /></button>
      </div>
      <form className="mbody col gap-12" onSubmit={submit}>
        {mode === "signup" && (
          <div className="field"><label>Full name</label>
            <input className="input" name="name" value={name} onChange={(e) => setName(e.target.value)} autoComplete="name" placeholder="Your name" /></div>
        )}
        <div className="field"><label>Email</label>
          <input className="input" type="email" name="email" required value={email} onChange={(e) => setEmail(e.target.value)} autoComplete="email" placeholder="you@company.com" /></div>
        {mode !== "reset" && (
          <div className="field"><label>Password</label>
            <input className="input" type="password" name="password" required minLength={6} value={pw} onChange={(e) => setPw(e.target.value)}
              autoComplete={mode === "signup" ? "new-password" : "current-password"} placeholder="••••••••" /></div>
        )}
        {err && <div className="feedback err"><I.alert width="13" height="13" />{err}</div>}
        {ok && <div className="feedback ok"><I.check width="13" height="13" />{ok}</div>}
        <button className="btn primary lg block" type="submit" disabled={busy}>
          {busy ? "Please wait…" : mode === "signin" ? "Sign in" : mode === "signup" ? "Create account" : "Send reset email"}
        </button>
        <div className="row" style={{ justifyContent: "space-between", fontSize: 12.5 }}>
          {mode === "signin"
            ? <>
                <button type="button" className="btn ghost sm" onClick={() => { setErr(null); setMode("signup"); }}>Create an account</button>
                <button type="button" className="btn ghost sm" onClick={() => { setErr(null); setMode("reset"); }}>Forgot password?</button>
              </>
            : <button type="button" className="btn ghost sm" onClick={() => { setErr(null); setOk(null); setMode("signin"); }}>← Back to sign in</button>}
        </div>
      </form>
    </Modal>
  );
}

Object.assign(window, {
  fmtUSD, fmtUSDc, fmtMiles, fmtRemaining, fmtClock, timeAgo,
  I, useTick, useServerClock, useRoute, navigate, useFocusTrap, clickable,
  AutoGrade, GradeChip, Pill, Photo, Countdown, WatchBtn, ListingCard, MarketBadge, MarketEstimate, SaleLight,
  Modal, Sheet, ToastHost, Empty, PrintDoc,
  useAuthUser, requireAuth, AuthModal,
});
