// marketplace-app.jsx — standalone Marketplace page.
// Mode-aware (Personal / Business). Interactive demo at the top, then catalog.

const { useState, useEffect, useMemo, useRef, createContext, useContext } = React;

// ── Translations (page-local) ──────────────────────────────────────────────
const MK_TR = {
  en: {
    nav_assistant: "Assistant", nav_marketplace: "Marketplace",
    nav_ecosystems: "Ecosystems", nav_builtin: "Built-in", nav_compare: "Why us",
    sign_in: "Sign in", get_started: "Get started",
    mode_personal: "Personal", mode_business: "Business",

    page_eyebrow_personal: "Marketplace · Personal",
    page_eyebrow_business: "Marketplace · Business",
    page_title_personal: "Forkable apps for your life. Live on install.",
    page_title_business: "Forkable apps for your company. Live on install.",
    page_lead_personal: "Real personal headaches, shipped as full sections. Click any card for a live preview. Want to talk to one? Scroll to the demo at the bottom — it talks back.",
    page_lead_business: "Real company tools, shipped as full sections. Click any card for a live preview. Want to talk to one? Scroll to the demo at the bottom — it talks back.",

    demo_eyebrow_personal: "Try it · Personal Finance",
    demo_eyebrow_business: "Try it · Conference Contacts",
    demo_title_personal: "Tell the assistant what to change. Watch the section morph.",
    demo_title_business: "Talk to it like a section in your company. Watch it morph.",
    demo_input_personal: "Try: \"add a Restaurants envelope of $200\"",
    demo_input_business: "Try: \"add a column for Company\"",
    demo_send: "Send", demo_thinking: "Thinking…",
    demo_suggest: "Try:",

    search: "Search sections, authors, tags…",
    categories: "Categories", popular: "Popular tags",
    install: "Install", open_preview: "Open preview", fork: "Fork",
    preview_tab: "Preview", schema_tab: "Schema", jobs_tab: "Jobs", rbac_tab: "RBAC",
    by: "by", stars: "stars", forks: "forks",
    tag_all: "All sections",
    foot_product: "Product", foot_build: "Build",
    foot_community: "Community", foot_company: "Company",
    foot_tagline: "areti is the unit-of-distribution shift: a section is a complete vertical slice, not a snippet.",
  },
  ru: {
    nav_assistant: "Ассистент", nav_marketplace: "Маркетплейс",
    nav_ecosystems: "Экосистемы", nav_builtin: "Из коробки", nav_compare: "Почему мы",
    sign_in: "Войти", get_started: "Попробовать",
    mode_personal: "Личное", mode_business: "Бизнес",

    page_eyebrow_personal: "Маркетплейс · Личное",
    page_eyebrow_business: "Маркетплейс · Бизнес",
    page_title_personal: "Форкаемые приложения для жизни. Поставил — работает.",
    page_title_business: "Форкаемые приложения для компании. Поставил — работает.",
    page_lead_personal: "Настоящие личные боли, упакованные в готовые секции. Кликни карточку — пройдись по живому превью. А если хочется поговорить с приложением — пролистай вниз до демо, оно отвечает.",
    page_lead_business: "Настоящие инструменты для компании, в виде готовых секций. А если хочется поговорить с приложением — пролистай вниз до демо, оно отвечает.",

    demo_eyebrow_personal: "Попробуй · Личные финансы",
    demo_eyebrow_business: "Попробуй · Контакты с конференций",
    demo_title_personal: "Скажи ассистенту, что поменять. Смотри, как секция перестраивается.",
    demo_title_business: "Говори с этим как с настоящей секцией в компании. Смотри, как она меняется.",
    demo_input_personal: "Например: «добавь конверт «Рестораны» на $200»",
    demo_input_business: "Например: «добавь колонку «Компания»»",
    demo_send: "Отправить", demo_thinking: "Думаю…",
    demo_suggest: "Попробуй:",

    search: "Найди секцию, автора или тег…",
    categories: "Категории", popular: "Популярные теги",
    install: "Поставить", open_preview: "Посмотреть", fork: "Форкнуть",
    preview_tab: "Превью", schema_tab: "Схема", jobs_tab: "Задачи", rbac_tab: "Доступы",
    by: "автор:", stars: "звёзд", forks: "форков",
    tag_all: "Все секции",
    foot_product: "Продукт", foot_build: "Сборка",
    foot_community: "Сообщество", foot_company: "Команда",
    foot_tagline: "areti меняет правила: делятся не кусками кода, а целыми секциями — со всем, что нужно для запуска.",
  }
};
const tr  = (k, lang) => (MK_TR[lang] && MK_TR[lang][k]) || MK_TR.en[k] || k;
const trm = (k, lang, mode) => {
  const kk = `${k}_${mode}`;
  return (MK_TR[lang] && MK_TR[lang][kk]) || (MK_TR.en && MK_TR.en[kk]) || tr(k, lang);
};

// ── Brand + Header ─────────────────────────────────────────────────────────
function BrandMark({ size = 28 }) {
  return (
    <span className="brand-mark"
      style={{ width: size, height: size, background: "transparent", border: 0 }}>
      <img src="assets/potato.png" alt="areti" width={size} height={size}
        style={{ width: size, height: size, objectFit: "contain", display: "block" }} />
    </span>
  );
}
function Brand() {
  return (
    <a href="Landing Page.html" className="brand">
      <BrandMark size={44} />
      <span style={{ display: "flex", flexDirection: "column" }}>
        <span className="brand-name">areti</span>
      </span>
    </a>
  );
}

