/* Stratum Leads — Operations Console. App shell: routing, lifted state, and
   the single audit-log / toast pipeline every page's actions flow through.
   Auctions intentionally keeps its own local state (see ops-auctions.jsx)
   so its live simulation resets on navigation — everything else here is the
   durable session state for this console. */

const SOD = window.STRATUM_OPS;
const { OpsSidebar, OpsTopbar, ToastStack, ProfileDrawer, fmtStrata, getCustomer, I, Spinner } = window.OpsShared;
const { Button, Field, Logo } = window.StratumLeadsDesignSystem_6367ed;

/* Phase 2 live wiring: window.USE_LIVE + a Supabase client (config.js) put the
   console in live mode; otherwise it stays fully mock (offline). This first live
   slice wires the Lead Review surface to the admin_review_queue() RPC (0041). */
const OPS_LIVE = !!(window.USE_LIVE && window.__sb);

/* admin_review_queue() row → the LeadOpsPage lead shape the mock UI already renders. */
const mapReviewRow = (r) => ({
  id: r.lead_ext_id, address: r.address, cityZip: r.city, county: r.county,
  tier: r.tier, trigger: r.trigger, score: r.lead_score, quality: r.quality,
  equityPct: r.equity_pct, estValue: r.est_value_usd, startingBid: r.starting_bid_strata,
  status: r.review_status, submittedAt: r.submitted_at ? new Date(r.submitted_at).toLocaleString() : "—",
  owners: r.owners || [], source: "DC Property & Ownership Export"
});

const EMPTY_ENRICH = { model: "contact resolution v2 — verify on ≥2 independent sources", lastRun: { targeted: 0, resolved: 0, verified: 0, suppressed: 0 }, sources: [], runs: [], leads: [] };

/* admin_enrichment_rows() flat rows (+ enrichment_runs) → the LeadEnrichPage shape:
   group by lead → owner-contact (person,kind,value), collect evidence sourceRefs,
   compute corroboration/band/status, and per-source queen diagnostics. */
function buildLiveEnrichment(rows, runs) {
  const leadsMap = {}, bySource = {};
  for (const r of rows) {
    const L = leadsMap[r.lead_ext_id] || (leadsMap[r.lead_ext_id] = { leadId: r.lead_ext_id, address: r.address, cityZip: r.city, tier: r.tier, owners: new Set(), _c: {} });
    if (r.owner_name) L.owners.add(r.owner_name);
    const key = r.person_id + "|" + r.kind + "|" + r.value;
    const c = L._c[key] || (L._c[key] = { id: key, ownerName: r.owner_name, type: r.kind, masked: r.value, confidence: 0, status: "unverified", suppressReason: null, _src: new Set(), sourceRefs: [] });
    c.confidence = Math.max(c.confidence, r.confidence || 0);
    c._src.add(r.source_key);
    c.sourceRefs.push({ source: r.source_key, id: r.source_key, at: r.at ? new Date(r.at).toLocaleString() : "", returned: r.value });
    if (r.status === "suppressed") {c.status = "suppressed";c.suppressReason = r.suppress_reason;} else if (r.status === "verified") c.status = "verified";
    const s = bySource[r.source_key] || (bySource[r.source_key] = { id: r.source_key, name: r.source_key, kind: r.kind, hits: 0, corr: 0, confSum: 0 });
    s.hits++;s.confSum += r.confidence || 0;if (r.status === "verified") s.corr++;
  }
  const leads = Object.values(leadsMap).map((L) => {
    const contacts = Object.values(L._c).map((c) => ({ id: c.id, ownerName: c.ownerName, type: c.type, masked: c.masked, confidence: c.confidence, band: c.confidence >= 80 ? "High" : c.confidence >= 60 ? "Medium" : "Low", corroboration: c._src.size, status: c.status, suppressReason: c.suppressReason, sourceRefs: c.sourceRefs }));
    const liveC = contacts.filter((c) => c.status !== "suppressed");
    return { leadId: L.leadId, address: L.address, cityZip: L.cityZip, tier: L.tier, owners: [...L.owners], contacts, resolvedCount: liveC.length, verifiedCount: contacts.filter((c) => c.status === "verified").length, suppressedCount: contacts.filter((c) => c.status === "suppressed").length, bestConfidence: liveC.reduce((m, c) => Math.max(m, c.confidence), 0) };
  });
  const sources = Object.values(bySource).map((s) => ({ id: s.id, name: s.name, kind: s.kind, attempts: s.hits, hits: s.hits, hitRate: 100, corroborationRate: s.hits ? Math.round(s.corr / s.hits * 100) : 0, avgConfidence: s.hits ? Math.round(s.confSum / s.hits) : 0, costPerHit: 0, queen: false }));
  if (sources.length) sources.slice().sort((a, b) => b.corroborationRate - a.corroborationRate)[0].queen = true;
  const resolvedTotal = leads.reduce((a, l) => a + l.resolvedCount, 0);
  const verifiedTotal = leads.reduce((a, l) => a + l.verifiedCount, 0);
  const suppressedTotal = leads.reduce((a, l) => a + l.suppressedCount, 0);
  const runsMapped = (runs || []).map((r) => ({ id: r.id, at: r.started_at ? new Date(r.started_at).toLocaleString() : "—", targeted: r.found, resolved: r.enriched, verified: verifiedTotal, suppressed: r.suppressed, costUsd: Number(r.cost_usd || 0) }));
  const lr = { at: runs && runs[0] ? new Date(runs[0].started_at).toLocaleString() : "—", durationLabel: "—", targeted: runs && runs[0] ? runs[0].found : leads.length, resolved: resolvedTotal, verified: verifiedTotal, suppressed: suppressedTotal };
  return { model: "contact resolution v2 — verify on ≥2 independent sources", lastRun: lr, sources, runs: runsMapped, leads };
}
const { HomePage, AuditLogPage } = window.OpsHome;
const { TicketsPage, NewTicketDrawer } = window.OpsTickets;
const { CustomersPage, AdjustWalletDrawer } = window.OpsCustomers;
const { LeadOpsPage } = window.OpsLeadOps;
const { LeadIntelPage } = window.OpsIntel;
const { LeadEnrichPage } = window.OpsEnrich;
const { SourcePlaybooksPage } = window.OpsPlaybooks;
const { PublishingQueuePage } = window.OpsPublishing;
const { SystemHealthPage } = window.OpsHealth;
const { GateReviewPage } = window.OpsGovernance;
const { AuctionsPage } = window.OpsAuctions;
const { WalletOpsPage } = window.OpsWalletOps;

