// Open Marketplace — app components
// Roles: contractor | homeowner | vendor. Public browse; sign-in gate to transact.

const { useState, useMemo, useEffect } = React;

// ── Small pieces ─────────────────────────────────────────────────────────
function Stars({ rating, size = 12 }) {
  return (
    <span style={{ color: "var(--gold-dark)", fontSize: size, letterSpacing: 1 }} aria-label={rating + " stars"}>
      {"★★★★★".slice(0, Math.round(rating))}<span style={{ opacity: 0.25 }}>{"★★★★★".slice(Math.round(rating))}</span>
    </span>
  );
}

function VerifiedBadge({ small }) {
  return (
    <span className="mpx-badge" style={small ? { fontSize: 10, padding: "1px 6px" } : null}>
      <svg width={small ? 9 : 11} height={small ? 9 : 11} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3.4"><path d="M20 6L9 17l-5-5"/></svg>
      Verified
    </span>
  );
}

function MemberChip({ small }) {
  return <span className="mpx-member" style={small ? { fontSize: 10, padding: "1px 6px" } : null}>Alliance member</span>;
}

function SellerAvatar({ seller, size = 34 }) {
  const initials = seller.name.split(" ").map(w => w[0]).slice(0, 2).join("");
  return (
    <div style={{ width: size, height: size, borderRadius: "50%", background: seller.grad, display: "grid", placeItems: "center", flexShrink: 0 }}>
      <span style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: size * 0.4, color: "#F4E9CC" }}>{initials}</span>
    </div>
  );
}

function SellerLine({ seller, small }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
      <span style={{ fontWeight: 600, fontSize: small ? 12 : 13 }}>{seller.name}</span>
      {seller.verified && <VerifiedBadge small={small} />}
      {seller.member && <MemberChip small={small} />}
    </div>
  );
}

// ── Save heart (micro-interaction → gate after pop) ──
function SaveHeart({ onGate }) {
  const [saved, setSaved] = useState(false);
  return (
    <button className={"mpx-heart" + (saved ? " saved" : "")}
            aria-label="Save listing"
            onClick={e => {
              e.stopPropagation();
              if (saved) { setSaved(false); return; }
              setSaved(true);
              setTimeout(() => onGate("save listings"), 650);
            }}>
      {saved ? "\u2665" : "\u2661"}
    </button>
  );
}

// ── Live activity ticker ──
function ActivityTicker() {
  const [i, setI] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setI(n => (n + 1) % MP_ACTIVITY.length), 4200);
    return () => clearInterval(id);
  }, []);
  const a = MP_ACTIVITY[i];
  return (
    <div className="mpx-ticker">
      <span className="pulse-dot"></span>
      <span key={i} className="mpx-tickitem">
        <b>{a.who}</b> {a.what} in {a.where} · {a.ago} ago
      </span>
    </div>
  );
}