function Header({ theme, setTheme, lang, setLang, mode, setMode }) {
  return (
    <header className="nav">
      <div className="nav-inner">
        <Brand />
        <span className="mode-toggle" role="group" aria-label="Mode">
          <button type="button" className={mode === "personal" ? "on" : ""} onClick={() => setMode("personal")}>
            <I.user width={14} height={14} /> {tr("mode_personal", lang)}
          </button>
          <button type="button" className={mode === "business" ? "on" : ""} onClick={() => setMode("business")}>
            <I.building width={14} height={14} /> {tr("mode_business", lang)}
          </button>
        </span>
        <nav className="nav-links" aria-label="Primary">
          <a className="nav-link" href="Landing Page.html#assistant">{tr("nav_assistant", lang)}</a>
          <a className="nav-link" href="Marketplace.html" aria-current="page" style={{color:"hsl(var(--foreground))"}}>{tr("nav_marketplace", lang)}</a>
          <a className="nav-link" href="Landing Page.html#ecosystems">{tr("nav_ecosystems", lang)}</a>
          <a className="nav-link" href="Landing Page.html#built-in">{tr("nav_builtin", lang)}</a>
          <a className="nav-link" href="Landing Page.html#compare">{tr("nav_compare", lang)}</a>
        </nav>
        <div className="nav-cta">
          <span className="lang-toggle" role="group" aria-label="Language">
            <button type="button" className={lang === "en" ? "on" : ""} onClick={() => setLang("en")}>EN</button>
            <span className="sep">|</span>
            <button type="button" className={lang === "ru" ? "on" : ""} onClick={() => setLang("ru")}>RU</button>
          </span>
          <button className="icon-btn" type="button" aria-label="Toggle theme"
            onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
            {theme === "dark" ? <I.sun /> : <I.moon />}
          </button>
          <button className="btn btn-ghost btn-sm" type="button">{tr("sign_in", lang)}</button>
          <button className="btn btn-primary btn-sm" type="button">
            {tr("get_started", lang)} <I.arrowRight />
          </button>
        </div>
      </div>
    </header>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// INTERACTIVE DEMO at top of marketplace
// ─────────────────────────────────────────────────────────────────────────────

// Initial states per mode — small but realistic.
const INITIAL_FINANCE = {
  __v: 3,
  month: "May",
  income: 5400,
  envelopes: [
    { name: "Rent",         budget: 1800, spent: 1800, hue: "primary" },
    { name: "Groceries",    budget: 600,  spent: 432,  hue: "green" },
    { name: "Transport",    budget: 200,  spent: 112,  hue: "cyan" },
    { name: "Subscriptions",budget: 80,   spent: 50,   hue: "violet" },
  ],
  txns: [
    { date: "May 14", merchant: "Whole Foods",   amount: -84.20, category: "Groceries" },
    { date: "May 13", merchant: "Uber",          amount: -18.40, category: "Transport" },
    { date: "May 12", merchant: "Netflix",       amount: -15.99, category: "Subscriptions" },
    { date: "May 10", merchant: "Payroll",       amount:  5400.00, category: "Income" },
  ],
};

const INITIAL_CONTACTS = {
  __v: 2,
  event: "Web Summit 2026",
  columns: ["Name", "Role", "Telegram", "LinkedIn", "Notes"],
  contacts: [
    { name: "Maya Chen",   role: "UX Lead @ OpenAI",         telegram: "@maya",      linkedin: "/in/maya-chen",   notes: "Wants intro to design team" },
    { name: "Jonas Park",  role: "PM @ Linear",              telegram: "@jonas_p",   linkedin: "/in/jonaspark",   notes: "Following up about API hooks" },
    { name: "Ali Bakr",    role: "Eng @ Stripe",             telegram: "@ali",       linkedin: "/in/ali-bakr",    notes: "Wants beta access" },
  ],
  me: {
    name: "You",
    title: "Founder @ Areti",
    telegram: "@you_areti",
    linkedin: "/in/you-areti",
  },
};

function loadDemoState(mode) {
  const init = mode === "business" ? INITIAL_CONTACTS : INITIAL_FINANCE;
  try {
    const raw = localStorage.getItem(`areti-demo-${mode}`);
    if (raw) {
      const parsed = JSON.parse(raw);
      if (parsed && parsed.__v === init.__v) return parsed;
    }
  } catch (e) {}
  return structuredClone(init);
}
function saveDemoState(mode, state) {
  try { localStorage.setItem(`areti-demo-${mode}`, JSON.stringify(state)); } catch (e) {}
}

function InteractiveDemo({ mode, lang }) {
  const [state, setState] = useState(() => loadDemoState(mode));
  const [busy, setBusy] = useState(false);
  const [msg, setMsg] = useState("");
  const [log, setLog] = useState([]); // [{role, text}]
  const [flashKey, setFlashKey] = useState(0); // bump to animate body
  const initialMode = useRef(mode);

  // When mode changes, reload state from storage
  useEffect(() => {
    setState(loadDemoState(mode));
    setLog([]);
    setMsg("");
    initialMode.current = mode;
  }, [mode]);

  // Persist
  useEffect(() => { saveDemoState(mode, state); }, [mode, state]);

  const suggestions = mode === "business"
    ? [
        "Add a column for Company",
        "Add Sara Kim from Vercel, telegram @sara, follows up next week",
        "Remove anyone from Stripe",
      ]
    : [
        "Add a new category called Parents",
        "Rename Budgeted to Spend",
        "Add a dropdown category chooser",
      ];

  const send = async (text) => {
    const userText = (text || msg).trim();
    if (!userText || busy) return;
    setMsg("");
    setLog(l => [...l, { role: "user", text: userText }]);
    setBusy(true);

    // Build a strict system prompt — return only valid JSON describing changes.
    const sys = mode === "business"
      ? `You modify a "Conference Contacts" app's JSON state. Return ONLY a strict JSON object, no commentary, no markdown fences. Shape:
{
  "narration": "One short sentence about what changed.",
  "patch": {
    "event"?: string,
    "columns"?: string[],
    "add_contacts"?: [{ "name": string, "role"?: string, "telegram"?: string, "linkedin"?: string, "notes"?: string }],
    "remove_contacts_matching"?: string,   // a substring; remove any contact whose JSON contains it (case-insensitive)
    "update_me"?: { "name"?: string, "title"?: string, "telegram"?: string, "linkedin"?: string }
  }
}
Only include keys you want to change. Keep responses tight.`
      : `You modify a "Personal Finance" app's JSON state. Return ONLY a strict JSON object, no commentary, no markdown fences. Shape:
{
  "narration": "One short sentence about what changed.",
  "patch": {
    "month"?: string,
    "income"?: number,
    "add_envelopes"?: [{ "name": string, "budget": number, "hue"?: "primary"|"green"|"cyan"|"violet"|"amber"|"rose"|"teal" }],
    "remove_envelopes_named"?: string[],
    "update_envelopes"?: [{ "name": string, "budget"?: number, "spent"?: number }],
    "add_txns"?: [{ "date"?: string, "merchant": string, "amount": number, "category"?: string }]
  }
}
Only include keys you want to change. Amounts in USD as numbers.`;

    const userMessage = `Current state:\n${JSON.stringify(state)}\n\nUser said: ${userText}`;

    let resp;
    try {
      resp = await window.claude.complete({
        messages: [
          { role: "user", content: sys + "\n\n" + userMessage }
        ]
      });
    } catch (e) {
      setLog(l => [...l, { role: "bot", text: "Couldn't reach the assistant. Try again." }]);
      setBusy(false);
      return;
    }

    // Extract first {...} block from response
    let parsed;
    try {
      const m = resp.match(/\{[\s\S]*\}/);
      parsed = m ? JSON.parse(m[0]) : null;
    } catch (e) {
      parsed = null;
    }
    if (!parsed) {
      setLog(l => [...l, { role: "bot", text: "Hmm, didn't get clean JSON back. Try a clearer request." }]);
      setBusy(false);
      return;
    }
    const { narration, patch } = parsed;
    setState(s => applyPatch(s, patch, mode));
    setFlashKey(k => k + 1);
    setLog(l => [...l, { role: "bot", text: narration || "Done." }]);
    setBusy(false);
  };

  const reset = () => {
    const init = mode === "business" ? structuredClone(INITIAL_CONTACTS) : structuredClone(INITIAL_FINANCE);
    setState(init);
    setLog([]);
    setFlashKey(k => k + 1);
  };

  return (
    <section className="demo-shell">
      <div className="demo-head">
        <span className="eyebrow"><span className="dot"/> {trm("demo_eyebrow", lang, mode)}</span>
        <h2 className="demo-title">{trm("demo_title", lang, mode)}</h2>
      </div>

      <div className="demo-board chat-left">
        <div className="demo-stage">
          <div className="demo-stage-bar">
            <span className="browser-dot" style={{background:"hsl(0 70% 60%)"}}/>
            <span className="browser-dot" style={{background:"hsl(38 90% 55%)"}}/>
            <span className="browser-dot" style={{background:"hsl(142 60% 50%)"}}/>
            <span className="url-pill">/app/{mode === "business" ? "contacts" : "finance"}</span>
            <span style={{marginLeft:"auto", display:"inline-flex", gap:6, alignItems:"center", fontSize:11, color:"hsl(var(--muted-foreground))"}}>
              <span className="live-dot"/> live · talks back
            </span>
          </div>
          <div className="demo-stage-body" key={flashKey}>
            {mode === "business"
              ? <ContactsApp state={state}/>
              : <FinanceApp  state={state}/>}
          </div>
        </div>

        <div className="demo-side">
          <div className="demo-chat-window">
            <div className="demo-chat-log">
              {log.length === 0 && (
                <div className="demo-chat-empty">
                  <I.spark width={20} height={20}/>
                  <p>{trm("demo_title", lang, mode)}</p>
                </div>
              )}
              {log.map((m, i) => (
                <div className={`demo-chat-msg ${m.role}`} key={i}>
                  <div className="bubble">{m.text}</div>
                </div>
              ))}
              {busy && (
                <div className="demo-chat-msg bot">
                  <div className="bubble"><span className="demo-typing"><span/><span/><span/></span> {tr("demo_thinking", lang)}</div>
                </div>
              )}
            </div>
            <div className="demo-suggest">
              <span className="demo-suggest-label">{tr("demo_suggest", lang)}</span>
              {suggestions.map(s => (
                <button key={s} type="button" className="demo-suggest-chip" onClick={() => send(s)} disabled={busy}>
                  {s}
                </button>
              ))}
            </div>
            <div className="demo-input">
              <input
                type="text"
                placeholder={trm("demo_input", lang, mode)}
                value={msg}
                onChange={(e) => setMsg(e.target.value)}
                onKeyDown={(e) => { if (e.key === "Enter") send(); }}
                disabled={busy}
              />
              <button type="button" className="btn btn-primary btn-sm" onClick={() => send()} disabled={busy}>
                <I.send width={14} height={14}/>
              </button>
              <button type="button" className="icon-btn" title="Reset" onClick={reset}>
                <I.x width={14} height={14}/>
              </button>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

// Apply patch into state immutably (mode-aware schema).
function applyPatch(s, patch, mode) {
  if (!patch || typeof patch !== "object") return s;
  const next = structuredClone(s);
  if (mode === "business") {
    if (Array.isArray(patch.columns)) next.columns = patch.columns;
    if (typeof patch.event === "string") next.event = patch.event;
    if (Array.isArray(patch.add_contacts)) {
      for (const c of patch.add_contacts) {
        if (c && c.name) next.contacts.push({
          name: String(c.name).slice(0, 60),
          role: c.role || "",
          telegram: c.telegram || "",
          linkedin: c.linkedin || "",
          notes: c.notes || "",
        });
      }
    }
    if (typeof patch.remove_contacts_matching === "string" && patch.remove_contacts_matching.trim()) {
      const needle = patch.remove_contacts_matching.toLowerCase();
      next.contacts = next.contacts.filter(c => !JSON.stringify(c).toLowerCase().includes(needle));
    }
    if (patch.update_me && typeof patch.update_me === "object") {
      next.me = { ...next.me, ...patch.update_me };
    }
  } else {
    if (typeof patch.month === "string") next.month = patch.month;
    if (typeof patch.income === "number") next.income = patch.income;
    if (Array.isArray(patch.add_envelopes)) {
      for (const e of patch.add_envelopes) {
        if (e && e.name) next.envelopes.push({
          name: String(e.name).slice(0, 40),
          budget: Number(e.budget) || 0,
          spent: 0,
          hue: e.hue || pickHue(next.envelopes.length),
        });
      }
    }
    if (Array.isArray(patch.remove_envelopes_named)) {
      const set = new Set(patch.remove_envelopes_named.map(n => n.toLowerCase()));
      next.envelopes = next.envelopes.filter(e => !set.has(e.name.toLowerCase()));
    }
    if (Array.isArray(patch.update_envelopes)) {
      for (const u of patch.update_envelopes) {
        const env = next.envelopes.find(e => e.name.toLowerCase() === String(u.name||"").toLowerCase());
        if (env) {
          if (typeof u.budget === "number") env.budget = u.budget;
          if (typeof u.spent  === "number") env.spent  = u.spent;
        }
      }
    }
    if (Array.isArray(patch.add_txns)) {
      for (const tx of patch.add_txns) {
        if (tx && (tx.merchant || tx.amount !== undefined)) next.txns.unshift({
          date: tx.date || "today",
          merchant: tx.merchant || "(unknown)",
          amount: Number(tx.amount) || 0,
          category: tx.category || "",
        });
      }
    }
  }
  return next;
}
function pickHue(i) {
  const palette = ["amber","rose","teal","green","cyan","violet","primary","indigo","orange"];
  return palette[i % palette.length];
}

// ── Personal Finance app UI (the demo "section") ───────────────────────────
function FinanceApp({ state }) {
  const totalBudget = state.envelopes.reduce((a, e) => a + (e.budget || 0), 0);
  const totalSpent  = state.envelopes.reduce((a, e) => a + (e.spent  || 0), 0);
  const remaining   = state.income - totalSpent;
  return (
    <div className="fa">
      <div className="fa-head">
        <h3>Personal Finance</h3>
        <span className="muted" style={{fontSize:12}}>{state.month} · live</span>
      </div>
      <div className="fa-kpis">
        <div className="fa-kpi"><div className="lbl">Income</div><div className="val">${money(state.income)}</div></div>
        <div className="fa-kpi"><div className="lbl">Budgeted</div><div className="val">${money(totalBudget)}</div></div>
        <div className="fa-kpi">
          <div className="lbl">Remaining</div>
          <div className="val" style={{color: remaining >= 0 ? "hsl(var(--success))" : "hsl(var(--destructive))"}}>${money(remaining)}</div>
        </div>
      </div>
      <div className="fa-envs">
        {state.envelopes.map(e => {
          const pct = e.budget ? Math.min(100, Math.round((e.spent / e.budget) * 100)) : 0;
          const over = e.spent > e.budget;
          const hue = HUE[e.hue] || HUE.primary;
          return (
            <div key={e.name} className="fa-env">
              <div className="fa-env-row">
                <span className="fa-env-name">
                  <span className="dotc" style={{background:`hsl(${hue})`}}/>
                  {e.name}
                </span>
                <span className="fa-env-amt">
                  <b>${money(e.spent)}</b>
                  <span className="muted"> / ${money(e.budget)}</span>
                </span>
              </div>
              <div className="fa-env-bar">
                <span style={{width:`${pct}%`, background: over ? "hsl(var(--destructive))" : `hsl(${hue})`}}/>
              </div>
            </div>
          );
        })}
      </div>
      <div className="fa-txns">
        <div className="fa-txns-head">Recent activity</div>
        {state.txns.slice(0, 5).map((t, i) => (
          <div key={i} className="fa-txn">
            <span className="fa-txn-date">{t.date}</span>
            <span className="fa-txn-merch">{t.merchant}</span>
            <span className="fa-txn-cat muted">{t.category}</span>
            <span className={`fa-txn-amt ${t.amount > 0 ? "pos" : ""}`}>
              {t.amount > 0 ? "+" : ""}${money(t.amount)}
            </span>
          </div>
        ))}
      </div>
    </div>
  );
}
function money(n) {
  const v = Math.abs(Number(n) || 0);
  return v.toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: 2 });
}

// ── Conference Contacts app UI (the demo "section") ────────────────────────
function ContactsApp({ state }) {
  return (
    <div className="ca">
      <div className="ca-head">
        <div>
          <h3>Conference Contacts</h3>
          <div className="muted" style={{fontSize:12}}>{state.event} · {state.contacts.length} contacts</div>
        </div>
        <button className="btn btn-outline btn-sm" type="button"><I.plus width={12} height={12}/> Add contact</button>
      </div>

      <div className="ca-grid">
        <div className="ca-table">
          <div className="ca-row hd">
            {state.columns.map((c, i) => <span key={i}>{c}</span>)}
          </div>
          {state.contacts.map((c, i) => (
            <div className="ca-row" key={i} style={{gridTemplateColumns: `repeat(${state.columns.length}, minmax(0,1fr))`}}>
              {state.columns.map((col, j) => {
                const key = col.toLowerCase();
                let val = c[key];
                if (val == null) {
                  // try the original schema mapping
                  if (key === "name") val = c.name;
                  else if (key === "role") val = c.role;
                  else if (key === "telegram") val = c.telegram;
                  else if (key === "linkedin") val = c.linkedin;
                  else if (key === "notes") val = c.notes;
                  else val = c[col] || "";
                }
                return (
                  <span key={j} className={key === "name" ? "ca-cell-name" : "ca-cell"} title={val || ""}>
                    {key === "telegram" && val ? <span style={{display:"inline-flex", alignItems:"center", gap:4}}><span className="ca-pill tg">tg</span> {val}</span>
                      : key === "linkedin" && val ? <span style={{display:"inline-flex", alignItems:"center", gap:4}}><span className="ca-pill li">in</span> {val}</span>
                      : val || <span className="muted">—</span>}
                  </span>
                );
              })}
            </div>
          ))}
        </div>

        <div className="ca-mycard">
          <div className="ca-mycard-head">My Card</div>
          <div className="ca-mycard-body">
            <div className="ca-qr"><QRPlaceholder seed={state.me.telegram || state.me.name}/></div>
            <div className="ca-me">
              <div className="ca-me-name">{state.me.name}</div>
              <div className="muted" style={{fontSize:12}}>{state.me.title}</div>
              <div className="ca-me-row"><span className="ca-pill tg">tg</span>{state.me.telegram}</div>
              <div className="ca-me-row"><span className="ca-pill li">in</span>{state.me.linkedin}</div>
            </div>
          </div>
          <div className="ca-mycard-foot muted">Scan to add me — Telegram + LinkedIn jump straight to your contacts list.</div>
        </div>
      </div>
    </div>
  );
}

// Stylized QR placeholder (deterministic from seed)
function QRPlaceholder({ seed = "areti" }) {
  // hash seed → boolean grid
  const N = 11;
  const grid = useMemo(() => {
    let h = 0; for (let i = 0; i < seed.length; i++) h = (h * 31 + seed.charCodeAt(i)) | 0;
    const g = [];
    for (let y = 0; y < N; y++) {
      const row = [];
      for (let x = 0; x < N; x++) {
        h = (h * 1103515245 + 12345) & 0x7fffffff;
        row.push((h % 100) < 48);
      }
      g.push(row);
    }
    // corner finders
    const corners = [[0,0],[0,N-3],[N-3,0]];
    for (const [cy,cx] of corners) {
      for (let y=0;y<3;y++) for (let x=0;x<3;x++) g[cy+y][cx+x] = (y===0||y===2||x===0||x===2);
    }
    return g;
  }, [seed]);
  return (
    <svg viewBox={`0 0 ${N} ${N}`} className="qr-svg" aria-hidden="true">
      <rect width={N} height={N} fill="hsl(var(--background))"/>
      {grid.flatMap((row, y) => row.map((on, x) => on
        ? <rect key={`${x}-${y}`} x={x} y={y} width="1" height="1" fill="currentColor"/>
        : null))}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Marketplace card (clickable opens preview modal)
// ─────────────────────────────────────────────────────────────────────────────
function MarketCard({ card, onOpen, lang }) {
  const IconCmp = I[card.iconKey];
  return (
    <article className="mk-card" onClick={() => onOpen(card)} style={{cursor:"pointer"}}>
      <div className="mk-thumb" style={{ "--mk-color": `hsl(${card.hue})` }}>
        <span className="glow" />
        <span style={{ position:"absolute", top:14, left:14, fontSize:10, fontWeight:600,
          letterSpacing:".07em", textTransform:"uppercase",
          color:"hsl(var(--muted-foreground))" }}>{(card.tags?.[0]) || "Section"}</span>
        <span style={{
          position: "absolute", right: 14, top: 14,
          width: 30, height: 30, borderRadius: 8,
          background: `hsl(${card.hue} / 0.12)`, color: `hsl(${card.hue})`,
          display: "inline-flex", alignItems: "center", justifyContent: "center",
        }}><IconCmp /></span>
        <div className="mk-thumb-bars" style={{ top: 48 }}>
          <span className="mk-thumb-row" style={{ width: "55%" }} />
          <div style={{ display: "flex", gap: 6, height: 28 }}>
            <span className="mk-thumb-tile" />
            <span className="mk-thumb-tile" style={{ background: `hsl(${card.hue} / 0.12)`, borderColor: `hsl(${card.hue} / 0.3)` }} />
            <span className="mk-thumb-tile" />
          </div>
          <span className="mk-thumb-row" style={{ width: "70%" }} />
          <span className="mk-thumb-row" style={{ width: "40%" }} />
        </div>
      </div>
      <div className="mk-meta">
        <div className="mk-meta-head">
          <div className="mk-title">{card.title}</div>
          {card.verified && <span className="pubchip verified">Verified</span>}
        </div>
        <div className="mk-author"><I.user width={11} height={11} /> {card.author}</div>
        <div className="mk-desc">{card.desc}</div>
      </div>
      <div className="mk-foot">
        <div className="mk-stats">
          <span className="mk-stat"><I.starFill /> {card.stars.toLocaleString()}</span>
          <span className="mk-stat"><I.fork /> {card.forks}</span>
          <span className="mk-stat credits">{card.credits}</span>
        </div>
        <span className="mk-install">{tr("open_preview", lang)} <I.arrowRight /></span>
      </div>
    </article>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Section preview modal (unchanged from before, lightly mode-adjusted)
// ─────────────────────────────────────────────────────────────────────────────
function SectionPreviewModal({ card, onClose, lang }) {
  const [tab, setTab] = useState("preview");
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => { document.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
  }, [onClose]);
  if (!card) return null;
  const IconCmp = I[card.iconKey];
  const tabs = [
    ["preview", tr("preview_tab", lang)],
    ["schema",  tr("schema_tab", lang)],
    ["jobs",    tr("jobs_tab", lang)],
    ["rbac",    tr("rbac_tab", lang)],
  ];
  return (
    <div className="sp-back" onClick={onClose}>
      <div className="sp-modal" onClick={(e) => e.stopPropagation()}>
        <div className="sp-head">
          <span className="ic" style={{ background: `hsl(${card.hue} / 0.14)`, color: `hsl(${card.hue})` }}><IconCmp /></span>
          <div style={{display:"flex", flexDirection:"column"}}>
            <span className="name">{card.title} {card.verified && <span className="pubchip verified" style={{marginLeft:6}}>Verified</span>}</span>
            <span className="by">{tr("by", lang)} {card.author} · {card.tags?.[0]}</span>
          </div>
          <span className="stats" style={{marginLeft:24}}>
            <span><I.starFill /> {card.stars.toLocaleString()}</span>
            <span><I.fork /> {card.forks}</span>
            <span style={{color:"hsl(var(--success))", fontWeight:600}}>{card.credits}</span>
          </span>
          <div className="actions">
            <button className="btn btn-outline btn-sm" type="button"><I.fork /> {tr("fork", lang)}</button>
            <button className="btn btn-primary btn-sm" type="button"><I.install /> {tr("install", lang)}</button>
            <button className="sp-close" type="button" onClick={onClose} aria-label="Close"><I.x /></button>
          </div>
        </div>
        <div className="sp-tabs">
          {tabs.map(([id, label]) => (
            <button key={id} className={`sp-tab ${tab === id ? "on" : ""}`} onClick={() => setTab(id)}>{label}</button>
          ))}
        </div>
        <div className="sp-body">
          {tab === "preview" && <GenericSectionMock card={card}/>}
          {tab === "schema"  && <SchemaMock card={card}/>}
          {tab === "jobs"    && <JobsMock card={card}/>}
          {tab === "rbac"    && <RbacMock card={card}/>}
        </div>
      </div>
    </div>
  );
}

function GenericSectionMock({ card }) {
  return (
    <div className="sp-mock">
      <div className="sp-mock-bar">
        <span className="browser-dot" style={{background:"hsl(0 70% 60%)"}} />
        <span className="browser-dot" style={{background:"hsl(38 90% 55%)"}} />
        <span className="browser-dot" style={{background:"hsl(142 60% 50%)"}} />
        <span className="url-pill" style={{marginLeft:6}}>/app/{card.id}</span>
        <span style={{marginLeft:"auto"}}>installed · auto-registered</span>
      </div>
      <div className="sp-mock-body">
        <div className="sp-grid">
          <div className="sp-row">
            <div className="sp-tile"><div className="lbl">Items</div><div className="val">42</div><div className="delta">+3 this week</div></div>
            <div className="sp-tile"><div className="lbl">Active</div><div className="val">28</div><div className="delta">14 archived</div></div>
            <div className="sp-tile"><div className="lbl">Last sync</div><div className="val">2m</div><div className="delta">auto, hourly</div></div>
          </div>
          <div style={{padding: 6, color: "hsl(var(--muted-foreground))", fontSize: 13}}>
            <div style={{display:"flex", flexDirection:"column", gap: 10}}>
              <div style={{height:14, width:"60%", background:"hsl(var(--muted))", borderRadius:6}}/>
              <div style={{height:14, width:"42%", background:"hsl(var(--muted))", borderRadius:6}}/>
              <div style={{display:"flex", gap:10, marginTop:8}}>
                <div style={{flex:1, height:90, background:`hsl(${card.hue} / 0.08)`, border:`1px solid hsl(${card.hue} / 0.25)`, borderRadius:10}}/>
                <div style={{flex:1, height:90, background:"hsl(var(--muted))", borderRadius:10}}/>
                <div style={{flex:1, height:90, background:"hsl(var(--muted))", borderRadius:10}}/>
              </div>
              <div style={{height:14, width:"75%", background:"hsl(var(--muted))", borderRadius:6, marginTop:6}}/>
              <div style={{height:14, width:"58%", background:"hsl(var(--muted))", borderRadius:6}}/>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function SchemaMock({ card }) {
  const sql = `create table ${card.id.replace(/-/g, "_")} (
  id uuid primary key default gen_random_uuid(),
  user_id uuid references auth.users on delete cascade,
  created_at timestamptz default now()
);
alter table ${card.id.replace(/-/g, "_")} enable row level security;
create policy owner_rw on ${card.id.replace(/-/g, "_")}
  using (auth.uid() = user_id) with check (auth.uid() = user_id);`;
  return (
    <div className="sp-grid">
      <div style={{fontSize:13, color:"hsl(var(--muted-foreground))"}}>Generated migrations · Supabase + RLS · runs on install</div>
      <pre className="sp-pre">{sql}</pre>
    </div>
  );
}

function JobsMock({ card }) {
  const jobs = [
    [`${card.id.replace(/-/g,"_")}_sync`,    "@hourly",     "12 min ago", "ok"],
    [`${card.id.replace(/-/g,"_")}_digest`,  "0 18 * * 0",  "Sunday",     "ok"],
  ];
  return (
    <div className="sp-grid">
      <div style={{fontSize:13, color:"hsl(var(--muted-foreground))"}}>Trigger.dev · auto-registered</div>
      <div className="habit-table">
        <div className="habit-row hd" style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
          <span className="name">Job</span><span className="name">Schedule</span><span className="name">Last run</span><span className="name">Result</span>
        </div>
        {jobs.map(j => (
          <div className="habit-row" key={j[0]} style={{ gridTemplateColumns: "1fr 1fr 1fr 1fr" }}>
            <span className="name mono" style={{fontSize:12}}>{j[0]}</span>
            <span className="mono" style={{fontSize:12, color:"hsl(var(--muted-foreground))"}}>{j[1]}</span>
            <span style={{fontSize:12, color:"hsl(var(--muted-foreground))"}}>{j[2]}</span>
            <span style={{fontSize:12, color:"hsl(var(--success))", fontWeight:500}}>{j[3]}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function RbacMock({ card }) {
  const roles = [
    ["owner",     "full read/write",                     HUE.primary],
    ["viewer",    "read-only on shared items",           HUE.cyan],
    ["assistant", "read when MCP is enabled",            HUE.violet],
  ];
  return (
    <div className="sp-grid">
      <div style={{fontSize:13, color:"hsl(var(--muted-foreground))"}}>Roles + policies generated for this section</div>
      <div style={{display:"grid", gap: 10}}>
        {roles.map(([role, desc, hue]) => (
          <div key={role} style={{
            display:"flex", alignItems:"center", gap:12,
            padding:"14px 16px", border:"1px solid hsl(var(--border))",
            borderRadius:10, background:"hsl(var(--card))",
          }}>
            <span style={{
              width:36, height:36, borderRadius:9,
              background:`hsl(${hue} / 0.12)`, color:`hsl(${hue})`,
              display:"inline-flex", alignItems:"center", justifyContent:"center",
            }}><I.shield /></span>
            <span style={{display:"flex", flexDirection:"column"}}>
              <span style={{fontSize:14, fontWeight:600}}>{role}</span>
              <span style={{fontSize:12, color:"hsl(var(--muted-foreground))"}}>{desc}</span>
            </span>
            <span className="mono" style={{
              marginLeft:"auto", fontSize:11,
              background:"hsl(var(--muted))", padding:"3px 9px",
              borderRadius:6, color:"hsl(var(--muted-foreground))",
            }}>policy.sql</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────────────
// Page
// ─────────────────────────────────────────────────────────────────────────────
function MarketplacePage() {
  const [theme, setTheme] = useState(() =>
    localStorage.getItem("idp-theme") ||
    (matchMedia && matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light")
  );
  const [lang, setLang] = useState(() => localStorage.getItem("idp-lang") || "en");
  const [mode, setMode] = useState(() => localStorage.getItem("idp-mode") || "personal");
  const [filter, setFilter] = useState("All");
  const [query, setQuery] = useState("");
  const [open, setOpen] = useState(null);

  useEffect(() => {
    document.documentElement.classList.toggle("dark", theme === "dark");
    document.body.dataset.theme = theme;
    localStorage.setItem("idp-theme", theme);
  }, [theme]);
  useEffect(() => {
    document.documentElement.lang = lang;
    localStorage.setItem("idp-lang", lang);
  }, [lang]);
  useEffect(() => {
    document.body.dataset.mode = mode;
    localStorage.setItem("idp-mode", mode);
    setFilter("All");
  }, [mode]);

  // Open modal from URL hash on load (links from landing card)
  useEffect(() => {
    const id = (location.hash || "").replace("#","");
    if (!id) return;
    const all = [...(window.MARKET_PERSONAL||[]), ...(window.MARKET_BUSINESS||[])];
    const card = all.find(c => c.id === id);
    if (card) setOpen(card);
  }, []);

  const data = mode === "business" ? MARKET_BUSINESS : MARKET_PERSONAL;

  const cats = useMemo(() => {
    const map = {};
    data.forEach(m => (m.tags || []).forEach(t => (map[t] = (map[t] || 0) + 1)));
    return [["All", data.length], ...Object.entries(map).sort((a,b)=>b[1]-a[1])];
  }, [data]);

  const filtered = useMemo(() => {
    let list = filter === "All" ? data : data.filter(m => (m.tags || []).includes(filter));
    if (query.trim()) {
      const q = query.toLowerCase();
      list = list.filter(m =>
        m.title.toLowerCase().includes(q) ||
        m.author.toLowerCase().includes(q) ||
        m.desc.toLowerCase().includes(q) ||
        (m.tags || []).some(t => t.toLowerCase().includes(q))
      );
    }
    return list;
  }, [filter, query, data]);

  return (
    <>
      <Header theme={theme} setTheme={setTheme} lang={lang} setLang={setLang} mode={mode} setMode={setMode}/>

      <section className="container">
        <div className="mk-page-hero">
          <span className="eyebrow"><span className="dot"/> {trm("page_eyebrow", lang, mode)}</span>
          <h1>{trm("page_title", lang, mode)}</h1>
          <p>{trm("page_lead", lang, mode)}</p>
          <div className="mk-page-search">
            <I.search />
            <input
              type="text"
              placeholder={tr("search", lang)}
              value={query}
              onChange={(e) => setQuery(e.target.value)}
            />
            <span className="kbd">⌘K</span>
          </div>
        </div>
      </section>

      <div className="container">
        <div className="mk-page-layout">
          <aside className="mk-side">
            <div>
              <h4>{tr("categories", lang)}</h4>
              <div style={{display:"flex", flexDirection:"column", gap:2, marginTop:8}}>
                {cats.map(([name, n]) => (
                  <button
                    key={name}
                    type="button"
                    className={`side-cat ${filter === name ? "on" : ""}`}
                    onClick={() => setFilter(name)}
                  >
                    <I.layout width={14} height={14}/>
                    <span>{name === "All" ? tr("tag_all", lang) : name}</span>
                    <span className="count">{n}</span>
                  </button>
                ))}
              </div>
            </div>
          </aside>

          <div>
            <div style={{display:"flex", alignItems:"center", marginBottom:18, gap: 12}}>
              <span style={{fontSize:13, color:"hsl(var(--muted-foreground))"}}>
                {filtered.length} {filtered.length === 1 ? "section" : "sections"}{filter !== "All" ? ` · ${filter}` : ""}
              </span>
              <span className="chip" style={{marginLeft:"auto", color:"hsl(var(--primary))"}}>
                <I.trending /> Trending this week
              </span>
            </div>
            <div className="market-grid">
              {filtered.map(card => (
                <MarketCard key={card.id} card={card} onOpen={setOpen} lang={lang}/>
              ))}
            </div>
          </div>
        </div>
      </div>

      <section className="container">
        <InteractiveDemo key={mode} mode={mode} lang={lang}/>
      </section>

      {open && <SectionPreviewModal card={open} lang={lang} onClose={() => { setOpen(null); if (location.hash) history.replaceState(null,"",location.pathname); }}/>}
      <Footer lang={lang}/>
    </>
  );
}

function Footer({ lang }) {
  return (
    <footer className="foot">
      <div className="container">
        <div className="foot-grid">
          <div>
            <Brand />
            <p style={{ fontSize: 13, color: "hsl(var(--muted-foreground))", maxWidth: 320, marginTop: 16 }}>
              {tr("foot_tagline", lang)}
            </p>
          </div>
          <div className="foot-col">
            <h4>{tr("foot_product", lang)}</h4>
            <a href="Landing Page.html#assistant">{tr("nav_assistant", lang)}</a>
            <a href="Marketplace.html">{tr("nav_marketplace", lang)}</a>
            <a href="Landing Page.html#ecosystems">{tr("nav_ecosystems", lang)}</a>
            <a href="Landing Page.html#built-in">{tr("nav_builtin", lang)}</a>
            <a href="Landing Page.html#compare">{tr("nav_compare", lang)}</a>
          </div>
          <div className="foot-col">
            <h4>{tr("foot_build", lang)}</h4>
            <a href="#">Docs</a>
            <a href="#">Section spec</a>
            <a href="#">RLS policies</a>
            <a href="#">MCP guide</a>
            <a href="#">Changelog</a>
          </div>
          <div className="foot-col">
            <h4>{tr("foot_community", lang)}</h4>
            <a href="#">Leaderboard</a>
            <a href="#">Credits program</a>
            <a href="#">Forum</a>
            <a href="#">Discord</a>
          </div>
          <div className="foot-col">
            <h4>{tr("foot_company", lang)}</h4>
            <a href="#">About</a>
            <a href="#">Pricing</a>
            <a href="#">Security</a>
            <a href="#">Contact</a>
          </div>
        </div>
        <div className="foot-bottom">
          <span>© 2026 areti · Built on Next.js, Supabase, Trigger.dev, Kubernetes, Claude.</span>
          <span style={{display:"flex", alignItems:"center", gap:14}}>
            <a href="#" aria-label="GitHub"><I.github width={16} height={16}/></a>
            <a href="#">Status</a>
            <a href="#">Privacy</a>
            <a href="#">Terms</a>
          </span>
        </div>
      </div>
    </footer>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<MarketplacePage />);
