// ===========================================================
// My Collection, main page.
// Owns the logged-out marketing surface, the empty state, and the
// populated dashboard (hero value, Collection/Wishlist tabs, stats,
// sort/filter, add-record flow). The prototype state switcher lives
// here too. Auth screens + signup gate are rendered by App.
// ===========================================================
const { useState: useMcState, useMemo: useMcMemo, useEffect: useMcEffect, useRef: useMcRef } = React;

function gbp(n) { return "£" + Math.round(n).toLocaleString("en-GB"); }
function condClass(code) { return code === "VG+" ? "VGplus" : (["M", "NM", "VG"].includes(code) ? code : "low"); }

// ---- resolve a stored record into a fully-priced display object ------------
function resolveRecord(rec, albums) {
  const album = (rec.slug
    ? albums.find(a => a.slug === rec.slug)
    : { ...rec.manual, rank: -1, slug: null }) || { ...(rec.manual || {}), rank: -1, slug: rec.slug || null };
  let pressing = rec.pressing;
  if (!pressing && rec.slug) {
    const list = window.BBR_PRESSINGS[rec.slug] || [];
    pressing = list.find(p => p.id === rec.pressingId) || list[0];
  }
  // Fallback so a record with no known pressing never crashes the page.
  if (!pressing) {
    pressing = {
      id: rec.pressingId || "unknown",
      label: (album && album.label) || "Unknown pressing",
      country: "—", year: (album && album.year) || "—",
      catno: "—", format: ["LP"], notes: "", baseNM: 0, lastSold: "—",
      have: 0, want: 0,
    };
  }
  // Guard every field the cards read downstream.
  if (!Array.isArray(pressing.format)) pressing.format = pressing.format ? [pressing.format] : ["LP"];
  if (pressing.baseNM == null) pressing.baseNM = 0;
  if (!pressing.label) pressing.label = "Unknown pressing";
  if (!pressing.lastSold) pressing.lastSold = "—";

  const value = window.BBR_valueOf(pressing.baseNM, rec.condition || "NM");
  // Final safety net: guarantee fields the cards read, even for odd records.
  const trend = rec.trend && Array.isArray(rec.trend.spark)
    ? rec.trend
    : { pct: 0, dir: "flat", spark: Array(12).fill(value) };
  const dateAdded = rec.dateAdded || "";
  const unknownPressing = !!(rec.pressingUnknown || (rec.pressing && rec.pressing.unknown));
  return {
    ...rec, album, pressing, value: unknownPressing ? 0 : value, trend, dateAdded, unknownPressing,
    low: unknownPressing ? 0 : Math.round(value * 0.8), high: unknownPressing ? 0 : Math.round(value * 1.4),
    decade: window.BBR_decadeOf((album && album.year) || 0),
    genre: (album && album.genre) || "Other",
  };
}

// ---- tiny charts -----------------------------------------------------------
function Sparkline({ data, dir, w = 60, h = 22 }) {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data), span = (max - min) || 1;
  const pts = data.map((v, i) => [(i / (data.length - 1)) * w, h - 3 - ((v - min) / span) * (h - 6)]);
  const d = "M" + pts.map(p => p[0].toFixed(1) + "," + p[1].toFixed(1)).join(" L");
  const color = dir === "down" ? "oklch(0.55 0.16 28)" : dir === "up" ? "oklch(0.52 0.13 150)" : "var(--ink-mute)";
  const last = pts[pts.length - 1];
  return (
    <svg width={w} height={h} className="spk">
      <path d={d} fill="none" stroke={color} strokeWidth="1.4" strokeLinejoin="round" strokeLinecap="round" />
      <circle cx={last[0]} cy={last[1]} r="2" fill={color} />
    </svg>
  );
}

function Delta({ pct, dir }) {
  const arrow = dir === "down" ? "▼" : dir === "up" ? "▲" : "→";
  const sign = pct > 0 ? "+" : "";
  return <span className={"mc-delta " + dir}><span className="mc-arrow">{arrow}</span>{sign}{pct.toFixed(1)}%</span>;
}