// ── Count-up number ──
function CountUp({ to, suffix = "", duration = 1200 }) {
  const [v, setV] = useState(0);
  useEffect(() => {
    let raf, t0;
    const step = ts => {
      if (!t0) t0 = ts;
      const p = Math.min(1, (ts - t0) / duration);
      setV(Math.round(to * (1 - Math.pow(1 - p, 3))));
      if (p < 1) raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [to]);
  return <span>{v.toLocaleString()}{suffix}</span>;
}

// ── Sticky signup funnel bar ──
function FunnelBar({ views, onDismiss }) {
  return (
    <div className="mpx-funnel mpx-funnel-in" data-screen-label="Signup funnel bar">
      <div style={{ flex: 1 }}>
        <div style={{ fontWeight: 600, fontSize: 13.5 }}>You've viewed {views} listings 👀</div>
        <div style={{ fontSize: 12.5, opacity: 0.75, marginTop: 2 }}>Create a free account to save them, message sellers, and get price-drop alerts.</div>
      </div>
      <a className="btn gold sm" href="/marketplace.html" style={{ textDecoration: "none", flexShrink: 0 }}>Create free account</a>
      <button className="btn sm" onClick={onDismiss} style={{ flexShrink: 0 }}>Later</button>
    </div>
  );
}

// ── Sign-in gate ─────────────────────────────────────────────────────────
function SignInModal({ context, onClose }) {
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal mpx-modal-in" style={{ maxWidth: 400, padding: 0 }} onClick={e => e.stopPropagation()}>
        <div style={{ padding: "28px 28px 24px", textAlign: "center" }}>
          <div style={{ width: 44, height: 44, borderRadius: "50%", background: "var(--gold-bg)", border: "1px solid var(--gold-soft)", display: "grid", placeItems: "center", margin: "0 auto 14px" }}>
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--gold-dark)" strokeWidth="2"><rect x="4" y="11" width="16" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
          </div>
          <div style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 22, marginBottom: 6 }}>Sign in to {context}</div>
          <div style={{ fontSize: 13, color: "var(--text-2)", lineHeight: 1.5 }}>
            Browsing is free for everyone. A free account lets you message sellers, request quotes, and post your own listings.
          </div>
        </div>
        <div style={{ padding: "0 28px 24px", display: "flex", flexDirection: "column", gap: 8 }}>
          <button className="btn" style={{ justifyContent: "center", gap: 10, padding: "11px 14px", fontSize: 15, fontWeight: 600, background: "#fff" }}
                  onClick={() => { window.location.href = "/marketplace.html"; }}>
            <GoogleG size={18} /> Continue with Google
          </button>
          <a className="btn primary" href="/marketplace.html" style={{ justifyContent: "center", textDecoration: "none" }}>Sign in</a>
          <a className="btn" href="/marketplace.html" style={{ justifyContent: "center", textDecoration: "none" }}>Create a free account</a>
          <button className="btn ghost" onClick={onClose} style={{ justifyContent: "center" }}>Keep browsing</button>
        </div>
      </div>
    </div>
  );
}

// ── Listing detail ───────────────────────────────────────────────────────
function ListingModal({ item, onClose, onGate }) {
  const seller = MP_SELLERS[item.seller];
  return (
    <div className="modal-overlay mpx-overlay-in" onClick={onClose}>
      <div className="modal mpx-modal-in" style={{ maxWidth: 640, padding: 0, overflow: "hidden" }} onClick={e => e.stopPropagation()}>
        <div style={{ display: "grid", gridTemplateColumns: "260px 1fr" }}>
          <div style={{ minHeight: 300, background: "var(--bg-card-soft)", position: "relative" }}><MPPhoto item={item} /></div>
          <div style={{ padding: "22px 24px", display: "flex", flexDirection: "column", gap: 12 }}>
            <div>
              <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12 }}>
                <div style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 22, lineHeight: 1.15 }}>{item.title}</div>
                <button className="btn ghost sm" onClick={onClose} aria-label="Close">✕</button>
              </div>
              <div style={{ fontSize: 13, color: "var(--text-2)", marginTop: 4 }}>{item.detail}</div>
            </div>
            <div style={{ display: "flex", alignItems: "baseline", gap: 8 }}>
              <span style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 30 }}>${item.price}</span>
              <span style={{ fontSize: 13, color: "var(--text-3)" }}>{item.unit}</span>
              <span className="chip" style={{ marginLeft: "auto" }}>{item.cond}</span>
            </div>
            <div style={{ fontSize: 12.5, color: "var(--text-3)" }}>{item.loc} · {item.dist} mi away</div>
            <div style={{ borderTop: "1px solid var(--border-soft)", paddingTop: 12, display: "flex", gap: 10, alignItems: "center" }}>
              <SellerAvatar seller={seller} />
              <div style={{ minWidth: 0 }}>
                <SellerLine seller={seller} small />
                <div style={{ fontSize: 11.5, color: "var(--text-3)", marginTop: 2 }}>
                  <Stars rating={seller.rating} size={10} /> {seller.rating} ({seller.reviews}) · responds {seller.resp}
                </div>
              </div>
            </div>
            <div style={{ display: "flex", gap: 8, marginTop: "auto" }}>
              <button className="btn gold" style={{ flex: 1, justifyContent: "center" }} onClick={() => onGate("message " + seller.name)}>Message seller</button>
              <button className="btn" onClick={() => onGate("save listings")}>♡ Save</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Listing cards (grid + list variants) ────────────────────────────────