const clone = (x) => JSON.parse(JSON.stringify(x));

function App({ live }) {
  const [route, setRoute] = React.useState("home");
  const [customers, setCustomers] = React.useState(() => clone(SOD.CUSTOMERS));
  const [tickets, setTickets] = React.useState(() => clone(SOD.TICKETS));
  const [ledger, setLedger] = React.useState(() => clone(SOD.LEDGER));
  const [leadQueue, setLeadQueue] = React.useState(() => clone(SOD.LEAD_QUEUE));
  const [liveQueue, setLiveQueue] = React.useState(null);   // Lead Review, live from admin_review_queue()
  const [liveEnrichment, setLiveEnrichment] = React.useState(null); // Lead Enrichment, live from admin_enrichment_rows()
  const [auditLog, setAuditLog] = React.useState(() => clone(SOD.AUDIT_LOG));
  const [selectedTicketId, setSelectedTicketId] = React.useState(null);
  const [selectedCustomerId, setSelectedCustomerId] = React.useState(null);
  const [selectedLeadId, setSelectedLeadId] = React.useState(null);
  const [adjustCtx, setAdjustCtx] = React.useState(null);
  const [showNewTicket, setShowNewTicket] = React.useState(false);
  const [profile, setProfile] = React.useState(() => ({ ...SOD.AGENT }));
  const [showProfile, setShowProfile] = React.useState(false);
  const [toasts, setToasts] = React.useState([]);

  const showToast = (tone, title, message) => {
    const id = "t" + Date.now() + Math.random();
    setToasts((prev) => [...prev, { id, tone, title, message }]);
    setTimeout(() => setToasts((prev) => prev.filter((t) => t.id !== id)), 3800);
  };
  const dismissToast = (id) => setToasts((prev) => prev.filter((t) => t.id !== id));
  const logAudit = (category, action, target, targetId) =>
  setAuditLog((prev) => [{ id: "AL-live-" + Date.now(), time: "Just now", actor: profile.name, category, action, target, targetId }, ...prev]);

  /* ---- live Lead Review (Phase 2): read the intake queue from admin_review_queue() ---- */
  const refetchQueue = () => {
    if (!live) return;
    window.__sb.rpc("admin_review_queue").then(({ data, error }) => {
      if (error) {showToast("danger", "Live queue error", error.message);return;}
      setLiveQueue((data || []).map(mapReviewRow));
    });
  };
  React.useEffect(() => {if (live) refetchQueue();}, [live]);

  /* ---- live Lead Enrichment (Phase 2): read contact_evidence via admin_enrichment_rows() ---- */
  const refetchEnrichment = () => {
    if (!live) return;
    Promise.all([
      window.__sb.rpc("admin_enrichment_rows"),
      window.__sb.from("enrichment_runs").select("id,started_at,found,enriched,suppressed,cost_usd").order("started_at", { ascending: false }).limit(5)]
    ).then(([r1, r2]) => {
      if (r1.error) {showToast("danger", "Enrichment load error", r1.error.message);return;}
      setLiveEnrichment(buildLiveEnrichment(r1.data || [], r2 && r2.data || []));
    });
  };
  React.useEffect(() => {if (live) refetchEnrichment();}, [live]);

  /* ---- live Source Playbooks + localities (Phase 2, #4/#5): CRUD via admin RPCs ---- */
  const [livePlaybooks, setLivePlaybooks] = React.useState(null);
  const [liveLocalities, setLiveLocalities] = React.useState(null);
  const [locality, setLocality] = React.useState("dc");   // global locality filter (topbar); one locality for now
  React.useEffect(() => {
    if (live && liveLocalities && liveLocalities.length) {const dc = liveLocalities.find((l) => l.state === "DC") || liveLocalities[0];setLocality(dc.id);}
  }, [live, liveLocalities]);
  const refetchPlaybooks = () => {
    if (!live) return;
    Promise.all([
      window.__sb.from("source_playbooks").select("*").order("name"),
      window.__sb.from("localities").select("*").eq("active", true).order("display_name")]
    ).then(([p, l]) => {
      if (p.error) {showToast("danger", "Playbooks load error", p.error.message);return;}
      setLivePlaybooks(p.data || []);setLiveLocalities(l && l.data || []);
    });
  };
  React.useEffect(() => {if (live) refetchPlaybooks();}, [live]);

  const savePlaybook = (pb) => window.__sb.rpc("admin_upsert_playbook", { p: pb }).then(({ data, error }) => {
    if (error || data && data.status !== "ok") {showToast("danger", "Save failed", error && error.message || data && data.message || data && data.status);return;}
    showToast("success", "Playbook saved", pb.name || pb.source_key);refetchPlaybooks();
  });
  const togglePlaybook = (source_key, enabled) => window.__sb.rpc("admin_toggle_playbook", { p_source_key: source_key, p_enabled: enabled }).then(({ error }) => {
    if (error) {showToast("danger", "Toggle failed", error.message);return;}
    showToast(enabled ? "success" : "warning", enabled ? "Adapter enabled" : "Adapter disabled", source_key);refetchPlaybooks();
  });
  const deletePlaybook = (source_key) => window.__sb.rpc("admin_delete_playbook", { p_source_key: source_key }).then(({ error }) => {
    if (error) {showToast("danger", "Delete failed", error.message);return;}
    showToast("info", "Adapter removed", source_key);refetchPlaybooks();
  });
  const addLocality = (state, county, display) => window.__sb.rpc("admin_upsert_locality", { p_state: state, p_county: county, p_display: display }).then(({ data, error }) => {
    if (error || data && data.status !== "ok") {showToast("danger", "Add locality failed", error && error.message || data && data.status);return;}
    showToast("success", "Locality added", display || county);refetchPlaybooks();
  });

  const saveProfile = (updates) => {
    setProfile((p) => ({ ...p, ...updates }));
    showToast("success", "Profile updated", updates.name);
    setShowProfile(false);
  };

  /* ---- navigation ---- */
  const openTicket = (ticketId) => {setSelectedTicketId(ticketId);setRoute("inbox");};
  const openCustomer = (customerId) => {setSelectedCustomerId(customerId);setRoute("customers");};
  const openLead = (leadId) => {setSelectedLeadId(leadId);setRoute("leadops");};
  const goHome = (r, ctx) => {
    if (r === "inbox" && ctx?.ticketId) setSelectedTicketId(ctx.ticketId);
    if (r === "customers" && ctx?.customerId) setSelectedCustomerId(ctx.customerId);
    setRoute(r);
  };

  /* ---- tickets ---- */
  const replyToTicket = (ticketId, { body, internal }) => {
    const ticket = tickets.find((t) => t.id === ticketId);
    if (!ticket) return;
    const time = "Just now";
    setTickets((prev) => prev.map((t) => t.id === ticketId ? { ...t, status: t.status === "New" ? "Open" : t.status, updatedAt: time, messages: [...t.messages, { author: profile.name, type: "agent", time, body, internal }] } : t));
    const cust = getCustomer(ticket.customerId);
    logAudit("ticket", internal ? `Added an internal note to ticket ${ticketId}` : `Replied to ticket ${ticketId}`, cust?.name, cust?.id);
    showToast("success", internal ? "Note added" : "Reply sent", ticket.subject);
  };
  const setTicketStatus = (ticketId, status) => {
    const ticket = tickets.find((t) => t.id === ticketId);
    if (!ticket) return;
    setTickets((prev) => prev.map((t) => t.id === ticketId ? { ...t, status, updatedAt: "Just now" } : t));
    const cust = getCustomer(ticket.customerId);
    logAudit("ticket", `Marked ticket ${ticketId} as ${status}`, cust?.name, cust?.id);
    showToast("info", `Ticket ${status.toLowerCase()}`, ticket.subject);
  };
  const createTicket = ({ customerId, category, priority, subject, body }) => {
    const id = "TCK-" + Math.floor(3900 + Math.random() * 500);
    const cust = getCustomer(customerId);
    const requester = cust?.users?.[0] || cust?.owner;
    const time = "Just now";
    const ticket = { id, customerId, category, subject, status: "New", priority, assignee: "Unassigned", slaMinutesLeft: 1440, createdAt: time, updatedAt: time, requester: { name: requester?.name, email: requester?.email }, messages: [{ author: requester?.name || "Customer", type: "customer", time, body }] };
    setTickets((prev) => [ticket, ...prev]);
    logAudit("ticket", `Opened ticket ${id} on behalf of customer`, cust?.name, cust?.id);
    showToast("success", "Ticket created", subject);
    setShowNewTicket(false);
    openTicket(id);
  };

  /* ---- wallet ---- */
  const applyWalletAdjustment = ({ customerId, ticketId, type, amount, reasonLabel, note }) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust) return;
    const sign = type === "debit" || type === "chargeback" ? -1 : 1;
    const delta = sign * amount;
    const newBalance = Math.max(0, +(cust.wallet.available + delta).toFixed(2));
    setCustomers((prev) => prev.map((c) => c.id === customerId ? { ...c, wallet: { ...c.wallet, available: newBalance } } : c));
    const txn = { id: "TXN-" + Math.floor(59000 + Math.random() * 900), customerId, type, amount: delta, balanceAfter: newBalance, method: "Support adjustment", status: "succeeded", actor: profile.name, note: note || reasonLabel, createdAt: "Just now" };
    setLedger((prev) => [txn, ...prev]);
    logAudit("wallet", `${reasonLabel} (${type}, ${amount} Strata)`, cust.name, cust.id);
    showToast("success", "Wallet adjusted", `New balance: ${fmtStrata(newBalance)} Strata`);
    setAdjustCtx(null);
  };
  const retryCharge = (ledgerId) => {
    const entry = ledger.find((l) => l.id === ledgerId);
    if (!entry) return;
    const cust = customers.find((c) => c.id === entry.customerId);
    setLedger((prev) => prev.map((l) => l.id === ledgerId ? { ...l, status: "succeeded", note: l.note + " — retried", createdAt: "Just now" } : l));
    if (cust && entry.type === "reload") setCustomers((prev) => prev.map((c) => c.id === cust.id ? { ...c, wallet: { ...c.wallet, available: +(c.wallet.available + entry.amount).toFixed(2) } } : c));
    logAudit("wallet", `Retried a failed charge (${ledgerId})`, cust?.name, cust?.id);
    showToast("success", "Charge succeeded", cust ? cust.name : entry.customerId);
  };

  /* ---- customers ---- */
  const resetPassword = (customerId, email) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust) return;
    const target = email || cust.owner.email;
    logAudit("account", "Sent a password reset email", cust.name, cust.id);
    showToast("info", "Password reset sent", target);
  };
  const changePlan = (customerId, planName) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust) return;
    const price = planName === "Starter" ? 49 : planName === "Professional" ? 149 : 499;
    setCustomers((prev) => prev.map((c) => c.id === customerId ? { ...c, plan: { ...c.plan, name: planName, price } } : c));
    logAudit("account", `Changed plan to ${planName}`, cust.name, cust.id);
    showToast("success", "Plan updated", `${cust.name} is now on ${planName}`);
  };
  const resendVault = (customerId, leadId) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust) return;
    setCustomers((prev) => prev.map((c) => c.id === customerId ? { ...c, wonLeads: c.wonLeads.map((l) => l.id === leadId ? { ...l, vaultStatus: "delivered" } : l) } : c));
    logAudit("account", "Released vault access for a won lead", cust.name, cust.id);
    showToast("success", "Vault released", cust.name);
  };
  const updateOwner = (customerId, updates) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust) return;
    setCustomers((prev) => prev.map((c) => c.id === customerId ? { ...c, owner: { ...c.owner, name: updates.name, email: updates.email, phone: updates.phone }, location: updates.location } : c));
    logAudit("account", "Updated account owner contact info", updates.name, customerId);
    showToast("success", "Account owner updated", updates.name);
  };
  const assignLead = (customerId, leadQueueEntry) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust || !leadQueueEntry) return;
    const tierBase = { AAA: 230, AA: 175, A: 135, BBB: 60, BB: 32, B: 22, "B-": 15 };
    const amount = Math.round((tierBase[leadQueueEntry.tier] || 50) * (0.85 + Math.random() * 0.3));
    const newLead = { id: "GL" + Math.floor(1000 + Math.random() * 9000), address: leadQueueEntry.address, cityZip: leadQueueEntry.cityZip, tier: leadQueueEntry.tier, trigger: leadQueueEntry.trigger, contact: "Property Owner", amount, vaultStatus: "delivered", wonAt: "Just now" };
    setCustomers((prev) => prev.map((c) => c.id === customerId ? { ...c, wonLeads: [newLead, ...c.wonLeads] } : c));
    logAudit("account", `Manually assigned a lead (${leadQueueEntry.address}) to customer`, cust.name, cust.id);
    showToast("success", "Lead assigned", `${leadQueueEntry.address} added to ${cust.name}'s vault`);
  };
  const resendInvoice = (customerId, invoiceId) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust) return;
    logAudit("wallet", `Resent invoice ${invoiceId}`, cust.name, cust.id);
    showToast("success", "Invoice resent", `${invoiceId} \u2014 ${cust.owner.email}`);
  };
  const sendCardUpdateLink = (customerId) => {
    const cust = customers.find((c) => c.id === customerId);
    if (!cust) return;
    logAudit("wallet", "Sent a card-update link", cust.name, cust.id);
    showToast("success", "Update link sent", cust.owner.email);
  };

  /* ---- lead ops ---- */
  const verifyLead = (id, { tier }) => {
    if (live) {
      window.__sb.rpc("admin_review_lead", { p_lead_ext_id: id, p_decision: "verify", p_tier: tier }).then(({ data, error }) => {
        if (error || data && data.status !== "ok") {showToast("danger", "Verify failed", error && error.message || data && data.status || "error");return;}
        showToast("success", "Lead verified", id);refetchQueue();
      });
      return;
    }
    const lead = leadQueue.find((l) => l.id === id);
    if (!lead) return;
    setLeadQueue((prev) => prev.map((l) => l.id === id ? { ...l, status: "verified", tier: tier } : l));
    logAudit("lead", "Verified and published a lead to the Preview Feed", lead.address, null);
    showToast("success", "Lead verified", `${lead.address} is now live in the Preview Feed`);
  };
  const rejectLead = (id, { reason }) => {
    if (live) {
      window.__sb.rpc("admin_review_lead", { p_lead_ext_id: id, p_decision: "reject", p_reason: reason }).then(({ data, error }) => {
        if (error || data && data.status !== "ok") {showToast("danger", "Reject failed", error && error.message || data && data.status || "error");return;}
        showToast("warning", "Lead rejected", id);refetchQueue();
      });
      return;
    }
    const lead = leadQueue.find((l) => l.id === id);
    if (!lead) return;
    setLeadQueue((prev) => prev.map((l) => l.id === id ? { ...l, status: "rejected", rejectReason: reason } : l));
    logAudit("lead", "Rejected a lead submission", lead.address, null);
    showToast("warning", "Lead rejected", lead.address);
  };

  /* ---- lead intelligence → review handoff ----
     The scoring pipeline's output enters the very same queue the Lead Review
     page consumes; new candidates are prepended so they surface at the top of
     the pending tab. This is the seam between the discovery and review flows. */
  const publishBatchToReview = (batch) => {
    if (!batch || batch.length === 0) return;
    const existing = new Set(leadQueue.map((l) => l.id));
    const fresh = batch.filter((l) => !existing.has(l.id)).map((l) => ({ ...l, status: "pending" }));
    if (fresh.length === 0) return;
    setLeadQueue((prev) => [...fresh, ...prev]);
    logAudit("lead", `Published ${fresh.length} scored lead${fresh.length === 1 ? "" : "s"} to the review queue`, "Lead Intelligence pass", null);
    showToast("success", "Batch sent to Lead Review", `${fresh.length} scored lead${fresh.length === 1 ? "" : "s"} added to the pending queue`);
  };

  /* ---- lead enrichment → vault handoff ----
     Promoting a corroborated contact is the delivery step: the verified owner
     phone/email becomes the deliverable for that lead's vault. */
  const promoteContact = (lead, contact) => {
    logAudit("lead", `Promoted a verified ${contact.type} to the vault for ${lead.address}`, lead.address, null);
    showToast("success", "Contact promoted to vault", `${contact.masked} · ${contact.confidence}% confidence`);
  };

  /* ---- publishing → marketplace ----
     A verified lead that clears the crawl_publish_gate goes live. Accepts a
     single lead or a batch. Mirrors the discovery→review→enrich→publish flow. */
  const publishLead = (leadOrArray) => {
    const arr = Array.isArray(leadOrArray) ? leadOrArray : [leadOrArray];
    if (arr.length === 0) return;
    const ids = new Set(arr.map((l) => l.id));
    setLeadQueue((prev) => prev.map((l) => ids.has(l.id) ? { ...l, status: "published" } : l));
    logAudit("lead", `Published ${arr.length} lead${arr.length === 1 ? "" : "s"} to the marketplace`, arr.length === 1 ? arr[0].address : `${arr.length} leads`, null);
    showToast("success", "Published to marketplace", arr.length === 1 ? `${arr[0].address} is now live` : `${arr.length} leads now live`);
  };

  /* ---- governance: gate holds + gated-action approvals (all audit-logged) ---- */
  const gateToggle = (gate, state) => {
    logAudit("governance", `${state === "held" ? "Held" : "Opened"} the ${gate.name} (${gate.action})`, gate.name, null);
    showToast(state === "held" ? "warning" : "success", state === "held" ? "Gate held" : "Gate opened", gate.name);
  };
  const decideApproval = (approval, decision) => {
    logAudit("governance", `${decision === "approve" ? "Approved" : "Held"} gated action — ${approval.title}`, approval.title, null);
    showToast(decision === "approve" ? "success" : "info", decision === "approve" ? "Approval granted" : "Action held", approval.title);
  };

  const openTickets = tickets.filter((t) => t.status !== "Closed").length;
  const pendingLeads = leadQueue.filter((l) => l.status === "pending").length;
  const liveAuctions = SOD.AUCTIONS.filter((a) => a.status === "live").length;

  return (
    <div style={{ display: "flex", minHeight: "100vh", background: "var(--bg)" }}>
      <OpsSidebar route={route} setRoute={setRoute} counts={{ openTickets, pendingLeads, liveAuctions }} profile={profile} />
      <div style={{ flex: 1, minWidth: 0, display: "flex", flexDirection: "column" }}>
        <OpsTopbar tickets={tickets} customers={customers} leadQueue={leadQueue} ledger={ledger} onOpenTicket={openTicket} onOpenCustomer={openCustomer} onOpenLead={openLead} onNewTicket={route === "inbox" ? () => setShowNewTicket(true) : null} profile={profile} onOpenProfile={() => setShowProfile(true)} localities={live && liveLocalities && liveLocalities.length ? liveLocalities : [{ id: "dc", display_name: "Washington, DC" }]} locality={locality} onLocalityChange={setLocality} />
        <main style={{ flex: 1, minWidth: 0 }}>
          {route === "home" && <HomePage tickets={tickets} ledger={ledger} leadQueue={leadQueue} auditLog={auditLog} onNavigate={goHome} />}
          {route === "inbox" &&
          <TicketsPage tickets={tickets} customers={customers} cannedResponses={SOD.CANNED_RESPONSES} selectedTicketId={selectedTicketId} onSelectTicket={setSelectedTicketId} onReply={replyToTicket} onSetStatus={setTicketStatus} onOpenAdjustWallet={setAdjustCtx} onOpenCustomer={openCustomer} onResetPassword={resetPassword} />
          }
          {route === "customers" &&
          <CustomersPage customers={customers} tickets={tickets} ledger={ledger} auditLog={auditLog} leadQueue={leadQueue} selectedCustomerId={selectedCustomerId} onSelectCustomer={setSelectedCustomerId} onOpenAdjustWallet={setAdjustCtx} onResetPassword={resetPassword} onChangePlan={changePlan} onResendVault={resendVault} onOpenTicket={openTicket} onUpdateOwner={updateOwner} onAssignLead={assignLead} onResendInvoice={resendInvoice} onSendCardUpdateLink={sendCardUpdateLink} />
          }
          {route === "intel" && <LeadIntelPage intel={SOD.INTEL} onPublishToReview={publishBatchToReview} onNavigate={goHome} reviewPendingCount={pendingLeads} />}
          {route === "enrich" && <LeadEnrichPage enrichment={live ? liveEnrichment || EMPTY_ENRICH : SOD.ENRICHMENT} onNotify={showToast} onPromote={promoteContact} />}
          {route === "playbooks" && <SourcePlaybooksPage live={live} sources={SOD.INTEL.sources} playbooks={livePlaybooks} localities={liveLocalities} onNotify={showToast} onSave={savePlaybook} onToggle={togglePlaybook} onDelete={deletePlaybook} onAddLocality={addLocality} />}
          {route === "publishing" && <PublishingQueuePage leadQueue={leadQueue} enrichment={SOD.ENRICHMENT} onPublish={publishLead} onNavigate={goHome} />}
          {route === "systemhealth" && <SystemHealthPage system={SOD.SYSTEM} sources={SOD.INTEL.sources} leadQueue={leadQueue} onNavigate={goHome} />}
          {route === "gatereview" && <GateReviewPage governance={SOD.GOVERNANCE} onGateToggle={gateToggle} onDecide={decideApproval} onNavigate={goHome} />}
          {route === "leadops" && <LeadOpsPage leadQueue={live ? liveQueue || [] : leadQueue} onVerify={verifyLead} onReject={rejectLead} selectedLeadId={selectedLeadId} onSelectLead={setSelectedLeadId} />}
          {route === "auctions" && <AuctionsPage />}
          {route === "walletops" && <WalletOpsPage ledger={ledger} customers={customers} onOpenAdjustWallet={setAdjustCtx} onRetryCharge={retryCharge} onOpenCustomer={openCustomer} />}
          {route === "auditlog" && <AuditLogPage auditLog={auditLog} onOpenTicket={openTicket} onOpenCustomer={openCustomer} />}
        </main>
      </div>

      {adjustCtx && <AdjustWalletDrawer ctx={adjustCtx} customers={customers} onClose={() => setAdjustCtx(null)} onApply={applyWalletAdjustment} />}
      {showNewTicket && <NewTicketDrawer customers={customers} onClose={() => setShowNewTicket(false)} onCreate={createTicket} />}
      {showProfile && <ProfileDrawer profile={profile} onClose={() => setShowProfile(false)} onSave={saveProfile} />}
      <ToastStack toasts={toasts} onDismiss={dismissToast} />
    </div>);

}