function TrendChart({ history, current }) {
  const data = history.map((p, i) => i === history.length - 1 ? { ...p, v: current } : p);
  const W = 600, H = 190, pad = 10;
  const vals = data.map(d => d.v);
  const min = Math.min(...vals) * 0.9, max = Math.max(...vals) * 1.05, span = (max - min) || 1;
  const x = i => pad + (i / (data.length - 1)) * (W - pad * 2);
  const y = v => H - pad - ((v - min) / span) * (H - pad * 2);
  const line = data.map((d, i) => (i ? "L" : "M") + x(i).toFixed(1) + "," + y(d.v).toFixed(1)).join(" ");
  const area = line + ` L${x(data.length - 1).toFixed(1)},${H - pad} L${x(0).toFixed(1)},${H - pad} Z`;
  const lastX = x(data.length - 1), lastY = y(current);
  return (
    <div className="mc-trend">
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ height: 190 }}>
        <defs>
          <linearGradient id="mcArea" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor="var(--accent)" stopOpacity="0.18" />
            <stop offset="100%" stopColor="var(--accent)" stopOpacity="0" />
          </linearGradient>
        </defs>
        {[0.25, 0.5, 0.75].map(f => <line key={f} x1={pad} x2={W - pad} y1={pad + f * (H - pad * 2)} y2={pad + f * (H - pad * 2)} stroke="var(--rule)" strokeWidth="1" />)}
        <path d={area} fill="url(#mcArea)" />
        <path d={line} fill="none" stroke="var(--accent)" strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
        <circle cx={lastX} cy={lastY} r="4" fill="var(--accent)" stroke="var(--paper)" strokeWidth="1.5" />
      </svg>
      <div className="mc-trend-foot">
        {data.filter((_, i) => i % 2 === 0 || i === data.length - 1).map((d, i) => <span key={i}>{d.m}</span>)}
      </div>
    </div>
  );
}

function Bars({ rows, accentIndex }) {
  const max = Math.max(...rows.map(r => r.v), 1);
  return (
    <div className="mc-break">
      {rows.map((r, i) => (
        <div className="mc-bk-row" key={r.k}>
          <div className="mc-bk-label">{r.k}</div>
          <div className="mc-bk-track"><div className={"mc-bk-fill" + (i === accentIndex ? " accent" : "")} style={{ width: (r.v / max * 100) + "%" }} /></div>
          <div className="mc-bk-val">{gbp(r.v)}</div>
        </div>
      ))}
    </div>
  );
}

function AnimatedMoney({ value }) {
  const [disp, setDisp] = useMcState(value);
  const prev = useMcRef(value);
  const raf = useMcRef(0);
  useMcEffect(() => {
    cancelAnimationFrame(raf.current);
    const from = prev.current, to = value, t0 = performance.now(), dur = 650;
    const tick = (t) => {
      const p = Math.min(1, (t - t0) / dur);
      const e = 1 - Math.pow(1 - p, 3);
      setDisp(Math.round(from + (to - from) * e));
      if (p < 1) raf.current = requestAnimationFrame(tick); else prev.current = to;
    };
    raf.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf.current);
  }, [value]);
  return <>{disp.toLocaleString("en-GB")}</>;
}

