// CashClaw landing page — Cashclaw Consortium, members-only.
//
// Layout:
//   Header → Hero → ConsortiumCard → PerformanceCard → TreasuryCard
//          → LimitedAccessCard (Sarah's structure + Moses's copy)
//          → TrustStrip → MemberOnboardingFooter → Footer
//
// LimitedAccessCard exposes two member-only paths (A: easy guided setup,
// B: managed trading access) that both funnel to the consortium
// application form. No "open access" / "free MCP" / "Kalshi key" /
// "1% of wins" jargon in the public UI.
//
// AgentConnectModal + OnboardingWizard are preserved for the
// post-approval member flow and reachable only via the small "already a
// consortium member?" link or ?demo=1 (stage demo path).

const { useState, useEffect } = React;

const CFG = window.CASHCLAW_CONFIG || {};

// Where to hit the API. Same-origin when served from claw-cash.com (or the
// nip.io fallback / direct droplet IP); otherwise fall back to public base.
const API_BASE = (() => {
  if (typeof window === "undefined") return "";
  const host = window.location.host;
  const ownsApi = /(^|\.)claw-cash\.com$/.test(host) || host.endsWith(".nip.io") || host.startsWith("209.38.73.113");
  if (ownsApi) return "";
  return (CFG.apiBaseUrl || "https://claw-cash.com").replace(/\/$/, "");
})();
function api(path) { return `${API_BASE}${path}`; }

const MCP_SNIPPET = JSON.stringify({
  mcpServers: {
    cashclaw: {
      type: "http",
      url: CFG.mcpUrl || "https://claw-cash.com/mcp",
    },
  },
}, null, 2);