function ListingCardGrid({ item, compact, onOpen, onGate, index }) {
  const seller = MP_SELLERS[item.seller];
  return (
    <div className="mp-card mpx-click mpx-enter" style={{ animationDelay: (index * 45) + "ms" }} onClick={() => onOpen(item)}>
      <div className="mp-image" style={{ aspectRatio: compact ? "16/10" : "16/11", position: "relative" }}>
        <MPPhoto item={item} />
        {index < 2 && <span className="mpx-new">JUST LISTED</span>}
        <SaveHeart onGate={onGate} />
      </div>
      <div style={{ padding: compact ? "10px 12px 12px" : "12px 14px 14px" }}>
        <div style={{ display: "flex", alignItems: "baseline", gap: 6 }}>
          <span style={{ fontWeight: 700, fontSize: compact ? 17 : 19 }}>${item.price}</span>
          <span style={{ fontSize: 12.5, color: "var(--text-3)" }}>{item.unit}</span>
          {item.cond !== "Rental" && <span className="chip" style={{ marginLeft: "auto", fontSize: 11 }}>{item.cond}</span>}
        </div>
        <div style={{ fontSize: compact ? 13.5 : 15, fontWeight: 500, marginTop: 3, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{item.title}</div>
        <div style={{ fontSize: 12.5, color: "var(--text-3)", marginTop: 3 }}>{item.loc} · {item.dist} mi</div>
        {!compact && (
          <div style={{ marginTop: 8, display: "flex", alignItems: "center", gap: 6 }}>
            <SellerAvatar seller={seller} size={20} />
            <span style={{ fontSize: 11.5, color: "var(--text-2)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{seller.name}</span>
            {seller.verified && <VerifiedBadge small />}
          </div>
        )}
      </div>
    </div>
  );
}

function ListingCardRow({ item, onOpen, index }) {
  const seller = MP_SELLERS[item.seller];
  return (
    <div className="mpx-row mpx-click mpx-enter" style={{ animationDelay: (index * 45) + "ms" }} onClick={() => onOpen(item)}>
      <div style={{ width: 150, borderRadius: 8, overflow: "hidden", flexShrink: 0, aspectRatio: "16/11", position: "relative" }}><MPPhoto item={item} /></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 16, fontWeight: 600 }}>{item.title}</div>
        <div style={{ fontSize: 13.5, color: "var(--text-2)", marginTop: 2 }}>{item.detail}</div>
        <div style={{ marginTop: 8, display: "flex", alignItems: "center", gap: 6 }}>
          <SellerAvatar seller={seller} size={22} />
          <SellerLine seller={seller} small />
        </div>
        <div style={{ fontSize: 11.5, color: "var(--text-3)", marginTop: 4 }}>
          <Stars rating={seller.rating} size={10} /> {seller.rating} ({seller.reviews}) · {item.loc} · {item.dist} mi
        </div>
      </div>
      <div style={{ textAlign: "right", flexShrink: 0 }}>
        <div style={{ fontWeight: 700, fontSize: 19 }}>${item.price}<span style={{ fontSize: 12.5, color: "var(--text-3)", fontWeight: 400 }}>{item.unit}</span></div>
        <span className="chip" style={{ marginTop: 6, display: "inline-block" }}>{item.cond}</span>
      </div>
    </div>
  );
}

// ── Browse (materials / machinery) ──────────────────────────────────────
function Browse({ items, cats, layout, density, onOpen, onGate }) {
  const [q, setQ] = useState("");
  const [cat, setCat] = useState("All");
  const [verifiedOnly, setVerifiedOnly] = useState(false);

  const filtered = useMemo(() => items.filter(it => {
    const s = MP_SELLERS[it.seller];
    if (cat !== "All" && it.cat !== cat) return false;
    if (verifiedOnly && !s.verified) return false;
    if (q && !(it.title + " " + it.detail + " " + s.name).toLowerCase().includes(q.toLowerCase())) return false;
    return true;
  }), [items, q, cat, verifiedOnly]);

  return (
    <div>
      <div className="filter-bar" style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center", marginBottom: 16 }}>
        <input className="filter-input" placeholder="What are you looking for?" value={q} onChange={e => setQ(e.target.value)} />
        {cats.map(c => (
          <button key={c} className={"filter-pill" + (cat === c ? " active" : "")} onClick={() => setCat(c)}>{c}</button>
        ))}
        <button className={"filter-pill" + (verifiedOnly ? " active" : "")} onClick={() => setVerifiedOnly(v => !v)}>✓ Verified only</button>
        <span style={{ marginLeft: "auto", fontSize: 12, color: "var(--text-3)" }}>{filtered.length} listings · within 25 mi of 85201</span>
      </div>

      {layout === "grid" ? (
        <div key={cat + q + verifiedOnly} style={{ display: "grid", gridTemplateColumns: `repeat(auto-fill, minmax(${density === "compact" ? 190 : 240}px, 1fr))`, gap: density === "compact" ? 12 : 16 }}>
          {filtered.map((it, i) => <ListingCardGrid key={it.id} item={it} compact={density === "compact"} onOpen={onOpen} onGate={onGate} index={i} />)}
        </div>
      ) : (
        <div key={cat + q + verifiedOnly} style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {filtered.map((it, i) => <ListingCardRow key={it.id} item={it} onOpen={onOpen} index={i} />)}
        </div>
      )}
      {filtered.length === 0 && (
        <div style={{ textAlign: "center", padding: "60px 0", color: "var(--text-3)", fontSize: 13.5 }}>
          Nothing matches — try clearing a filter.
        </div>
      )}
    </div>
  );
}

// ── Find a roofer (homeowner) ────────────────────────────────────────────
function FindRoofer({ onGate }) {
  const [job, setJob] = useState(null);
  const [zip, setZip] = useState("");
  const [timeline, setTimeline] = useState("Flexible");
  const [matched, setMatched] = useState(false);

  const roofers = matched && job === "repair"
    ? [...MP_ROOFERS].sort((a, b) => (b.specialties.includes("Repairs") ? 1 : 0) - (a.specialties.includes("Repairs") ? 1 : 0))
    : MP_ROOFERS;

  return (
    <div data-screen-label="Find a roofer">
      <div className="mpx-hero mpx-enter">
        <img src={MP_HERO} alt="Roofing crew at golden hour" />
        <div style={{ position: "relative", zIndex: 1, padding: "24px 26px", color: "#FBF7EB", display: "flex", alignItems: "flex-end", justifyContent: "space-between", width: "100%", gap: 20, flexWrap: "wrap" }}>
          <div>
            <div style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 30, lineHeight: 1.05 }}>Vetted roofers. Real reviews.</div>
            <div style={{ fontSize: 13, opacity: 0.8, marginTop: 5 }}>Licensed, insured, and rated by homeowners like you.</div>
          </div>
          <div style={{ display: "flex", gap: 26, textAlign: "center", textShadow: "0 1px 8px rgba(27,24,20,0.65)" }}>
            <div><div style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 26 }}><CountUp to={240} suffix="+" /></div><div style={{ fontSize: 11, opacity: 0.75 }}>vetted companies</div></div>
            <div><div style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 26 }}><CountUp to={12400} /></div><div style={{ fontSize: 11, opacity: 0.75 }}>roofs completed</div></div>
            <div><div style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 26 }}>4.8<span style={{ color: "var(--gold)" }}>★</span></div><div style={{ fontSize: 11, opacity: 0.75 }}>average rating</div></div>
          </div>
        </div>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "320px 1fr", gap: 20, alignItems: "start" }}>
      {/* Quote wizard */}
      <div className="card" style={{ padding: 20, position: "sticky", top: 16 }}>
        <div style={{ fontFamily: "var(--serif)", fontStyle: "italic", fontSize: 20, marginBottom: 4 }}>Get free quotes</div>
        <div style={{ fontSize: 12.5, color: "var(--text-2)", marginBottom: 14 }}>Every roofer here is vetted — licensed, insured, and rated by real customers.</div>
        <div style={{ fontSize: 12, fontWeight: 600, color: "var(--text-2)", marginBottom: 8 }}>What do you need?</div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
          {MP_JOB_TYPES.map(j => (
            <button key={j.id}
                    className={"mpx-jobbtn" + (job === j.id ? " active" : "")}
                    onClick={() => { setJob(j.id); setMatched(false); }}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d={j.icon}/></svg>
              {j.label}
            </button>
          ))}
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginTop: 12 }}>
          <div>
            <div style={{ fontSize: 12, fontWeight: 600, color: "var(--text-2)", marginBottom: 5 }}>ZIP code</div>
            <input className="input" style={{ width: "100%", boxSizing: "border-box" }} placeholder="85201" value={zip} maxLength={5} onChange={e => setZip(e.target.value.replace(/\D/g, ""))} />
          </div>
          <div>
            <div style={{ fontSize: 12, fontWeight: 600, color: "var(--text-2)", marginBottom: 5 }}>Timeline</div>
            <select className="select" style={{ width: "100%" }} value={timeline} onChange={e => setTimeline(e.target.value)}>
              <option>Urgent — leaking now</option>
              <option>Within 2 weeks</option>
              <option>Within a month</option>
              <option>Flexible</option>
            </select>
          </div>
        </div>
        <button className="btn gold" style={{ width: "100%", justifyContent: "center", marginTop: 14 }}
                disabled={!job || zip.length < 5}
                onClick={() => setMatched(true)}>
          {matched ? "✓ Matched below" : "See matched roofers"}
        </button>
        {(!job || zip.length < 5) && <div style={{ fontSize: 11, color: "var(--text-3)", textAlign: "center", marginTop: 6 }}>Pick a job type and enter your ZIP</div>}
      </div>

      {/* Roofer cards */}
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {matched && (
          <div className="banner" style={{ padding: "12px 16px", fontSize: 13 }}>
            <span className="pulse-dot"></span>
            <span><b>{roofers.length} vetted roofers</b> serve {zip} — {timeline.toLowerCase()}. Request quotes from up to 3.</span>
          </div>
        )}
        {roofers.map((r, idx) => {
          const s = MP_SELLERS[r.seller];
          return (
            <div key={r.id + (matched ? "-m" : "")} className="mpx-row mpx-enter" style={{ animationDelay: (idx * 60) + "ms" }}>
              <SellerAvatar seller={s} size={52} />
              <div style={{ flex: 1, minWidth: 0 }}>
                <SellerLine seller={s} />
                <div style={{ fontSize: 12, color: "var(--text-3)", margin: "3px 0 6px" }}>
                  <Stars rating={s.rating} size={11} /> <b style={{ color: "var(--text-1)" }}>{s.rating}</b> ({s.reviews} reviews) · {r.years} yrs · {r.jobs.toLocaleString()} jobs · {r.city}
                </div>
                <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 6 }}>
                  {r.specialties.map(sp => <span key={sp} className="chip">{sp}</span>)}
                  <span className="chip green">Responds {s.resp}</span>
                </div>
                <div style={{ fontSize: 12.5, color: "var(--text-2)", fontStyle: "italic" }}>“{r.quote}”</div>
              </div>
              <div style={{ flexShrink: 0, display: "flex", flexDirection: "column", gap: 6 }}>
                <button className="btn gold sm" onClick={() => onGate("request a quote from " + s.name)}>Request quote</button>
                <button className="btn sm" onClick={() => onGate("message " + s.name)}>Message</button>
              </div>
            </div>
          );
        })}
      </div>
      </div>
    </div>
  );
}