// ---- record card -----------------------------------------------------------
function RecordCard({ r, onRemove, onIdentify }) {
  return (
    <div className={"mc-card" + (r.unknownPressing ? " mc-card-needspressing" : "")}>
      <div className="mc-card-actions">
        <button className="mc-iconbtn danger" title="Remove" onClick={() => onRemove(r.id)}>
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.4"><path d="M2 3.5h10M5 3.5V2h4v1.5M3.5 3.5l.6 8.5h5.8l.6-8.5"/></svg>
        </button>
      </div>
      <div className="mc-card-cover"><Sleeve album={r.album} size={76} /></div>
      <div className="mc-card-body">
        <div className="mc-card-top">
          <div>
            <div className="mc-card-title">{r.album.title}</div>
            <div className="mc-card-artist">{r.album.artist}</div>
          </div>
          {r.unknownPressing
            ? <span className="mc-cond mc-cond-unknown">No pressing</span>
            : <span className={"mc-cond " + condClass(r.condition)}>{r.condition}</span>}
        </div>
        {r.unknownPressing ? (
          <div className="mc-needspressing">
            <div className="mc-needspressing-msg">
              <b>Pressing not identified.</b> Tell us which pressing you own and we'll value it and add it to your collection total.
            </div>
            <div className="mc-needspressing-actions">
              <button className="mc-np-btn" onClick={() => onIdentify && onIdentify(r)}>Add pressing to value it</button>
              <button className="mc-np-link" onClick={() => window.__nav && window.__nav.goPressingGuide && window.__nav.goPressingGuide()}>How to identify it →</button>
            </div>
          </div>
        ) : (
          <>
            <div className="mc-card-meta">
              <b>{r.pressing.label}</b> · {r.pressing.country} · {r.pressing.year}<br />
              {r.pressing.format.join(" · ")}{r.pressing.catno && r.pressing.catno !== "—" ? " · " + r.pressing.catno : ""}
            </div>
            <div className="mc-card-foot">
              <div>
                <div className="mc-card-val"><span className="cur">£</span><AnimatedMoney value={r.value} /></div>
                {r.pressing.fromDiscogs
                  ? <div className="mc-card-range">Market low · {typeof r.pressing.numForSale === "number" && r.pressing.numForSale > 0 ? r.pressing.numForSale.toLocaleString("en-GB") + " for sale" : "via Discogs"}</div>
                  : <div className="mc-card-range">Estimated value</div>}
              </div>
              {r.pressing.fromDiscogs && (typeof r.pressing.have === "number" || typeof r.pressing.want === "number") && (r.pressing.have || r.pressing.want) ? (
                <div className="mc-card-community">
                  <div className="mc-cc-stat"><span className="mc-cc-num">{(r.pressing.have || 0).toLocaleString("en-GB")}</span><span className="mc-cc-label">own it</span></div>
                  <div className="mc-cc-stat"><span className="mc-cc-num">{(r.pressing.want || 0).toLocaleString("en-GB")}</span><span className="mc-cc-label">wishlist</span></div>
                </div>
              ) : null}
            </div>
          </>
        )}
      </div>
    </div>
  );
}

function WishCard({ r, onBuy, onMove, onRemove }) {
  return (
    <div className="mc-card wish">
      <div className="mc-card-actions">
        <button className="mc-iconbtn danger" title="Remove" onClick={() => onRemove(r.id)}>
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.4"><path d="M2 3.5h10M5 3.5V2h4v1.5M3.5 3.5l.6 8.5h5.8l.6-8.5"/></svg>
        </button>
      </div>
      <div className="mc-card-cover"><Sleeve album={r.album} size={76} /></div>
      <div className="mc-card-body">
        <div className="mc-card-top">
          <div>
            <div className="mc-card-title">{r.album.title}</div>
            <div className="mc-card-artist">{r.album.artist} · {r.album.year}</div>
          </div>
          {r.album.rank > 0 && <span className="mc-chip">№ {String(r.album.rank).padStart(3, "0")}</span>}
        </div>
        <div className="mc-card-meta"><b>{r.pressing.label}</b> · {r.pressing.country} · {r.pressing.year} · {r.pressing.format.join(" · ")}</div>
        <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", marginTop: 12 }}>
          <div>
            <div className="mc-card-val"><span className="cur">£</span><AnimatedMoney value={r.value} /></div>
            {r.pressing.fromDiscogs
              ? <div className="mc-card-range">Market low{typeof r.pressing.numForSale === "number" && r.pressing.numForSale > 0 ? " · " + r.pressing.numForSale.toLocaleString("en-GB") + " for sale" : ""}</div>
              : <div className="mc-card-range">Estimated value</div>}
          </div>
          {r.pressing.fromDiscogs && (r.pressing.have || r.pressing.want) ? (
            <div className="mc-card-community">
              <div className="mc-cc-stat"><span className="mc-cc-num">{(r.pressing.have || 0).toLocaleString("en-GB")}</span><span className="mc-cc-label">own it</span></div>
              <div className="mc-cc-stat"><span className="mc-cc-num">{(r.pressing.want || 0).toLocaleString("en-GB")}</span><span className="mc-cc-label">wishlist</span></div>
            </div>
          ) : null}
        </div>
        <div className="mc-card-foot">
          <div className="mc-buy-row">
            <a className="mc-buy" href={(window.BBR_buyUrl && window.BBR_buyUrl(r.album.title + " " + r.album.artist, r.album.slug)) || "#"} target="_blank" rel="noopener" onClick={() => window.BBR_trackClick && window.BBR_trackClick(r.album.slug, "collection")}>
              Buy on vinyl <span className="ar">→</span>
            </a>
            <button className="mc-move" onClick={() => onMove(r)} title="Mark as purchased">Got it</button>
          </div>
          <div className="mc-vendor">via {r.vendor || "Amazon UK"} · prices via Discogs</div>
        </div>
      </div>
    </div>
  );
}