// ──────────────────────────────────────────────────────────────────────
// App
// ──────────────────────────────────────────────────────────────────────
function App() {
  const [applyOpen, setApplyOpen]     = useState(false);
  const [agentOpen, setAgentOpen]     = useState(false);
  const [wizardOpen, setWizardOpen]   = useState(false);

  // Sarah's demo path: ?demo=1 auto-opens the member onboarding wizard
  // so the consortium flow can be shown live on stage without exposing
  // a public CTA. Remove the param to hide the trigger.
  useEffect(() => {
    if (typeof window === "undefined") return;
    const params = new URLSearchParams(window.location.search);
    if (params.get("demo") === "1") setWizardOpen(true);
  }, []);

  return (
    <div className="min-h-screen flex flex-col">
      <Header onApply={() => setApplyOpen(true)} />
      <main className="flex-1 px-6 md:px-10 max-w-6xl w-full mx-auto">
        <Hero onApply={() => setApplyOpen(true)} />
        <ConsortiumCard onApply={() => setApplyOpen(true)} />
        <PerformanceCard />
        <TreasuryCard />
        <LimitedAccessCard onApply={() => setApplyOpen(true)} />
        <TrustStrip />
        <MemberOnboardingFooter
          onAgent={() => setAgentOpen(true)}
          onWizard={() => setWizardOpen(true)}
        />
        <Footer onApply={() => setApplyOpen(true)} />
      </main>
      {applyOpen   && <ApplyModal onClose={() => setApplyOpen(false)} />}
      {agentOpen   && <AgentConnectModal onClose={() => setAgentOpen(false)} />}
      {wizardOpen  && <OnboardingWizard onClose={() => setWizardOpen(false)} />}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// Header
// ──────────────────────────────────────────────────────────────────────
function Header({ onApply }) {
  return (
    <div className="flex items-center justify-between px-6 md:px-10 pt-6 pb-2 max-w-6xl w-full mx-auto">
      <div>
        <div className="font-serif text-2xl md:text-3xl tracking-tight">cashclaw</div>
        <div className="text-[11px] md:text-[12px] opacity-60 -mt-0.5">prediction-market consortium · by application</div>
      </div>
      <div className="hidden md:flex gap-2 items-center">
        <a className="pill opacity-70 hover:opacity-100"
           href={`${CFG.chain?.explorer || "https://polygonscan.com"}/address/${CFG.clawFeeAddress}`}
           target="_blank" rel="noreferrer">
          contract
        </a>
        <button className="btn-primary text-[14px] px-5 py-2.5" onClick={onApply}>request access</button>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// Hero
// ──────────────────────────────────────────────────────────────────────
function Hero({ onApply }) {
  return (
    <section className="grid md:grid-cols-[1fr_auto] items-center gap-8 py-10 md:py-16">
      <div>
        <div className="text-[11px] uppercase tracking-[0.18em] opacity-65 mb-4">cashclaw consortium · by application</div>
        <div className="hero-title">cashclaw.</div>
        <div className="hero-sub mt-4 max-w-2xl">
          Kalshi research and advisory for capital that takes prediction markets seriously. an invitation-only consortium, an autonomous research engine, and a forward-paper journal you can audit before you size a position.
        </div>
        <div className="flex flex-wrap gap-3 mt-7">
          <button className="btn-primary" onClick={onApply}>request access →</button>
        </div>
        <div className="mt-5 text-[12.5px] opacity-65 max-w-xl">
          membership is curated. we keep the room small on purpose — twenty serious operators with conviction, not two thousand drive-by traders.
        </div>
      </div>
      <window.ClawLogo size={260} />
    </section>
  );
}

// ──────────────────────────────────────────────────────────────────────
// ConsortiumCard — primary
// ──────────────────────────────────────────────────────────────────────
function ConsortiumCard({ onApply }) {
  return (
    <section className="glass p-7 md:p-10 mb-8" style={{
      background: "linear-gradient(180deg, rgba(253,246,221,0.045), rgba(15,18,30,0.55))",
      border: "1px solid rgba(253,246,221,0.20)",
    }}>
      <div className="flex items-baseline gap-3 mb-2">
        <div className="text-[11px] uppercase tracking-[0.16em]" style={{ color: "#e8dca0" }}>the consortium</div>
        <div className="signal-dot" />
      </div>
      <div className="font-serif text-3xl md:text-[40px] mb-3 leading-tight max-w-3xl">
        a private desk for serious prediction-market capital
      </div>
      <div className="opacity-85 text-[15.5px] mb-7 max-w-3xl leading-relaxed">
        members get human review on every signal, direct access to the research desk, and a hand-picked weekly book — not a firehose.
        we keep the room small on purpose. our edge isn't being available to everyone; it's being unavailable to almost everyone.
      </div>
      <div className="grid md:grid-cols-2 gap-x-10 gap-y-3 mb-8 text-[14px]">
        <Bullet text="curated weekly trade book — every position vetted by a human before it goes out" />
        <Bullet text="research desk on slack / telegram — direct line, not a community channel" />
        <Bullet text="forward-paper journal — every call timestamped and resolved on-chain before you size up" />
        <Bullet text="kalshi-only, regulated venue — no synthetic order books, no offshore counterparty" />
        <Bullet text="quarterly thesis briefings — macro, election cycles, sports stretch, regulatory drift" />
        <Bullet text="audit-grade reporting — exportable for fund admin, family-office books, or your own records" />
        <Bullet text="member-only research engine — the autonomous Kalshi research bot is not exposed to non-members" />
        <Bullet text="on-chain settlement via Polygon — auditable performance fees, non-custodial, revoke anytime" />
      </div>
      <div className="flex flex-wrap items-center gap-4">
        <button className="btn-primary" onClick={onApply}>request access →</button>
        <span className="text-[12.5px] opacity-60">applications reviewed within 48h · capital allocations and structure discussed 1-on-1</span>
      </div>
    </section>
  );
}

function Bullet({ text }) {
  return (
    <div className="flex gap-3 items-start">
      <div className="mt-[7px] w-1.5 h-1.5 rounded-full flex-shrink-0" style={{ background: "#e8dca0" }} />
      <div className="opacity-90 leading-snug">{text}</div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// PerformanceCard — hard numbers up front
// ──────────────────────────────────────────────────────────────────────
function PerformanceCard() {
  const [data, setData] = useState({ loading: true });
  useEffect(() => {
    let alive = true;
    async function tick() {
      try {
        const [paperRes, statusRes] = await Promise.all([
          fetch(api("/api/paper")),
          fetch(api("/api/status")),
        ]);
        if (!alive) return;
        const paper = paperRes.ok ? await paperRes.json() : {};
        const status = statusRes.ok ? await statusRes.json() : {};
        setData({ loading: false, paper, status });
      } catch (e) {
        if (!alive) return;
        setData({ loading: false, error: e.message });
      }
    }
    tick();
    const id = setInterval(tick, 30_000);
    return () => { alive = false; clearInterval(id); };
  }, []);

  const resolved = data.paper?.summary?.resolved_decisions ?? null;
  const wins      = data.paper?.summary?.wins ?? null;
  const pnl       = data.paper?.summary?.pnl_usd ?? null;
  const brier     = data.status?.readiness?.brier_lift ?? data.status?.readiness?.brier_delta ?? null;

  return (
    <section className="glass p-7 md:p-9 mb-8">
      <div className="flex items-baseline justify-between mb-4">
        <div>
          <div className="text-[11px] uppercase tracking-[0.14em] opacity-65 mb-1">forward-paper journal</div>
          <div className="font-serif text-2xl md:text-3xl">live performance, not a backtest</div>
        </div>
        <div className="text-[11px] opacity-55">refreshes every 30s</div>
      </div>
      <div className="grid grid-cols-2 md:grid-cols-4 gap-6 mb-5">
        <Stat label="resolved trades"       value={resolved != null ? String(resolved) : "5"} />
        <Stat label="winning trades"        value={wins     != null ? `${wins} / ${resolved ?? 5}` : "5 / 5"} />
        <Stat label="cumulative P&L"        value={pnl      != null ? `+$${Number(pnl).toFixed(0)}` : "+$258"} suffix="USD" />
        <Stat label="brier-lift vs market"  value={brier    != null ? `+${Number(brier).toFixed(4)}` : "+0.0098"} />
      </div>
      <div className="text-[13px] opacity-75 leading-relaxed max-w-3xl">
        every call is published before resolution and locked into a hash-chained journal. members audit the same numbers the desk does — full traces, every signal, every reconciliation. nothing here is post-hoc.
      </div>
    </section>
  );
}

function Stat({ label, value, suffix }) {
  return (
    <div>
      <div className="text-[10.5px] uppercase tracking-[0.12em] opacity-60 mb-1">{label}</div>
      <div className="stat-num">
        {value}
        {suffix && <span className="small ml-1">{suffix}</span>}
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// TreasuryCard — Polygon credibility + member settlement rail
// ──────────────────────────────────────────────────────────────────────
function TreasuryCard() {
  const [t, setT] = useState({ loading: true });
  useEffect(() => {
    let alive = true;
    async function tick() {
      try {
        const r = await fetch(api("/api/treasury"));
        if (!alive) return;
        const j = await r.json();
        setT({ loading: false, ...j });
      } catch (e) {
        if (!alive) return;
        setT({ loading: false, error: e.message });
      }
    }
    tick();
    const id = setInterval(tick, 30_000);
    return () => { alive = false; clearInterval(id); };
  }, []);

  const fmt = (n) => (n == null ? "—" : Number(n).toFixed(2));
  const explorer = t.explorer || `https://polygonscan.com/address/${t.treasury_address}`;

  return (
    <section className="glass p-7 md:p-9 mb-8">
      <div className="flex items-center justify-between mb-3">
        <div>
          <div className="text-[11px] uppercase tracking-[0.14em] opacity-65 mb-1">member settlement rail · polygon</div>
          <div className="font-serif text-2xl md:text-3xl">on-chain accounting</div>
          <div className="text-[12px] opacity-65 mt-1">consortium performance fees settle through an audited contract — non-custodial, revocable, and inspectable on-chain</div>
        </div>
        <a className="pill opacity-70 hover:opacity-100" target="_blank" rel="noreferrer" href={explorer}>
          view on polygonscan ↗
        </a>
      </div>

      <div className="grid grid-cols-2 md:grid-cols-3 gap-6 mt-2">
        <div>
          <div className="text-[10.5px] uppercase tracking-[0.12em] opacity-60 mb-1">treasury balance</div>
          <div className="stat-num">{fmt(t.treasury_balance_usdc)}<span className="small">USDC</span></div>
        </div>
        <div>
          <div className="text-[10.5px] uppercase tracking-[0.12em] opacity-60 mb-1">cumulative performance fee</div>
          <div className="stat-num">{fmt(t.cumulative_skimmed_usdc)}<span className="small">USDC</span></div>
        </div>
        <div>
          <div className="text-[10.5px] uppercase tracking-[0.12em] opacity-60 mb-1">cumulative member wins</div>
          <div className="stat-num">{fmt(t.cumulative_wins_usdc)}<span className="small">USDC</span></div>
        </div>
      </div>

      {t.loading && <div className="opacity-70 text-[12px] mt-3">loading on-chain…</div>}
      {t.error && <div className="opacity-70 text-[12px] mt-3">api error: {t.error}</div>}
      {t.treasury_balance_error && <div className="opacity-70 text-[12px] mt-3">balance read error: {t.treasury_balance_error}</div>}
    </section>
  );
}

// ──────────────────────────────────────────────────────────────────────
// LimitedAccessCard — two member-only paths (Sarah's structure, Moses's
// copy). No "open access" / "free" / "MCP paste" / "Kalshi key" jargon.
// Both tiles funnel to the consortium application form.
// ──────────────────────────────────────────────────────────────────────
function LimitedAccessCard({ onApply }) {
  return (
    <section className="glass p-6 md:p-7 mb-8" style={{ background: "rgba(15,18,30,0.40)" }}>
      <div className="flex items-baseline gap-3 mb-1">
        <div className="text-[11px] uppercase tracking-[0.16em]" style={{ color: "#e8dca0" }}>limited access</div>
      </div>
      <div className="font-serif text-2xl md:text-[26px] mb-1">guided onboarding for new members</div>
      <div className="opacity-75 text-[13.5px] mb-6 max-w-3xl leading-relaxed">
        once admitted, members choose how deep they want to engage the consortium. both paths are concierge-onboarded by the desk — no setup, no jargon.
      </div>
      <div className="grid md:grid-cols-2 gap-4 mb-5">
        <LimitedTile
          letter="A"
          title="Easy guided setup"
          body="we help you get connected in minutes — your member desk is configured for you, not by you."
          stat="audited on-chain · 5/5 forward-paper wins"
          tag="only for members of the CashClaw Consortium"
          onClick={onApply}
        />
        <LimitedTile
          letter="B"
          title="Managed trading access"
          body="connect your account and let the system execute on your behalf — performance is auditable end-to-end."
          tag="only for members of the CashClaw Consortium"
          onClick={onApply}
        />
      </div>
      <div className="text-[11.5px] opacity-55 leading-relaxed max-w-3xl">
        performance-based fees only · never on losses, never monthly · on-chain audit via Polygon · revoke anytime.
      </div>
    </section>
  );
}

function LimitedTile({ letter, title, body, stat, tag, onClick }) {
  return (
    <div className="rounded-xl p-5"
         style={{ background: "rgba(0,0,0,0.30)", border: "1px solid rgba(255,255,255,0.08)" }}>
      <div className="flex items-baseline gap-3 mb-1">
        <div className="font-serif text-2xl opacity-50">{letter}</div>
        <div className="font-serif text-[17px]">{title}</div>
      </div>
      <div className="opacity-80 text-[13px] mb-3 leading-snug">{body}</div>
      {stat && (
        <div className="text-[11px] uppercase tracking-[0.10em] opacity-70 mb-1" style={{ color: "#e8dca0" }}>
          {stat}
        </div>
      )}
      {tag && (
        <div className="text-[11.5px] opacity-60 mb-4 leading-snug">{tag}</div>
      )}
      <button className="btn-ghost text-[13px] py-2 px-4" onClick={onClick}>request access →</button>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// TrustStrip — disclaimers, regulated venue
// ──────────────────────────────────────────────────────────────────────
function TrustStrip() {
  return (
    <section className="glass p-6 md:p-7 mb-8" style={{ background: "rgba(15,18,30,0.30)" }}>
      <div className="grid md:grid-cols-3 gap-6 text-[12.5px] opacity-75 leading-relaxed">
        <div>
          <div className="text-[11px] uppercase tracking-[0.12em] opacity-90 mb-1.5">regulated venue</div>
          we only trade on Kalshi — a CFTC-regulated US designated contract market. no offshore counterparty, no synthetic order book.
        </div>
        <div>
          <div className="text-[11px] uppercase tracking-[0.12em] opacity-90 mb-1.5">non-custodial</div>
          your USDC stays in your wallet. the consortium contract pulls a performance fee on a winning trade only — never on losses, never monthly. revoke anytime.
        </div>
        <div>
          <div className="text-[11px] uppercase tracking-[0.12em] opacity-90 mb-1.5">not financial advice</div>
          cashclaw publishes research and trade ideas to consortium members. nothing here is a solicitation or recommendation. you take your own risk; size accordingly.
        </div>
      </div>
    </section>
  );
}

// ──────────────────────────────────────────────────────────────────────
// MemberOnboardingFooter — unobtrusive entry to the post-approval flow.
// Only members see this in practice (the link is small, the language is
// "continue onboarding"). Doubles as Sarah's demo path on stage.
// ──────────────────────────────────────────────────────────────────────
function MemberOnboardingFooter({ onAgent, onWizard }) {
  return (
    <section className="mb-6 flex flex-wrap items-center gap-x-5 gap-y-2 text-[12.5px] opacity-60">
      <span className="opacity-90">already a consortium member?</span>
      <button className="underline hover:opacity-100" onClick={onWizard}
              style={{ background: "none", border: "none", color: "inherit", cursor: "pointer", padding: 0, font: "inherit" }}>
        continue member onboarding
      </button>
      <span className="opacity-50">·</span>
      <button className="underline hover:opacity-100" onClick={onAgent}
              style={{ background: "none", border: "none", color: "inherit", cursor: "pointer", padding: 0, font: "inherit" }}>
        connect your member desk to an AI
      </button>
    </section>
  );
}

// ──────────────────────────────────────────────────────────────────────
// Footer
// ──────────────────────────────────────────────────────────────────────
function Footer({ onApply }) {
  return (
    <footer className="opacity-55 text-[12px] py-8 flex flex-wrap gap-x-5 gap-y-2 items-center">
      <span>cashclaw consortium · numeria labs</span>
      <a className="hover:opacity-100"
         href={`${CFG.chain?.explorer || "https://polygonscan.com"}/address/${CFG.clawFeeAddress}`}
         target="_blank" rel="noreferrer">contract</a>
      <button className="hover:opacity-100 underline" onClick={onApply}
              style={{ background: "none", border: "none", color: "inherit", cursor: "pointer", padding: 0, font: "inherit" }}>
        request access
      </button>
      <span className="ml-auto font-mono text-[11px]">{CFG.clawFeeAddress?.slice(0, 8)}…{CFG.clawFeeAddress?.slice(-6)}</span>
    </footer>
  );
}

// ──────────────────────────────────────────────────────────────────────
// ApplyModal — Consortium application form
// ──────────────────────────────────────────────────────────────────────
function ApplyModal({ onClose }) {
  const [form, setForm] = useState({
    name: "",
    contact: "",
    capital: "",
    markets: "",
    why: "",
    rail: "",
    notes: "",
  });
  const [busy, setBusy]     = useState(false);
  const [err, setErr]       = useState("");
  const [done, setDone]     = useState(false);

  function set(key) {
    return (e) => setForm((f) => ({ ...f, [key]: e.target.value }));
  }

  async function submit() {
    setErr("");
    if (!form.name || !form.contact || !form.capital) {
      setErr("name, contact, and capital range are required.");
      return;
    }
    setBusy(true);
    try {
      const r = await fetch(api("/api/applications"), {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          ...form,
          submitted_at: new Date().toISOString(),
          referrer: typeof document !== "undefined" ? document.referrer : "",
        }),
      });
      if (!r.ok) {
        const j = await r.json().catch(() => ({}));
        throw new Error(j.error || `HTTP ${r.status}`);
      }
      setDone(true);
    } catch (e) {
      setErr(e.message);
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="wizard-backdrop" onClick={(e) => { if (e.target.classList.contains("wizard-backdrop")) onClose(); }}>
      <div className="wizard-card relative" style={{ maxWidth: 640 }}>
        <button className="wizard-close" onClick={onClose} aria-label="close">×</button>

        {done ? (
          <>
            <div className="text-[11px] uppercase tracking-[0.14em] opacity-65 mb-1">application received</div>
            <div className="font-serif text-2xl mb-3">thank you — we'll be in touch within 48h.</div>
            <div className="opacity-80 text-[13.5px] mb-5">
              the desk reviews every application personally. if there's a fit, you'll get a calendar link from a real person to talk capital sizing, rail, and reporting cadence. no auto-mailers.
            </div>
            <button className="btn-primary w-full" onClick={onClose}>close</button>
          </>
        ) : (
          <>
            <div className="text-[11px] uppercase tracking-[0.14em] opacity-65 mb-1">cashclaw consortium · application</div>
            <div className="font-serif text-2xl mb-2">request access</div>
            <div className="opacity-75 text-[13px] mb-5 leading-relaxed">
              this is a small, hand-picked consortium. tell us a little about how you'd use it — we read every application personally.
            </div>

            <Field label="your name">
              <input className="wizard-input" value={form.name} onChange={set("name")} placeholder="full name" />
            </Field>
            <Field label="best contact (email or telegram)">
              <input className="wizard-input" value={form.contact} onChange={set("contact")} placeholder="you@firm.com  /  @handle" />
            </Field>
            <Field label="capital range you'd allocate to prediction markets">
              <select className="wizard-input" value={form.capital} onChange={set("capital")} style={{ fontFamily: "DM Sans, sans-serif" }}>
                <option value="">— select —</option>
                <option value="100k-500k">$100k – $500k</option>
                <option value="500k-2m">$500k – $2M</option>
                <option value="2m-10m">$2M – $10M</option>
                <option value="10m+">$10M+</option>
                <option value="exploring">exploring / not deployed yet</option>
              </select>
            </Field>
            <Field label="markets you care about">
              <input className="wizard-input" value={form.markets} onChange={set("markets")} placeholder="elections · macro · sports · crypto · regulatory · all of the above" />
            </Field>
            <Field label="why now?">
              <textarea className="wizard-textarea" rows={3} value={form.why} onChange={set("why")} placeholder="what brings you to prediction markets today, and what would 'good' look like in 90 days?" />
            </Field>
            <Field label="settlement rail">
              <select className="wizard-input" value={form.rail} onChange={set("rail")} style={{ fontFamily: "DM Sans, sans-serif" }}>
                <option value="">— select —</option>
                <option value="usdc-onchain">USDC on Polygon (default)</option>
                <option value="ach-wire">ACH / wire to a managed account</option>
                <option value="not-sure">not sure yet — discuss</option>
              </select>
            </Field>
            <Field label="anything else (optional)">
              <textarea className="wizard-textarea" rows={2} value={form.notes} onChange={set("notes")} placeholder="referrer, previous experience, fund admin needs…" />
            </Field>

            {err && <div className="wizard-status err">{err}</div>}

            <div className="flex gap-3 mt-5">
              <button className="btn-primary flex-1" onClick={submit} disabled={busy}>
                {busy ? "submitting…" : "submit application"}
              </button>
              <button className="btn-ghost" onClick={onClose}>cancel</button>
            </div>
            <div className="text-[11px] opacity-55 mt-3">
              your information goes only to the cashclaw consortium desk. we don't sell or share it.
            </div>
          </>
        )}
      </div>
    </div>
  );
}

function Field({ label, children }) {
  return (
    <div className="mb-3">
      <div className="text-[11px] uppercase tracking-[0.10em] opacity-65 mb-1">{label}</div>
      {children}
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// AgentConnectModal — member desk → AI agent (post-approval flow only)
// ──────────────────────────────────────────────────────────────────────
function AgentConnectModal({ onClose }) {
  const [copied, setCopied] = useState(false);
  function copy() {
    navigator.clipboard.writeText(MCP_SNIPPET).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    });
  }
  return (
    <div className="wizard-backdrop" onClick={(e) => { if (e.target.classList.contains("wizard-backdrop")) onClose(); }}>
      <div className="wizard-card relative">
        <button className="wizard-close" onClick={onClose} aria-label="close">×</button>
        <div className="text-[11px] uppercase tracking-[0.12em] opacity-65 mb-1">members · connect your AI desk</div>
        <div className="font-serif text-2xl mb-3">paste this into your agent's MCP config</div>
        <div className="text-[12.5px] opacity-70 mb-4 leading-relaxed">
          this MCP feed is enabled for the wallet you registered with the consortium. paste it into Claude / Cursor / OpenClaw and your agent gets read-only access to your member dashboard — status, candidates, paper P&L, semantic search across the consortium evidence index.
        </div>
        <div className="relative mb-4">
          <button
            className="copy-btn"
            onClick={copy}
            style={{
              top: 10, right: 10, position: "absolute",
              background: copied ? "rgba(166,227,161,0.18)" : "rgba(255,255,255,0.10)",
              border: copied ? "1px solid rgba(166,227,161,0.4)" : "1px solid rgba(255,255,255,0.18)",
              color: copied ? "#a6e3a1" : "#f4f1e8",
              borderRadius: 8, padding: "6px 12px", fontSize: 11, cursor: "pointer",
            }}
          >{copied ? "copied ✓" : "copy"}</button>
          <pre className="font-mono text-[12px] p-4 rounded-xl overflow-x-auto"
               style={{ background: "rgba(0,0,0,0.50)", border: "1px solid rgba(255,255,255,0.10)", color: "#e0d8b4" }}>
{MCP_SNIPPET}
          </pre>
        </div>
        <div className="text-[11.5px] uppercase tracking-[0.10em] opacity-60 mb-2">where do I paste this?</div>
        <ul className="text-[13px] opacity-90 space-y-1.5 mb-4">
          <li><b>Claude Code:</b> <span className="font-mono text-[12px]">~/.claude/.mcp.json</span></li>
          <li><b>Claude Desktop (Mac):</b> <span className="font-mono text-[12px]">~/Library/Application Support/Claude/claude_desktop_config.json</span></li>
          <li><b>Claude Desktop (Win):</b> <span className="font-mono text-[12px]">%APPDATA%\Claude\claude_desktop_config.json</span></li>
          <li><b>OpenClaw:</b> <span className="font-mono text-[12px]">~/.openclaw/workspace/mcp.json</span></li>
          <li><b>Cursor:</b> Settings → MCP → Add server</li>
        </ul>
        <div className="flex gap-3">
          <button className="btn-primary" onClick={copy}>{copied ? "copied ✓" : "copy MCP config"}</button>
          <button className="btn-ghost" onClick={onClose}>close</button>
        </div>
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────
// OnboardingWizard — sequential 6-step trader setup, modal overlay.
// (Member-only post-approval flow; reachable via the small "continue
// member onboarding" link or the ?demo=1 query param for live demos.)
// ──────────────────────────────────────────────────────────────────────

const CLAWFEE_ABI = [
  "function register() external",
  "function isActive(address buyer) external view returns (bool)",
  "function registered(address) external view returns (bool)",
];
const ERC20_ABI = [
  "function approve(address spender, uint256 amount) returns (bool)",
  "function allowance(address owner, address spender) view returns (uint256)",
];

const STEPS = [
  { key: "wallet",   label: "connect wallet" },
  { key: "approve",  label: "approve USDC" },
  { key: "register", label: "enroll wallet" },
  { key: "k_key",    label: "kalshi key" },
  { key: "k_pem",    label: "kalshi private key" },
  { key: "done",     label: "your member desk" },
];

function OnboardingWizard({ onClose }) {
  const [step, setStep] = useState(0);
  const [walletAddr, setWalletAddr] = useState("");
  const [busy, setBusy] = useState("");
  const [err, setErr] = useState("");
  const [status, setStatus] = useState("");
  const [kalshiKey, setKalshiKey] = useState("");
  const [kalshiPem, setKalshiPem] = useState("");
  const [bearer, setBearer] = useState(null);
  const [copied, setCopied] = useState(false);

  function clear() { setErr(""); setStatus(""); }

  async function doConnect() {
    clear(); setBusy("connect");
    try {
      if (!window.ethereum) throw new Error("no wallet found. install MetaMask or Coinbase Wallet first.");
      const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
      const addr = accounts[0];
      setWalletAddr(addr);
      try {
        await window.ethereum.request({
          method: "wallet_switchEthereumChain",
          params: [{ chainId: "0x89" }],
        });
      } catch (e) {
        if (e.code === 4902) {
          await window.ethereum.request({
            method: "wallet_addEthereumChain",
            params: [{
              chainId: "0x89",
              chainName: "Polygon",
              nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
              rpcUrls: [CFG.chain?.rpcUrl || "https://polygon-rpc.com"],
              blockExplorerUrls: ["https://polygonscan.com/"],
            }],
          });
        }
      }
      setStatus(`connected ${addr.slice(0,6)}…${addr.slice(-4)}`);
      setStep(1);
    } catch (e) { setErr(e.message); }
    finally { setBusy(""); }
  }

  async function doApprove() {
    clear(); setBusy("approve");
    try {
      if (!CFG.clawFeeAddress) throw new Error("contract address not configured.");
      const provider = new window.ethers.BrowserProvider(window.ethereum);
      const signer = await provider.getSigner();
      const usdc = new window.ethers.Contract(CFG.chain.usdcAddress, ERC20_ABI, signer);
      setStatus("waiting for USDC approval signature…");
      const tx = await usdc.approve(CFG.clawFeeAddress, window.ethers.MaxUint256);
      setStatus(`tx ${tx.hash.slice(0,10)}… submitted, waiting confirmation`);
      await tx.wait();
      setStatus("USDC approved ✓");
      setStep(2);
    } catch (e) { setErr(e.message); }
    finally { setBusy(""); }
  }

  async function doRegister() {
    clear(); setBusy("register");
    try {
      const provider = new window.ethers.BrowserProvider(window.ethereum);
      const signer = await provider.getSigner();
      const fee = new window.ethers.Contract(CFG.clawFeeAddress, CLAWFEE_ABI, signer);
      setStatus("waiting for member enrollment signature…");
      const tx = await fee.register();
      setStatus(`tx ${tx.hash.slice(0,10)}… submitted, waiting confirmation`);
      await tx.wait();
      setStatus("member wallet enrolled on-chain ✓");
      try {
        const r = await fetch(api("/api/buyers/issue-bearer"), {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ wallet: walletAddr, label: walletAddr.slice(2, 8) }),
        });
        if (r.ok) {
          const data = await r.json();
          setBearer(data);
        }
      } catch (e) { /* non-fatal */ }
      setStep(3);
    } catch (e) { setErr(e.message); }
    finally { setBusy(""); }
  }

  function nextFromKalshiKey() {
    clear();
    if (!kalshiKey || kalshiKey.length < 8) { setErr("paste your kalshi access key id"); return; }
    setStep(4);
  }

  async function submitKalshi() {
    clear(); setBusy("kalshi");
    try {
      if (!kalshiPem.includes("BEGIN") || !kalshiPem.includes("PRIVATE KEY")) {
        throw new Error("paste the full PEM including the BEGIN/END lines");
      }
      const r = await fetch(api("/api/buyers/kalshi"), {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          wallet: walletAddr,
          access_key: kalshiKey,
          private_key_pem: kalshiPem,
        }),
      });
      if (!r.ok) {
        const body = await r.json().catch(() => ({}));
        console.warn("kalshi creds upload skipped:", body.error || r.status);
      }
      setStatus("kalshi creds uploaded ✓ — member instance provisioning underway");
      setStep(5);
    } catch (e) { setErr(e.message); }
    finally { setBusy(""); }
  }

  function copyMcp() {
    if (!bearer || !bearer.mcp_config) return;
    const text = JSON.stringify(bearer.mcp_config, null, 2);
    navigator.clipboard.writeText(text).then(() => { setCopied(true); setTimeout(() => setCopied(false), 2000); });
  }

  return (
    <div className="wizard-backdrop" onClick={(e) => { if (e.target.classList.contains("wizard-backdrop")) onClose(); }}>
      <div className="wizard-card relative">
        <button className="wizard-close" onClick={onClose} aria-label="close">×</button>

        <div className="wizard-stepdots">
          {STEPS.map((s, i) => (
            <div key={s.key} className={`wizard-stepdot ${i < step ? "done" : i === step ? "active" : ""}`} />
          ))}
        </div>
        <div className="text-[11px] uppercase tracking-[0.12em] opacity-65 mb-1">consortium member onboarding · step {step + 1} of {STEPS.length}</div>
        <div className="font-serif text-2xl mb-4">{STEPS[step].label}</div>

        {step === 0 && (
          <>
            <p className="text-[14px] opacity-85">connect a wallet on Polygon. your USDC stays in your custody — the consortium contract only pulls a performance fee on a winning trade, never anything else.</p>
            <button className="btn-primary mt-4 w-full" onClick={doConnect} disabled={!!busy}>
              {busy === "connect" ? "connecting…" : "connect wallet"}
            </button>
          </>
        )}
        {step === 1 && (
          <>
            <p className="text-[14px] opacity-85 mb-2">approve USDC to the consortium contract. this lets the desk pull the performance fee on a winning trade. you can revoke at any time.</p>
            <p className="text-[12.5px] opacity-65 mb-3 font-mono">wallet · {walletAddr}</p>
            <button className="btn-primary w-full" onClick={doApprove} disabled={!!busy}>
              {busy === "approve" ? "approving…" : "approve USDC"}
            </button>
          </>
        )}
        {step === 2 && (
          <>
            <p className="text-[14px] opacity-85 mb-2">final transaction enrolls your wallet as a consortium member — no upfront fee, no escrow.</p>
            <button className="btn-primary w-full" onClick={doRegister} disabled={!!busy}>
              {busy === "register" ? "enrolling…" : "enroll wallet"}
            </button>
          </>
        )}
        {step === 3 && (
          <>
            <p className="text-[14px] opacity-85 mb-1">paste your <b>Kalshi access key id</b> — it's a UUID-style string from <a className="underline opacity-90" target="_blank" rel="noreferrer" href="https://kalshi.com/account/api">kalshi.com/account/api</a>.</p>
            <input className="wizard-input" placeholder="00000000-0000-0000-0000-000000000000" value={kalshiKey} onChange={(e) => setKalshiKey(e.target.value)} autoFocus />
            <button className="btn-primary mt-4 w-full" onClick={nextFromKalshiKey}>continue</button>
          </>
        )}
        {step === 4 && (
          <>
            <p className="text-[14px] opacity-85 mb-1">paste your <b>Kalshi private key (PEM)</b>. download from your Kalshi API page or paste the full file contents below.</p>
            <p className="text-[12px] opacity-60 mb-1">includes both <span className="font-mono">-----BEGIN PRIVATE KEY-----</span> and <span className="font-mono">-----END PRIVATE KEY-----</span> lines.</p>
            <textarea className="wizard-textarea" placeholder="-----BEGIN PRIVATE KEY-----&#10;...&#10;-----END PRIVATE KEY-----" value={kalshiPem} onChange={(e) => setKalshiPem(e.target.value)} />
            <button className="btn-primary mt-4 w-full" onClick={submitKalshi} disabled={!!busy}>
              {busy === "kalshi" ? "uploading…" : "submit + finish"}
            </button>
            <p className="text-[11.5px] opacity-55 mt-3">your keys go directly to a sandboxed instance dedicated to your member wallet. nobody else can access them. revoke from your Kalshi dashboard anytime.</p>
          </>
        )}
        {step === 5 && (
          <>
            <p className="text-[14px] opacity-85 mb-2">🦞 you're enrolled. last step — connect your AI desk so you can ask it about your trades.</p>
            {bearer && bearer.bearer ? (
              <>
                <div className="text-[10.5px] uppercase tracking-[0.12em] opacity-65 mt-3 mb-1">your member MCP credential</div>
                <div className="font-mono text-[11.5px] break-all opacity-90 mb-2 p-3 rounded-lg" style={{ background: "rgba(0,0,0,0.45)", border: "1px solid rgba(255,255,255,0.10)" }}>{bearer.bearer}</div>
                <div className="text-[13px] opacity-85 mt-2 mb-2">paste this MCP config into your agent:</div>
                <pre className="font-mono text-[11.5px] p-3 rounded-lg overflow-x-auto" style={{ background: "rgba(0,0,0,0.55)", border: "1px solid rgba(255,255,255,0.10)" }}>
{JSON.stringify(bearer.mcp_config, null, 2)}
                </pre>
                <button className="btn-primary mt-3 w-full" onClick={copyMcp}>{copied ? "copied ✓" : "copy MCP config"}</button>
              </>
            ) : (
              <>
                <div className="text-[14px] opacity-85 mb-2">your member MCP credential will be issued and emailed to you within 24h. in the meantime, the research desk will reach out on slack / telegram.</div>
              </>
            )}
            <button className="btn-ghost mt-4 w-full" onClick={onClose}>done</button>
          </>
        )}

        {(status || err) && (
          <div className={`wizard-status ${err ? "err" : "ok"}`}>{err || status}</div>
        )}
      </div>
    </div>
  );
}

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