// ── Pro membership banner ($500/mo) ──────────────────────────────────────
function ProBanner({ role, onGate }) {
  return (
    <div className="banner" style={{ margin: "0 0 18px", alignItems: "center" }}>
      <div style={{ width: 38, height: 38, borderRadius: "50%", background: "var(--gold)", display: "grid", placeItems: "center", flexShrink: 0 }}>
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#1B1814" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12l9-8 9 8M5 10v10h14V10"/></svg>
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ fontWeight: 600, fontSize: 13.5 }}>
          {role === "vendor" ? "Reach 240+ roofing companies with a storefront" : "Want more leads? Get the $500/mo growth membership"}
        </div>
        <div style={{ fontSize: 12.5, color: "var(--text-2)", marginTop: 2 }}>
          {role === "vendor"
            ? "Featured listings, direct messaging, and buyer analytics for vendors."
            : "Includes a professional website built for you + a steady flow of quality, vetted leads."}
        </div>
      </div>
      <button className="btn gold sm" style={{ flexShrink: 0 }} onClick={() => onGate("apply for the growth membership")}>Learn more</button>
    </div>
  );
}

// ── Role config ──────────────────────────────────────────────────────────
const MP_ROLES = {
  contractor: { label: "Contractor", defaultTab: "materials", cta: "+ Post a listing",
    hero: "Buy surplus materials, rent machinery near you, and sell what's sitting in your yard." },
  homeowner: { label: "Homeowner", defaultTab: "roofers", cta: "Get free quotes",
    hero: "Every roofer here is vetted — licensed, insured, and rated by real customers." },
  vendor: { label: "Vendor", defaultTab: "materials", cta: "+ Post a listing",
    hero: "Put your products in front of hundreds of roofing companies actively buying." },
};