/* ---- Auth gate (Phase 2) ----------------------------------------------------
   Live mode (?use_live=true) requires a signed-in PLATFORM ADMIN: it checks the
   Supabase session, then is_platform_admin() (0038). Non-admins and anon are
   turned away. Mock mode (default) renders the console directly, offline. */
function OpsGateShell({ children }) {
  React.useEffect(() => {window.OpsShared.refresh();});
  return (
    <div style={{ minHeight: "100vh", display: "grid", placeItems: "center", background: "var(--bg)", padding: 24 }}>
      <div style={{ width: "min(420px,100%)", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: "var(--radius-lg)", boxShadow: "var(--shadow-lg)", padding: 28, display: "grid", gap: 18 }}>
        <div style={{ display: "flex", justifyContent: "center" }}><Logo variant="stack" size={24} /></div>
        <div style={{ textAlign: "center" }}><span className="eyebrow" style={{ margin: 0 }}>Operations Console</span></div>
        {children}
      </div>
    </div>);

}

function OpsGate() {
  const [phase, setPhase] = React.useState(OPS_LIVE ? "checking" : "ok");
  const [email, setEmail] = React.useState("");
  const [err, setErr] = React.useState("");
  const [loginEmail, setLoginEmail] = React.useState("");
  const [pw, setPw] = React.useState("");
  const [busy, setBusy] = React.useState(false);

  const check = async () => {
    setPhase("checking");setErr("");
    try {
      const { data: { session } } = await window.__sb.auth.getSession();
      if (!session) {setPhase("signin");return;}
      setEmail(session.user.email || "");
      const { data: isAdmin, error } = await window.__sb.rpc("is_platform_admin");
      if (error) {setErr(error.message);setPhase("error");return;}
      setPhase(isAdmin ? "ok" : "denied");
    } catch (e) {setErr(String(e && e.message || e));setPhase("error");}
  };
  React.useEffect(() => {if (OPS_LIVE) check();}, []);

  const signIn = async () => {
    setBusy(true);setErr("");
    try {
      const { error } = await window.__sb.auth.signInWithPassword({ email: loginEmail.trim(), password: pw });
      if (error) throw error;
      window.localStorage.setItem("STRATUM_USE_LIVE", "true");
      await check();
    } catch (e) {setErr(e && e.message || String(e));} finally {setBusy(false);}
  };
  const signOut = async () => {try {await window.__sb.auth.signOut();} catch (e) {}setPhase("signin");};

  if (phase === "ok") return <App live={OPS_LIVE} />;
  if (phase === "checking") return <OpsGateShell><div style={{ display: "grid", gap: 10, justifyItems: "center", color: "var(--text-muted)" }}><Spinner size={22} /><span>Checking access…</span></div></OpsGateShell>;
  if (phase === "denied") return <OpsGateShell><div style={{ display: "grid", gap: 12, justifyItems: "center", textAlign: "center" }}>{I("shield-x", { width: 30, color: "var(--danger)" })}<strong style={{ fontSize: 15 }}>Not authorized</strong><span style={{ fontSize: 13, color: "var(--text-muted)" }}><b>{email}</b> is not a platform admin. Ask an owner to allowlist you, then reload.</span><Button variant="secondary" onClick={signOut}>Sign out</Button></div></OpsGateShell>;
  if (phase === "error") return <OpsGateShell><div style={{ display: "grid", gap: 12, justifyItems: "center", textAlign: "center" }}><strong style={{ color: "var(--danger)" }}>Couldn't verify access</strong><span style={{ fontSize: 12.5, color: "var(--text-muted)" }}>{err}</span><Button variant="secondary" onClick={check}>Retry</Button></div></OpsGateShell>;
  return (
    <OpsGateShell>
      <div style={{ display: "grid", gap: 14 }}>
        <div style={{ textAlign: "center", fontSize: 13, color: "var(--text-muted)" }}>Platform-admin sign in</div>
        <Field label="Email" type="email" value={loginEmail} onChange={(e) => setLoginEmail(e.target.value)} placeholder="you@stratumleads.com" />
        <Field label="Password" type="password" value={pw} onChange={(e) => setPw(e.target.value)} />
        {err && <span style={{ fontSize: 12.5, color: "var(--danger)" }}>{err}</span>}
        <Button variant="primary" disabled={busy || !loginEmail || !pw} fullWidth icon={busy ? <Spinner size={14} /> : I("log-in", { width: 15 })} onClick={signIn}>{busy ? "Signing in…" : "Sign in"}</Button>
      </div>
    </OpsGateShell>);

}

{
  const __r = typeof document !== "undefined" && document.getElementById("root");
  if (__r && !window.__rootMounted) {
    window.__rootMounted = true;
    ReactDOM.createRoot(__r).render(<OpsGate />);
    window.OpsShared.refresh();
  }
}