// ===========================================================
//  POPULATED / EMPTY APP (re-seeds when dataMode changes via key)
// ===========================================================
function CollectionApp({ albums, dataMode, onRequireAuth, openAddRef }) {
  const store = window.BBR_store;
  const [, forceMc] = useMcState(0);
  useMcEffect(() => store.subscribe(() => forceMc((n) => n + 1)), []);
  const records = store.collection;
  const wishlist = store.wishlist;
  const [tab, setTab] = useMcState("collection");
  const [search, setSearch] = useMcState("");
  const [sortKey, setSortKey] = useMcState("value");
  const [filterGenre, setFilterGenre] = useMcState("all");
  const [add, setAdd] = useMcState(null); // {intent, preset, fromWishlistId}

  // expose opener so the marketing/empty CTAs + nav can trigger it
  useMcEffect(() => { if (openAddRef) openAddRef.current = (intent) => setAdd({ intent: intent || "collection" }); }, []);

  const resolved = useMcMemo(() => records.map(r => resolveRecord(r, albums)), [records, albums]);
  const resolvedWish = useMcMemo(() => wishlist.map(r => resolveRecord(r, albums)), [wishlist, albums]);

  const total = resolved.reduce((s, r) => s + r.value, 0);
  const needsPressingCount = resolved.filter(r => r.unknownPressing).length;
  const wishTotal = resolvedWish.reduce((s, r) => s + r.value, 0);
  const mostValuable = resolved.reduce((m, r) => (!m || r.value > m.value ? r : m), null);
  const avg = resolved.length ? Math.round(total / resolved.length) : 0;
  const latest = resolved.reduce((m, r) => (!m || r.dateAdded > m.dateAdded ? r : m), null);

  const genres = useMcMemo(() => Array.from(new Set(resolved.map(r => r.genre))).sort(), [resolved]);

  const view = useMcMemo(() => {
    let list = resolved.filter(r => {
      if (filterGenre !== "all" && r.genre !== filterGenre) return false;
      if (search && !((r.album.title + " " + r.album.artist).toLowerCase().includes(search.toLowerCase()))) return false;
      return true;
    });
    const cmp = {
      value: (a, b) => b.value - a.value,
      artist: (a, b) => a.album.artist.localeCompare(b.album.artist),
      year: (a, b) => a.album.year - b.album.year,
      added: (a, b) => b.dateAdded.localeCompare(a.dateAdded),
      condition: (a, b) => window.BBR_CONDITIONS.findIndex(c => c.code === a.condition) - window.BBR_CONDITIONS.findIndex(c => c.code === b.condition),
    }[sortKey];
    return list.slice().sort(cmp);
  }, [resolved, filterGenre, search, sortKey]);

  const wishView = useMcMemo(() => {
    const cmp = {
      value: (a, b) => b.value - a.value,
      added: (a, b) => b.dateAdded.localeCompare(a.dateAdded),
      ranking: (a, b) => (a.album.rank > 0 ? a.album.rank : 999) - (b.album.rank > 0 ? b.album.rank : 999),
    }[sortKey === "artist" || sortKey === "year" || sortKey === "condition" ? "value" : sortKey] || ((a, b) => b.value - a.value);
    return resolvedWish.slice().sort(cmp);
  }, [resolvedWish, sortKey]);

  // breakdowns
  const byDecade = useMcMemo(() => {
    const m = {};
    resolved.forEach(r => { m[r.decade] = (m[r.decade] || 0) + r.value; });
    return Object.entries(m).map(([k, v]) => ({ k, v })).sort((a, b) => a.k.localeCompare(b.k));
  }, [resolved]);
  const byGenre = useMcMemo(() => {
    const m = {};
    resolved.forEach(r => { m[r.genre] = (m[r.genre] || 0) + r.value; });
    return Object.entries(m).map(([k, v]) => ({ k, v })).sort((a, b) => b.v - a.v);
  }, [resolved]);

  function handleAdd(rec) {
    if (add.intent === "wishlist") {
      store.addToWishlist(rec);
    } else {
      store.addToCollection(rec);
      if (add.fromWishlistId) store.removeFromWishlist(add.fromWishlistId);
      if (add.replaceId) store.removeFromCollection(add.replaceId);
    }
    setAdd(null);
  }
  function moveToCollection(wr) {
    setAdd({ intent: "move", fromWishlistId: wr.id, preset: { album: wr.album, pressing: wr.pressing } });
  }
  // Re-open the add flow for a record whose pressing is unknown, so the user can
  // choose one. On finish we remove the old unidentified record and add the new.
  function identifyPressing(r) {
    setAdd({ intent: "collection", replaceId: r.id, preset: { album: r.album, pressing: null } });
  }

  const empty = resolved.length === 0 && tab === "collection";
  const wishEmpty = resolvedWish.length === 0 && tab === "wishlist";

  return (
    <div className="mc">
      {/* HERO */}
      <div className="mc-hero">
        <div>
          <div className="mc-hero-label">
            <span className="mc-eyebrow">Estimated collection value</span>
          </div>
          <div className="mc-hero-total"><span className="cur">£</span><AnimatedMoney value={total} /></div>
          {total > 0 ? (
            <>
              <div className="mc-hero-sub">
                <span className="mc-chip">{resolved.length} records</span>
                <span className="mc-chip">Avg {gbp(avg)}</span>
                <span className="mc-chip">+{gbp(43)} this month</span>
              </div>
              <div className="mc-hero-milestone">
                <div className="mc-milestone-bar"><div className="mc-milestone-fill" style={{ width: Math.min(100, total / 1500 * 100) + "%" }} /></div>
                <div className="mc-milestone-cap"><span>Next milestone</span><span>£1,500</span></div>
              </div>
            </>
          ) : (
            <div className="mc-hero-sub"><span className="mc-chip">Add your first record to begin</span></div>
          )}
        </div>
        {total > 0 && (
          <div className="mc-hero-stats">
            <div className="mc-stat">
              <div className="mc-stat-k">Most valuable</div>
              <div className="mc-stat-v">{gbp(mostValuable.value)}<small>{mostValuable.album.title}</small></div>
            </div>
            <div className="mc-stat">
              <div className="mc-stat-k">Latest addition</div>
              <div className="mc-stat-v" style={{ fontStyle: "italic" }}>{latest.album.title}<small style={{ fontStyle: "normal" }}>{latest.album.artist}</small></div>
            </div>
            <div className="mc-stat">
              <div className="mc-stat-k">Records</div>
              <div className="mc-stat-v">{resolved.length}<small>across {byGenre.length} genres</small></div>
            </div>
            <div className="mc-stat">
              <div className="mc-stat-k">Wishlist</div>
              <div className="mc-stat-v">{gbp(wishTotal)}<small>{resolvedWish.length} records wanted</small></div>
            </div>
          </div>
        )}
      </div>

      {/* TABS + CONTROLS */}
      <div className="mc-bar">
        <div className="mc-tabs">
          <button className={"mc-tab " + (tab === "collection" ? "active" : "")} onClick={() => setTab("collection")}>Collection<span className="ct">{resolved.length}</span></button>
          <button className={"mc-tab " + (tab === "wishlist" ? "active" : "")} onClick={() => setTab("wishlist")}>Wishlist<span className="ct">{resolvedWish.length}</span></button>
        </div>
        <div className="mc-controls">
          {tab === "collection" && (
            <div className="mc-search">
              <svg width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5"><circle cx="7" cy="7" r="5" /><path d="M11 11l3.5 3.5" /></svg>
              <input placeholder="Search your collection…" value={search} onChange={e => setSearch(e.target.value)} />
            </div>
          )}
          {tab === "collection" && (
            <div className="mc-select">
              <select value={filterGenre} onChange={e => setFilterGenre(e.target.value)}>
                <option value="all">All genres</option>
                {genres.map(g => <option key={g} value={g}>{g}</option>)}
              </select>
            </div>
          )}
          <div className="mc-select">
            <select value={sortKey} onChange={e => setSortKey(e.target.value)}>
              {tab === "collection" ? (
                <>
                  <option value="value">Sort: Value</option>
                  <option value="artist">Sort: Artist</option>
                  <option value="year">Sort: Year</option>
                  <option value="added">Sort: Date added</option>
                  <option value="condition">Sort: Condition</option>
                </>
              ) : (
                <>
                  <option value="value">Sort: Price</option>
                  <option value="added">Sort: Date added</option>
                  <option value="ranking">Sort: Ranking</option>
                </>
              )}
            </select>
          </div>
          <button className="mc-add" onClick={() => setAdd({ intent: tab === "wishlist" ? "wishlist" : "collection" })}>
            <span className="plus">+</span> {tab === "wishlist" ? "Add to wishlist" : "Add record"}
          </button>
        </div>
      </div>

      {/* WISHLIST TOTAL */}
      {tab === "wishlist" && resolvedWish.length > 0 && (
        <div style={{ display: "flex", alignItems: "baseline", gap: 14, marginBottom: 18 }}>
          <span className="mc-eyebrow">Estimated to complete</span>
          <span className="mc-money" style={{ fontSize: 26 }}>{gbp(wishTotal)}</span>
        </div>
      )}

      {/* GRID */}
      {empty && (
        <div className="mc-empty">
          <div className="mc-empty-stack">
            {[1, 5, 8].map((rank, i) => <div key={rank} style={{ "--r": (i - 1) * 6 + "deg" }}><Sleeve album={albums.find(a => a.rank === rank)} size={92} /></div>)}
          </div>
          <h3>Your shelf is empty</h3>
          <p>Log the records you own to see what your collection is worth. Start with your favourites from the Hundred, or add anything manually.</p>
          <div className="mc-empty-cta">
            <button className="mc-btn solid" onClick={() => setAdd({ intent: "collection" })}><span style={{ fontSize: 14 }}>+</span> Add your first record</button>
            <button className="mc-btn ghost" onClick={() => window.__nav && window.__nav.goList()}>Browse the List 100→1</button>
          </div>
        </div>
      )}
      {wishEmpty && (
        <div className="mc-empty">
          <h3>Nothing on the wishlist yet</h3>
          <p>Queue up the records you're hunting for. We'll track the price and give you a one-tap path to buy on vinyl.</p>
          <div className="mc-empty-cta">
            <button className="mc-btn solid" onClick={() => setAdd({ intent: "wishlist" })}><span style={{ fontSize: 14 }}>+</span> Add to wishlist</button>
          </div>
        </div>
      )}

      {tab === "collection" && !empty && needsPressingCount > 0 && (
        <div className="mc-np-banner">
          <span className="mc-np-banner-dot">?</span>
          <span className="mc-np-banner-text">
            {needsPressingCount === 1
              ? "1 record needs a pressing before it can be valued."
              : `${needsPressingCount} records need a pressing before they can be valued.`}
            {" "}Identify them to add their value to your collection total.
          </span>
          <button className="mc-np-banner-link" onClick={() => window.__nav && window.__nav.goPressingGuide && window.__nav.goPressingGuide()}>
            Identification guide →
          </button>
        </div>
      )}

      {tab === "collection" && !empty && (
        <div className="mc-grid">
          {view.map(r => <RecordCard key={r.id} r={r} onRemove={(id) => store.removeFromCollection(id)} onIdentify={identifyPressing} />)}
        </div>
      )}
      {tab === "wishlist" && !wishEmpty && (
        <div className="mc-grid">
          {wishView.map(r => <WishCard key={r.id} r={r} onMove={moveToCollection} onRemove={(id) => store.removeFromWishlist(id)} />)}
        </div>
      )}

      {/* DASHBOARD */}
      {tab === "collection" && resolved.length > 1 && (
        <div className="mc-dash">
          <div className="mc-dash-head">
            <h3>The numbers</h3>
            <span className="mc-eyebrow">Updated live as you grade &amp; add</span>
          </div>
          <div className="mc-dash-grid">
            <div className="mc-panel">
              <div className="mc-panel-k">Collection value · last 12 months</div>
              <TrendChart history={window.BBR_VALUE_HISTORY} current={total} />
            </div>
            <div className="mc-panel">
              <div className="mc-panel-k">Where the value sits</div>
              <Bars rows={byGenre} accentIndex={0} />
              <div style={{ height: 22 }} />
              <div className="mc-panel-k">By decade</div>
              <Bars rows={byDecade} accentIndex={-1} />
            </div>
          </div>
          <div className="mc-tiles">
            <div className="mc-tile">
              <div className="cv"><Sleeve album={mostValuable.album} size={64} /></div>
              <div>
                <div className="mc-tile-k">Crown jewel</div>
                <div className="mc-tile-t">{mostValuable.album.title}</div>
                <div className="mc-tile-s">{mostValuable.condition} · {gbp(mostValuable.value)} · {mostValuable.pressing.label} {mostValuable.pressing.year}</div>
              </div>
            </div>
            <div className="mc-tile">
              <div className="cv"><Sleeve album={latest.album} size={64} /></div>
              <div>
                <div className="mc-tile-k">Latest addition</div>
                <div className="mc-tile-t">{latest.album.title}</div>
                <div className="mc-tile-s">Added {latest.dateAdded} · {gbp(latest.value)}</div>
              </div>
            </div>
          </div>
          <p className="add-pr-attr" style={{ marginTop: 18, justifyContent: "flex-start" }}>
            <svg width="11" height="11" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.5"><circle cx="6" cy="6" r="5" /><path d="M6 5.5v3M6 3.6h.01" /></svg>
            Valuations are median sale prices via Discogs for each specific pressing &amp; grade.
          </p>
        </div>
      )}

      {add && (
        <AddRecordFlow
          albums={albums}
          intent={add.intent}
          preset={add.preset}
          onAdd={handleAdd}
          onClose={() => setAdd(null)}
        />
      )}
    </div>
  );
}