const MP_TABS = [
  { id: "materials", label: "Buy materials" },
  { id: "machinery", label: "Rent machinery" },
  { id: "roofers", label: "Find a roofer" },
];

// ── Main app ─────────────────────────────────────────────────────────────
function OpenMarketplace({ layout, density, showProBanner, accent }) {
  const params = new URLSearchParams(window.location.search);
  const initRole = MP_ROLES[params.get("role")] ? params.get("role") : "contractor";
  const initTab = ["materials", "machinery", "roofers"].includes(params.get("tab"))
    ? params.get("tab") : MP_ROLES[initRole].defaultTab;
  const [role, setRole] = useState(initRole);
  const [tab, setTab] = useState(initTab);
  const [openItem, setOpenItem] = useState(null);
  const [gate, setGate] = useState(null);
  const [views, setViews] = useState(0);
  const [funnelDismissed, setFunnelDismissed] = useState(false);

  const pickRole = r => { setRole(r); setTab(MP_ROLES[r].defaultTab); };
  const openListing = it => { setOpenItem(it); setViews(v => v + 1); };
  const showFunnel = views >= 2 && !funnelDismissed && !openItem && !gate;
  const a = Array.isArray(accent) ? accent : ["#C7A24A", "#A88431", "#FBF3DA", "#F4E6BE"];
  const accentVars = { "--gold": a[0], "--gold-dark": a[1], "--gold-bg": a[2], "--gold-soft": a[3] };

  return (
    <div style={{ minHeight: "100vh", background: "var(--bg-content)", ...accentVars }}>
      {/* Nav */}
      <nav className="mpx-nav" data-screen-label="Marketplace nav">
        <a href="website.html" className="mpx-brand">
          <span className="mpx-brandmark">RL</span>
          <span>Roof Linker <span style={{ color: "var(--text-3)", fontWeight: 400 }}>Marketplace</span></span>
        </a>
        <div className="mpx-tabs">
          {MP_TABS.map(t => (
            <button key={t.id} className={"mpx-tab" + (tab === t.id ? " active" : "")} onClick={() => setTab(t.id)}>{t.label}</button>
          ))}
        </div>
        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          <a className="btn sm" href="/marketplace.html" style={{ textDecoration: "none" }}>Sign in</a>
          <button className="btn primary sm" onClick={() => setGate(MP_ROLES[role].cta.replace(/^\+ /, "").toLowerCase())}>{MP_ROLES[role].cta}</button>
        </div>
      </nav>

      {/* Role strip */}
      <div className="mpx-rolestrip" data-screen-label="Role switcher">
        <span style={{ fontSize: 14, color: "var(--text-3)" }}>I'm a…</span>
        <div className="mpx-roleseg">
          {Object.entries(MP_ROLES).map(([id, r]) => (
            <button key={id} className={role === id ? "active" : ""} onClick={() => pickRole(id)}>{r.label}</button>
          ))}
        </div>
        <span style={{ fontSize: 14, color: "var(--text-2)", fontStyle: "italic", fontFamily: "var(--serif)" }}>{MP_ROLES[role].hero}</span>
      </div>

      {/* Live activity */}
      <ActivityTicker />

      {/* Content */}
      <main key={tab + role} style={{ maxWidth: 1160, margin: "0 auto", padding: "14px 24px 90px" }} data-screen-label={"Marketplace · " + tab}>
        {showProBanner && role !== "homeowner" && <ProBanner role={role} onGate={setGate} />}
        {tab === "materials" && <Browse items={MP_MATERIALS} cats={MP_MATERIAL_CATS} layout={layout} density={density} onOpen={openListing} onGate={setGate} />}
        {tab === "machinery" && <Browse items={MP_MACHINERY} cats={MP_MACHINERY_CATS} layout={layout} density={density} onOpen={openListing} onGate={setGate} />}
        {tab === "roofers" && <FindRoofer onGate={setGate} />}
      </main>

      {showFunnel && <FunnelBar views={views} onDismiss={() => setFunnelDismissed(true)} />}

      {openItem && <ListingModal item={openItem} onClose={() => setOpenItem(null)} onGate={ctx => { setOpenItem(null); setGate(ctx); }} />}
      {gate && <SignInModal context={gate} onClose={() => setGate(null)} />}
    </div>
  );
}

Object.assign(window, { OpenMarketplace });