// ===========================================================
//  MARKETING SURFACE (logged out)
// ===========================================================
function MarketingSurface({ albums, onSignup, onLogin, onGate }) {
  const sample = [1, 6, 20, 23, 8].map(rank => albums.find(a => a.rank === rank));
  return (
    <div className="mkt">
      <div className="mkt-hero">
        <div>
          <div className="mkt-eyebrow">My Collection · free for readers</div>
          <h1 className="mkt-h1">Know what your <em>records</em> are really worth.</h1>
          <p className="mkt-lede">Log the vinyl you own, see a live valuation from real market data, and build a wishlist with a one-tap path to buy. Your shelf, valued, and a reason to come back.</p>
          <div className="mkt-cta">
            <button className="mc-btn solid" onClick={onSignup}>Create a free account</button>
            <button className="mc-btn ghost" onClick={onLogin}>Sign in</button>
          </div>
          <div className="mkt-fine">No cost · takes a minute · public collection on the leaderboards</div>
        </div>
        <div className="mkt-preview">
          <div className="mkt-dash in" aria-hidden="true">
            <div className="hd-dash-top">
              <div>
                <div className="hd-dash-val"><span className="cur">£</span>{window.HdCountUp ? <HdCountUp value={1240} /> : "1,240"}</div>
                <div className="hd-dash-cap">estimated collection value</div>
              </div>
              <span className="hd-dash-delta">&#9650; 12%</span>
            </div>
            {window.HeroSpark ? <HeroSpark /> : null}
            <div className="hd-dash-prog">
              <div className="hd-dash-prog-row"><span>Canon owned</span><span>23 / 100</span></div>
              <div className="hd-dash-bar"><i style={{ "--w": "23%" }} /></div>
            </div>
            <div className="hd-gbars">
              {[["Rock", "88%"], ["Soul / R&B", "60%"], ["Jazz", "40%"], ["Hip-Hop", "28%"]].map((row, i) => (
                <div className="hd-gbar" key={row[0]}>
                  <span className="hd-gbar-l">{row[0]}</span>
                  <span className="hd-gbar-t"><i style={{ "--w": row[1], transitionDelay: (i * 80) + "ms" }} /></span>
                </div>))}
            </div>
            <button className="mkt-dash-foot" onClick={onGate}>Sign up to value your own shelf &rarr;</button>
          </div>
        </div>
      </div>
      <div className="mkt-feat">
        <div className="mkt-feat-grid">
          {[
            { n: "01", h: "Track what you own", p: "Add records from the Hundred or anything manually. Pick the exact pressing and grade the condition." },
            { n: "02", h: "See what it's worth", p: "Every record is valued at the median market sale price for that pressing and grade, with a live running total." },
            { n: "03", h: "Buy what's next", p: "Queue up records you want, watch the price move, and buy on vinyl when you're ready." },
          ].map(f => (
            <div className="mkt-feat-cell" key={f.n}>
              <div className="mkt-feat-n">{f.n}</div>
              <div className="mkt-feat-h">{f.h}</div>
              <div className="mkt-feat-p">{f.p}</div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ===========================================================
//  PAGE WRAPPER
// ===========================================================
function MyCollection({ albums, user, dataMode, onAuthOpen, onGate }) {
  if (!user) {
    return <MarketingSurface albums={albums} onSignup={() => onAuthOpen("signup")} onLogin={() => onAuthOpen("login")} onGate={() => onGate("collection")} />;
  }
  // v2: verified collection (collection_items) + public leaderboards.
  return <CollectionAppV2 albums={albums} user={user} onGate={onGate} />;
}

Object.assign(window, { MyCollection });
