// screens-workspaces.jsx — Client Workspace screens
// Tabs: Overview | My Tasks | Recommendations | Peer Review | Actions

// Languages offered for AI content generation. "English" is the default / no-op.
const CONTENT_LANGUAGES = [
  "English", "Spanish", "French", "German", "Portuguese",
  "Italian", "Hindi", "Arabic", "Chinese (Simplified)", "Japanese",
];

// ---------------------------------------------------------------------------
// ClientsScreen — superadmin/consultant entry point: pick a client/tenant
// ---------------------------------------------------------------------------
// Days remaining on a trial (null = no trial end set / no expiry).
function _trialDaysLeft(t) {
  if (!t || !t.trial_ends_at) return null;
  const ms = new Date(t.trial_ends_at).getTime() - Date.now();
  return Math.ceil(ms / 86400000);
}

function ClientsScreen() {
  const [tenants, setTenants] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [search, setSearch] = React.useState("");
  const [busyId, setBusyId] = React.useState(null);
  const role = window.session?.role;
  const isSuper = role === "superadmin";

  const load = React.useCallback(async () => {
    try {
      let list = [];
      if (isSuper) {
        list = (await api.call("listTenants")) || [];   // full TenantOut incl. status + trial fields
      } else {
        const portfolio = await api.call("myPortfolio");
        list = (portfolio?.clients || []).map(c => ({
          id: c.tenant_id, name: c.tenant_name, status: c.status || "active", trial_ends_at: null,
        }));
      }
      setTenants(list);
    } catch (_) {}
    setLoading(false);
  }, [isSuper]);

  React.useEffect(() => { load(); }, [load]);

  // Superadmin lifecycle actions (stopPropagation so the row doesn't navigate).
  const act = async (e, kind, t) => {
    e.stopPropagation();
    try {
      if (kind === "disable") {
        if (!window.confirm(`Disable "${t.name}"? Its generated data is archived to S3 and removed from the live DB until you re-enable.`)) return;
        setBusyId(t.id);
        await api.call("tenantDisable", { tenantId: t.id }, { reason: "Disabled by admin" });
        window.__toast && window.__toast(`${t.name} disabled`);
      } else if (kind === "enable") {
        setBusyId(t.id);
        await api.call("tenantEnable", { tenantId: t.id });
        window.__toast && window.__toast(`${t.name} re-enabled`);
      } else if (kind === "extend") {
        const v = window.prompt(`Set trial length for "${t.name}" (days from now):`, "15");
        if (v == null) return;
        const days = parseInt(v, 10);
        if (isNaN(days) || days < 0) { window.__toast && window.__toast("Enter a valid number of days", "warn"); return; }
        setBusyId(t.id);
        await api.call("tenantTrial", { tenantId: t.id }, { days });
        window.__toast && window.__toast(`Trial set to ${days} days`);
      }
      await load();
    } catch (err) {
      window.__toast && window.__toast(err?.message || "Action failed", "warn");
    } finally {
      setBusyId(null);
    }
  };

  const filtered = tenants.filter(t =>
    (t.name || "").toLowerCase().includes(search.toLowerCase())
  );

  if (loading) return <div style={{ padding: 48, color: "var(--muted)" }}>Loading clients…</div>;

  const cols = "1.3fr 1.2fr 110px 220px";
  const btn = (label, onClick, tone) => (
    <button onClick={onClick} disabled={busyId}
      style={{ border: "1px solid var(--line)", background: "var(--panel)", color: tone || "var(--ink)",
        borderRadius: 6, padding: "4px 10px", fontSize: 12, fontWeight: 600, cursor: busyId ? "not-allowed" : "pointer" }}>
      {label}
    </button>
  );

  return (
    <div style={{ padding: "var(--pad)", maxWidth: 1200 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 24 }}>
        <div>
          <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0 }}>Clients</h1>
          <div style={{ color: "var(--muted)", fontSize: 14, marginTop: 4 }}>
            Select a client to view their overview, workspaces, and intelligence hub.
          </div>
        </div>
        <button
          onClick={() => window.__nav("new-client")}
          style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "10px 18px", fontWeight: 600, cursor: "pointer", fontSize: 14 }}
        >+ Onboard Client</button>
      </div>

      <input
        placeholder="Search clients…"
        value={search}
        onChange={e => setSearch(e.target.value)}
        style={{ width: "100%", padding: "10px 14px", borderRadius: 8, border: "1px solid var(--line)", marginBottom: 20, fontSize: 14, background: "var(--panel)", color: "var(--ink)" }}
      />

      {filtered.length === 0 ? (
        <div style={{ textAlign: "center", padding: 64, color: "var(--muted)" }}>
          <div style={{ fontSize: 32, marginBottom: 12 }}>🏢</div>
          <div style={{ fontWeight: 600 }}>No clients found</div>
        </div>
      ) : (
        <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden" }}>
          <div style={{ display: "grid", gridTemplateColumns: cols, padding: "9px 20px", background: "var(--panel-2)", borderBottom: "1px solid var(--line)", fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.06em" }}>
            <div>Client Name</div>
            <div>Trial</div>
            <div style={{ textAlign: "center" }}>Status</div>
            <div style={{ textAlign: "right" }}>Actions</div>
          </div>
          {filtered.map((t, i) => {
            const active = (t.status || "active") === "active";
            const days = _trialDaysLeft(t);
            let trialText = "—", trialColor = "var(--muted)";
            if (active && days != null) {
              if (days < 0) { trialText = "Trial expired"; trialColor = "var(--bad)"; }
              else if (days === 0) { trialText = "Last day"; trialColor = "var(--warn)"; }
              else { trialText = `${days}d left`; trialColor = days <= 3 ? "var(--warn)" : "var(--muted)"; }
            } else if (!active) {
              trialText = "—";
            }
            return (
              <div
                key={t.id}
                style={{ display: "grid", gridTemplateColumns: cols, alignItems: "center", padding: "14px 20px", borderBottom: i < filtered.length - 1 ? "1px solid var(--line-2)" : "none", cursor: "pointer", transition: "background .1s", opacity: active ? 1 : 0.7 }}
                onClick={() => { window.session.setTenant(t.id); window.__nav("client-overview", t.id); }}
                onMouseEnter={e => e.currentTarget.style.background = "var(--hover)"}
                onMouseLeave={e => e.currentTarget.style.background = ""}
              >
                <div style={{ fontWeight: 700, fontSize: 14, color: "var(--accent)" }}>{t.name}</div>
                <div style={{ fontSize: 13, color: trialColor, fontWeight: 500 }}>{trialText}</div>
                <div style={{ textAlign: "center" }}>
                  <span style={{
                    background: active ? "var(--good-soft)" : "color-mix(in oklab, var(--bad) 14%, transparent)",
                    color: active ? "var(--good)" : "var(--bad)",
                    borderRadius: 6, padding: "3px 10px", fontSize: 12, fontWeight: 600 }}>
                    {active ? "Active" : "Disabled"}
                  </span>
                </div>
                <div style={{ display: "flex", justifyContent: "flex-end", gap: 6, alignItems: "center" }}
                     onClick={e => e.stopPropagation()}>
                  {isSuper && active && btn("Extend", e => act(e, "extend", t))}
                  {isSuper && active && btn("Disable", e => act(e, "disable", t), "var(--bad)")}
                  {isSuper && !active && btn("Enable", e => act(e, "enable", t), "var(--good)")}
                  <span
                    onClick={() => { window.session.setTenant(t.id); window.__nav("client-overview", t.id); }}
                    style={{ color: "var(--accent)", fontSize: 13, fontWeight: 600, cursor: "pointer" }}>View →</span>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// WorkspaceListScreen
// ---------------------------------------------------------------------------
function WorkspaceListScreen({ clientId }) {
  const [workspaces, setWorkspaces] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [search, setSearch] = React.useState("");

  React.useEffect(() => {
    api.tcall("listWorkspaces").then(r => {
      setWorkspaces(r || []);
      setLoading(false);
    }).catch(() => setLoading(false));
  }, []);

  const filtered = workspaces.filter(w =>
    w.name.toLowerCase().includes(search.toLowerCase()) ||
    (w.client_company_name || "").toLowerCase().includes(search.toLowerCase())
  );

  const statusBadge = (s) => {
    const map = { active: ["good", "Active"], analyzing: ["warn", "Analyzing"], failed: ["bad", "Failed"] };
    const [color, label] = map[s] || ["muted", s];
    return <span style={{ color: `var(--${color})`, background: `var(--${color}-soft)`, borderRadius: 6, padding: "2px 8px", fontSize: 12, fontWeight: 600 }}>{label}</span>;
  };

  if (loading) return <div style={{ padding: 48, color: "var(--muted)" }}>Loading workspaces…</div>;

  if (!window.session?.tenantId) {
    return (
      <div style={{ padding: "var(--pad)", maxWidth: 1100 }}>
        <h1 style={{ fontSize: 22, fontWeight: 700, marginBottom: 8 }}>Workspaces</h1>
        <div style={{ marginTop: 48, textAlign: "center", color: "var(--muted)" }}>
          <div style={{ fontSize: 32, marginBottom: 12 }}>👆</div>
          <div style={{ fontWeight: 600 }}>No client selected</div>
          <div style={{ fontSize: 14, marginTop: 6 }}>Select a client from the Clients screen to view their workspaces.</div>
        </div>
      </div>
    );
  }

  // Group workspaces by client company
  const grouped = filtered.reduce((acc, w) => {
    const key = w.client_company_name || "Other";
    if (!acc[key]) acc[key] = [];
    acc[key].push(w);
    return acc;
  }, {});
  const companies = Object.keys(grouped).sort();

  return (
    <div style={{ padding: "var(--pad)", maxWidth: 1100 }}>
      {(window.session?.role === "superadmin" || window.session?.role === "consultant") && (
        <button
          onClick={() => window.__nav("clients")}
          style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", fontSize: 13, padding: 0, marginBottom: 16 }}
        >← Clients</button>
      )}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 24 }}>
        <div>
          <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0 }}>Workspaces</h1>
          <div style={{ color: "var(--muted)", fontSize: 14, marginTop: 4 }}>
            Persistent intelligence hubs — each workspace tracks a client and their competitors continuously.
          </div>
        </div>
        <button
          onClick={() => window.__nav("new-client", clientId)}
          style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "10px 18px", fontWeight: 600, cursor: "pointer" }}
        >
          + New Workspace
        </button>
      </div>

      <input
        placeholder="Search clients…"
        value={search}
        onChange={e => setSearch(e.target.value)}
        style={{ width: "100%", padding: "10px 14px", borderRadius: 8, border: "1px solid var(--line)", marginBottom: 20, fontSize: 14, background: "var(--panel)", color: "var(--ink)" }}
      />

      {filtered.length === 0 ? (
        <div style={{ textAlign: "center", padding: 64, color: "var(--muted)" }}>
          <div style={{ fontSize: 32, marginBottom: 12 }}>🏢</div>
          <div style={{ fontWeight: 600 }}>No workspaces yet</div>
          <div style={{ fontSize: 14, marginTop: 6 }}>Onboard your first client to get started with the CredAxis intelligence hub.</div>
        </div>
      ) : (
        <div>
          {companies.map(company => (
            <div key={company} style={{ marginBottom: 28 }}>
              <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: "0.08em", textTransform: "uppercase",
                            color: "var(--muted-2)", padding: "4px 4px 10px", borderBottom: "1px solid var(--line-2)", marginBottom: 10 }}>
                {company}
              </div>
              <div style={{ display: "grid", gap: 8 }}>
                {grouped[company].map(w => (
                  <div
                    key={w.id}
                    onClick={() => window.__nav("client-detail", w.id)}
                    style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: "16px 20px", cursor: "pointer", display: "flex", alignItems: "center", gap: 16 }}
                  >
                    <div style={{ flex: 1 }}>
                      <div style={{ fontWeight: 600, fontSize: 15 }}>{w.name}</div>
                      <div style={{ color: "var(--muted)", fontSize: 13, marginTop: 2 }}>
                        {w.competitor_count} competitor{w.competitor_count !== 1 ? "s" : ""}
                      </div>
                      {w.assigned_consultants && w.assigned_consultants.length > 0 && (
                        <div style={{ display: "flex", alignItems: "center", gap: 6, marginTop: 6 }}>
                          {w.assigned_consultants.map(c => (
                            <span key={c.consultant_id} style={{ fontSize: 11, background: "var(--accent-soft, #eff0ff)", color: "var(--accent)", borderRadius: 20, padding: "2px 8px", fontWeight: 600 }}>
                              {c.name}
                            </span>
                          ))}
                        </div>
                      )}
                    </div>
                    <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                      {w.last_refreshed_at && (
                        <span style={{ color: "var(--muted-2)", fontSize: 12 }}>
                          Refreshed {new Date(w.last_refreshed_at).toLocaleDateString()}
                        </span>
                      )}
                      {statusBadge(w.status)}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// WorkspaceSetupScreen — 3-step wizard
// ---------------------------------------------------------------------------
function WorkspaceSetupScreen({ onDone, initialClientId }) {
  const [step, setStep] = React.useState(1);
  const [companies, setCompanies] = React.useState([]);
  const [clientId, setClientId] = React.useState(initialClientId || "");
  const [name, setName] = React.useState("");
  const [domain, setDomain] = React.useState("");
  const [workspaceId, setWorkspaceId] = React.useState(null);
  const [competitors, setCompetitors] = React.useState([]);
  const [adding, setAdding] = React.useState(false);
  const [creating, setCreating] = React.useState(false);
  const [analysing, setAnalysing] = React.useState(false);
  const [err, setErr] = React.useState("");

  React.useEffect(() => {
    api.tcall("listCompanies").then(r => setCompanies((r || []).filter(c => c.is_client)));
  }, []);

  const createWorkspace = async () => {
    if (!clientId || !name.trim()) { setErr("Select a client and enter a workspace name."); return; }
    setCreating(true); setErr("");
    try {
      const ws = await api.tcall("createWorkspace", {}, { name, client_company_id: clientId });
      setWorkspaceId(ws.id);
      setStep(2);
    } catch (e) { setErr(e.message || "Failed to create workspace"); }
    setCreating(false);
  };

  const addCompetitor = async () => {
    if (!domain.trim()) return;
    setAdding(true); setErr("");
    try {
      const c = await api.tcall("addWorkspaceCompetitor", { workspaceId }, { domain });
      setCompetitors(prev => [...prev, c]);
      setDomain("");
    } catch (e) { setErr(e.message || "Failed to add competitor"); }
    setAdding(false);
  };

  const startAnalysis = async () => {
    setAnalysing(true);
    try {
      await api.tcall("analyseWorkspace", { workspaceId });
      onDone && onDone(workspaceId);
    } catch (e) { setErr(e.message || "Failed to start analysis"); setAnalysing(false); }
  };

  const stepLabels = ["1. Select Client", "2. Add Competitors", "3. Launch"];

  return (
    <div style={{ padding: "var(--pad)", maxWidth: 640 }}>
      <h1 style={{ fontSize: 22, fontWeight: 700, marginBottom: 8 }}>Onboard Client</h1>
      <div style={{ display: "flex", gap: 8, marginBottom: 32 }}>
        {stepLabels.map((l, i) => (
          <span key={i} style={{
            padding: "4px 14px", borderRadius: 20, fontSize: 13, fontWeight: 600,
            background: step === i + 1 ? "var(--accent)" : "var(--line)",
            color: step === i + 1 ? "var(--accent-ink)" : "var(--muted)"
          }}>{l}</span>
        ))}
      </div>

      {err && <div style={{ background: "var(--bad)", color: "#fff", borderRadius: 8, padding: "10px 14px", marginBottom: 16, fontSize: 14 }}>{err}</div>}

      {step === 1 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div>
            <label style={{ display: "block", fontWeight: 600, marginBottom: 6, fontSize: 14 }}>Workspace name</label>
            <input
              value={name}
              onChange={e => setName(e.target.value)}
              placeholder="e.g. Acme Corp Intelligence Hub"
              style={{ width: "100%", padding: "10px 14px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 14, background: "var(--panel)", color: "var(--ink)" }}
            />
          </div>
          <div>
            <label style={{ display: "block", fontWeight: 600, marginBottom: 6, fontSize: 14 }}>Client company</label>
            <select
              value={clientId}
              onChange={e => setClientId(e.target.value)}
              style={{ width: "100%", padding: "10px 14px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 14, background: "var(--panel)", color: "var(--ink)" }}
            >
              <option value="">Select client…</option>
              {companies.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
            </select>
          </div>
          <button
            onClick={createWorkspace}
            disabled={creating}
            style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px 20px", fontWeight: 600, cursor: "pointer", marginTop: 8 }}
          >
            {creating ? "Creating…" : "Create Workspace →"}
          </button>
        </div>
      )}

      {step === 2 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div style={{ fontSize: 14, color: "var(--muted)" }}>Add competitor domains. These will be tracked alongside your client.</div>
          <div style={{ display: "flex", gap: 8 }}>
            <input
              value={domain}
              onChange={e => setDomain(e.target.value)}
              onKeyDown={e => e.key === "Enter" && addCompetitor()}
              placeholder="competitor.com"
              style={{ flex: 1, padding: "10px 14px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 14, background: "var(--panel)", color: "var(--ink)" }}
            />
            <button
              onClick={addCompetitor}
              disabled={adding}
              style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "10px 18px", fontWeight: 600, cursor: "pointer" }}
            >
              {adding ? "Adding…" : "Add"}
            </button>
          </div>
          {competitors.length > 0 && (
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              {competitors.map(c => (
                <div key={c.id} style={{ background: "var(--panel-2)", border: "1px solid var(--line)", borderRadius: 8, padding: "10px 14px", display: "flex", justifyContent: "space-between" }}>
                  <span style={{ fontWeight: 500 }}>{c.name}</span>
                  <span style={{ color: "var(--muted)", fontSize: 13 }}>{c.website}</span>
                </div>
              ))}
            </div>
          )}
          <div style={{ display: "flex", gap: 10, marginTop: 8 }}>
            <button onClick={() => setStep(3)} style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px 20px", fontWeight: 600, cursor: "pointer" }}>
              Next →
            </button>
            <button onClick={() => setStep(3)} style={{ background: "none", border: "1px solid var(--line)", borderRadius: 8, padding: "12px 20px", fontWeight: 500, cursor: "pointer", color: "var(--muted)" }}>
              Skip for now
            </button>
          </div>
        </div>
      )}

      {step === 3 && (
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div style={{ background: "var(--accent-soft)", borderRadius: 12, padding: 20 }}>
            <div style={{ fontWeight: 700, fontSize: 16, color: "var(--accent)", marginBottom: 8 }}>Ready to launch</div>
            <div style={{ fontSize: 14, color: "var(--ink-2)", lineHeight: 1.6 }}>
              This will run evidence collection (Firecrawl + SEMrush), compute CredAxis scores for
              all companies, and generate AI recommendations ranked by impact-to-effort ratio.
              Crons will keep refreshing automatically.
            </div>
          </div>
          <div style={{ fontSize: 14, color: "var(--muted)" }}>
            Competitors added: <b>{competitors.length}</b>
          </div>
          <button
            onClick={startAnalysis}
            disabled={analysing}
            style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "14px 24px", fontWeight: 700, cursor: "pointer", fontSize: 15 }}
          >
            {analysing ? "Launching analysis…" : "🚀 Launch Analysis"}
          </button>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// WorkspaceDashboardScreen — 5-tab detail view
// ---------------------------------------------------------------------------
function WorkspaceDashboardScreen({ workspaceId }) {
  const [workspace, setWorkspace] = React.useState(null);
  const [tab, setTab] = React.useState("overview");
  const [loading, setLoading] = React.useState(true);

  const reload = () => {
    api.tcall("getWorkspace", { workspaceId }).then(w => {
      setWorkspace(w);
      setLoading(false);
    }).catch(() => setLoading(false));
  };

  React.useEffect(() => { reload(); }, [workspaceId]);

  if (loading) return <div style={{ padding: 48, color: "var(--muted)" }}>Loading workspace…</div>;
  if (!workspace) return <div style={{ padding: 48, color: "var(--bad)" }}>Workspace not found.</div>;

  const tabs = [
    { id: "overview",        label: "Overview" },
    { id: "peer-analysis",   label: "Peer Analysis" },
    { id: "ai-visibility",   label: "AI Visibility" },
    { id: "recommendations", label: "Recommendations" },
    { id: "tasks",           label: "Tasks" },
    { id: "plans",           label: "Plans" },
  ];

  const statusColor = { active: "good", analyzing: "warn", failed: "bad" }[workspace.status] || "muted";

  return (
    <div style={{ padding: "var(--pad)", maxWidth: 1200 }}>
      {/* Header */}
      <div style={{ marginBottom: 24 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 6 }}>
          <button
            onClick={() => window.__nav("workspaces")}
            style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", fontSize: 13 }}
          >← Workspaces</button>
        </div>
        <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between" }}>
          <div>
            <h1 style={{ fontSize: 24, fontWeight: 700, margin: 0 }}>{workspace.name}</h1>
            <div style={{ color: "var(--muted)", fontSize: 14, marginTop: 4 }}>
              {workspace.client_company_name} · {workspace.competitors?.length || 0} competitor{workspace.competitors?.length !== 1 ? "s" : ""}
            </div>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            {workspace.last_refreshed_at && (
              <span style={{ color: "var(--muted-2)", fontSize: 12 }}>
                Last refreshed {new Date(workspace.last_refreshed_at).toLocaleString()}
              </span>
            )}
            <span style={{ color: `var(--${statusColor})`, background: `var(--${statusColor}-soft)`, borderRadius: 6, padding: "3px 10px", fontSize: 12, fontWeight: 600 }}>
              {workspace.status}
            </span>
            <button
              onClick={async () => {
                await api.tcall("analyseWorkspace", { workspaceId });
                reload();
              }}
              style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "8px 16px", fontWeight: 600, cursor: "pointer", fontSize: 13 }}
            >
              Refresh Analysis
            </button>
          </div>
        </div>
      </div>

      {/* Tab bar */}
      <div style={{ display: "flex", gap: 2, marginBottom: 28, borderBottom: "1px solid var(--line)", paddingBottom: 0 }}>
        {tabs.map(t => (
          <button
            key={t.id}
            onClick={() => setTab(t.id)}
            style={{
              background: "none", border: "none", cursor: "pointer",
              padding: "10px 20px", fontWeight: tab === t.id ? 700 : 500,
              color: tab === t.id ? "var(--accent)" : "var(--muted)",
              borderBottom: tab === t.id ? "2px solid var(--accent)" : "2px solid transparent",
              fontSize: 14, marginBottom: -1,
            }}
          >{t.label}</button>
        ))}
      </div>

      {/* Assigned consultants bar */}
      <WorkspaceConsultantBar workspace={workspace} workspaceId={workspaceId} tenantId={workspace.tenant_id} onRefresh={reload} />

      {/* Tab content */}
      {tab === "overview"        && <WorkspaceOverviewTab workspace={workspace} workspaceId={workspaceId} />}
      {tab === "peer-analysis"   && <WorkspacePeerAnalysisTab workspace={workspace} workspaceId={workspaceId} />}
      {tab === "ai-visibility"   && <WorkspaceAiVisibilityTab workspaceId={workspaceId} />}
      {tab === "recommendations" && <WorkspaceRecommendationsTab workspaceId={workspaceId} />}
      {tab === "tasks"           && <WorkspaceTasksTab workspace={workspace} workspaceId={workspaceId} />}
      {tab === "plans"           && <WorkspacePlansTab workspace={workspace} workspaceId={workspaceId} />}
    </div>
  );
}

// ---------------------------------------------------------------------------
// WorkspaceConsultantBar — shown in workspace detail header
// Superadmin can assign/remove; others see read-only list
// ---------------------------------------------------------------------------
function WorkspaceConsultantBar({ workspace, workspaceId, tenantId, onRefresh }) {
  const [allConsultants, setAllConsultants] = React.useState([]);
  const [adding, setAdding] = React.useState(false);
  const [selectedId, setSelectedId] = React.useState("");
  const [saving, setSaving] = React.useState(false);
  const isSuperadmin = window.session?.role === "superadmin";
  const assigned = workspace.assigned_consultants || [];

  React.useEffect(() => {
    if (!isSuperadmin) return;
    api.call("listConsultants").then(r => setAllConsultants(r || [])).catch(() => {});
  }, [isSuperadmin]);

  const assign = async () => {
    if (!selectedId) return;
    setSaving(true);
    try {
      await api.tcall("assignWorkspaceConsultant", { workspaceId }, { consultant_id: selectedId });
      onRefresh();
      setAdding(false);
      setSelectedId("");
    } catch (e) {}
    setSaving(false);
  };

  const remove = async (consultantId) => {
    await api.tcall("removeWorkspaceConsultant", { workspaceId, consultantId }).catch(() => {});
    onRefresh();
  };

  const unassigned = allConsultants.filter(c => !assigned.some(a => a.consultant_id === c.id));

  if (assigned.length === 0 && !isSuperadmin) return null;

  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 20, flexWrap: "wrap" }}>
      <span style={{ fontSize: 12, color: "var(--muted)", fontWeight: 600 }}>Consultants:</span>
      {assigned.map(c => (
        <span key={c.consultant_id} style={{ display: "inline-flex", alignItems: "center", gap: 5, background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 20, padding: "3px 10px", fontSize: 12, fontWeight: 600 }}>
          {c.name}
          {isSuperadmin && (
            <button onClick={() => remove(c.consultant_id)} style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", fontSize: 14, lineHeight: 1, padding: 0 }}>×</button>
          )}
        </span>
      ))}
      {assigned.length === 0 && <span style={{ fontSize: 12, color: "var(--muted-2)" }}>None assigned</span>}
      {isSuperadmin && !adding && (
        <button onClick={() => setAdding(true)} style={{ background: "none", border: "1px dashed var(--line)", borderRadius: 20, padding: "3px 10px", fontSize: 12, color: "var(--muted)", cursor: "pointer" }}>
          + Assign
        </button>
      )}
      {isSuperadmin && adding && (
        <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
          <select value={selectedId} onChange={e => setSelectedId(e.target.value)}
            style={{ padding: "4px 8px", borderRadius: 6, border: "1px solid var(--line)", fontSize: 12, background: "var(--panel)", color: "var(--ink)" }}>
            <option value="">Select consultant…</option>
            {unassigned.map(c => (
              <option key={c.id} value={c.id}>{c.user?.full_name || c.user?.email || c.id}</option>
            ))}
          </select>
          <button onClick={assign} disabled={!selectedId || saving}
            style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 6, padding: "4px 12px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
            {saving ? "…" : "Assign"}
          </button>
          <button onClick={() => { setAdding(false); setSelectedId(""); }}
            style={{ background: "none", border: "none", cursor: "pointer", fontSize: 12, color: "var(--muted)" }}>Cancel</button>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Tab: Overview
// ---------------------------------------------------------------------------
function WorkspaceOverviewTab({ workspace, workspaceId }) {
  const [benchmark, setBenchmark] = React.useState([]);
  const [history, setHistory] = React.useState([]);

  React.useEffect(() => {
    api.tcall("workspaceBenchmark", { workspaceId }).then(r => setBenchmark(r || [])).catch(() => {});
    api.tcall("workspaceScoreHistory", { workspaceId }).then(r => setHistory(r || [])).catch(() => {});
  }, [workspaceId]);

  const maxScore = Math.max(...benchmark.map(r => r.final_score || 0), 1);

  return (
    <div>
      {/* Benchmark bar chart */}
      {benchmark.length > 0 && (
        <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 24, marginBottom: 24 }}>
          <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 20 }}>Authority Score Ranking</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
            {benchmark.map(row => (
              <div key={row.company_id}>
                <div style={{ display: "flex", justifyContent: "space-between", fontSize: 13, marginBottom: 4 }}>
                  <span style={{ fontWeight: row.is_client ? 700 : 400, color: row.is_client ? "var(--accent)" : "var(--ink)" }}>
                    {row.company_name} {row.is_client ? "(Client)" : ""}
                  </span>
                  <span style={{ color: "var(--muted)", fontWeight: 600 }}>
                    {row.final_score != null ? row.final_score.toFixed(1) : "—"}/100
                  </span>
                </div>
                <div style={{ height: 8, background: "var(--line)", borderRadius: 4, overflow: "hidden" }}>
                  <div style={{
                    height: "100%", borderRadius: 4,
                    width: `${((row.final_score || 0) / maxScore) * 100}%`,
                    background: row.is_client ? "var(--accent)" : "var(--muted-2)"
                  }} />
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Score trend sparklines */}
      {history.length > 0 && (
        <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 24, marginBottom: 24 }}>
          <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 20 }}>Score Trend (90 days)</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            {history.map(row => (
              <div key={row.company_id}>
                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 6 }}>
                  <span style={{ fontSize: 13, fontWeight: row.is_client ? 700 : 400, color: row.is_client ? "var(--accent)" : "var(--ink)" }}>
                    {row.company_name}
                  </span>
                  <span style={{ fontSize: 12, color: "var(--muted)" }}>{row.snapshots.length} data points</span>
                </div>
                <SparkLine data={row.snapshots} isClient={row.is_client} />
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Score breakdown */}
      {benchmark.length > 0 && (
        <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 24 }}>
          <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 16 }}>Score Breakdown</div>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
            <thead>
              <tr style={{ borderBottom: "1px solid var(--line)" }}>
                <th style={{ textAlign: "left", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>Company</th>
                <th style={{ textAlign: "right", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>Total</th>
                <th style={{ textAlign: "right", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>Common (60)</th>
                <th style={{ textAlign: "right", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>Industry (30)</th>
                <th style={{ textAlign: "right", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>Momentum (10)</th>
                <th style={{ textAlign: "right", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>Band</th>
              </tr>
            </thead>
            <tbody>
              {benchmark.map(row => (
                <tr key={row.company_id} style={{ borderBottom: "1px solid var(--line-2)" }}>
                  <td style={{ padding: "8px", fontWeight: row.is_client ? 700 : 400, color: row.is_client ? "var(--accent)" : "var(--ink)" }}>
                    {row.company_name}
                  </td>
                  <td style={{ textAlign: "right", padding: "8px", fontWeight: 700 }}>{row.final_score?.toFixed(1) ?? "—"}</td>
                  <td style={{ textAlign: "right", padding: "8px", color: "var(--muted)" }}>{row.common_score?.toFixed(1) ?? "—"}</td>
                  <td style={{ textAlign: "right", padding: "8px", color: "var(--muted)" }}>{row.industry_score?.toFixed(1) ?? "—"}</td>
                  <td style={{ textAlign: "right", padding: "8px", color: "var(--muted)" }}>{row.momentum_score?.toFixed(1) ?? "—"}</td>
                  <td style={{ textAlign: "right", padding: "8px" }}>
                    {row.score_band && (
                      <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 6, padding: "2px 8px", fontSize: 11, fontWeight: 600 }}>{row.score_band}</span>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

function SparkLine({ data, isClient }) {
  if (!data || data.length < 2) return <div style={{ height: 32, color: "var(--muted-2)", fontSize: 12, display: "flex", alignItems: "center" }}>Not enough data</div>;
  const scores = data.map(d => d.total_score || 0);
  const min = Math.min(...scores);
  const max = Math.max(...scores, min + 1);
  const w = 200, h = 32;
  const pts = scores.map((s, i) => {
    const x = (i / (scores.length - 1)) * w;
    const y = h - ((s - min) / (max - min)) * h;
    return `${x},${y}`;
  }).join(" ");
  return (
    <svg width={w} height={h} style={{ overflow: "visible" }}>
      <polyline points={pts} fill="none" stroke={isClient ? "var(--accent)" : "var(--muted-2)"} strokeWidth={2} />
    </svg>
  );
}

// ---------------------------------------------------------------------------
// Tab: AI Visibility — share of voice across AI platforms (Perplexity/OpenAI/Gemini)
// ---------------------------------------------------------------------------
function WorkspaceAiVisibilityTab({ workspaceId }) {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    api.tcall("workspaceAiVisibility", { workspaceId })
      .then(r => { setData(r || null); setLoading(false); })
      .catch(() => setLoading(false));
  }, [workspaceId]);

  if (loading) return <div style={{ padding: 24, color: "var(--muted)" }}>Loading AI visibility…</div>;

  if (!data || !data.probe) {
    return (
      <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 32, textAlign: "center", color: "var(--muted)" }}>
        <div style={{ fontWeight: 700, fontSize: 16, color: "var(--ink)", marginBottom: 8 }}>No AI visibility data yet</div>
        <div style={{ fontSize: 13 }}>
          Run an analysis to check whether this brand and its peers surface in answers from
          Perplexity, ChatGPT and Gemini for buyer-intent questions.
        </div>
      </div>
    );
  }

  const companies = data.companies || [];
  const platforms = data.platforms || [];
  const cited = data.cited_domains || [];
  const pct = v => `${Math.round((v || 0) * 100)}%`;

  return (
    <div>
      {/* Probe meta */}
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16, color: "var(--muted)", fontSize: 12 }}>
        <span>Share of voice across {platforms.map(p => p[0].toUpperCase() + p.slice(1)).join(" · ")}</span>
        <span>{data.probe.prompt_count} buyer prompts · last run {new Date(data.probe.run_at).toLocaleString()}</span>
      </div>

      {/* Share-of-voice ranking bars */}
      <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 24, marginBottom: 24 }}>
        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 20 }}>AI Share of Voice</div>
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {companies.map(row => (
            <div key={row.company_id}>
              <div style={{ display: "flex", justifyContent: "space-between", fontSize: 13, marginBottom: 4 }}>
                <span style={{ fontWeight: row.is_client ? 700 : 400, color: row.is_client ? "var(--accent)" : "var(--ink)" }}>
                  {row.company_name} {row.is_client ? "(Client)" : ""}
                </span>
                <span style={{ color: "var(--muted)", fontWeight: 600 }}>
                  {pct(row.sov)} {row.avg_rank != null ? `· avg rank ${row.avg_rank}` : ""}
                </span>
              </div>
              <div style={{ height: 8, background: "var(--line)", borderRadius: 4, overflow: "hidden" }}>
                <div style={{ height: "100%", borderRadius: 4, width: `${(row.sov || 0) * 100}%`, background: row.is_client ? "var(--accent)" : "var(--muted-2)" }} />
              </div>
            </div>
          ))}
        </div>
      </div>

      {/* Per-platform breakdown */}
      <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 24, marginBottom: 24 }}>
        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 16 }}>By Platform</div>
        <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 13 }}>
          <thead>
            <tr style={{ borderBottom: "1px solid var(--line)" }}>
              <th style={{ textAlign: "left", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>Company</th>
              {platforms.map(p => (
                <th key={p} style={{ textAlign: "right", padding: "6px 8px", color: "var(--muted)", fontWeight: 600 }}>
                  {p[0].toUpperCase() + p.slice(1)}
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {companies.map(row => (
              <tr key={row.company_id} style={{ borderBottom: "1px solid var(--line-2)" }}>
                <td style={{ padding: "8px", fontWeight: row.is_client ? 700 : 400, color: row.is_client ? "var(--accent)" : "var(--ink)" }}>
                  {row.company_name}
                </td>
                {platforms.map(p => {
                  const ps = (row.platforms || {})[p];
                  return (
                    <td key={p} style={{ textAlign: "right", padding: "8px", color: ps && ps.prompts_hit ? "var(--ink)" : "var(--muted-2)" }}>
                      {ps ? pct(ps.sov) : "—"}
                    </td>
                  );
                })}
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {/* Sources the AI cites — surface targets */}
      {cited.length > 0 && (
        <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 24 }}>
          <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 6 }}>Sources the AI cites</div>
          <div style={{ color: "var(--muted)", fontSize: 12, marginBottom: 14 }}>
            Domains these AI answers drew from — strong targets for getting your brand mentioned.
          </div>
          <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
            {cited.map(d => (
              <span key={d} style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 6, padding: "4px 10px", fontSize: 12, fontWeight: 600 }}>{d}</span>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Tab: My Tasks
// ---------------------------------------------------------------------------
function WorkspaceTasksTab({ workspace, workspaceId }) {
  const [tasks, setTasks] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [showCreate, setShowCreate] = React.useState(false);
  const [statusFilter, setStatusFilter] = React.useState("all");
  const [taskPage, setTaskPage] = React.useState(1);
  const TASK_PAGE_SIZE = 25;

  const reload = () => {
    setLoading(true);
    api.tcall("listWorkspaceTasks", { workspaceId }).then(r => {
      setTasks(r || []);
      setLoading(false);
    }).catch(() => setLoading(false));
  };

  React.useEffect(() => { reload(); }, [workspaceId]);

  const srcBadge = (t) => {
    const map = {
      recommendation: ["var(--accent-soft)", "var(--accent)", "AI Rec"],
      peer_event:     ["var(--good-soft)",   "var(--good)",   "Peer Insight"],
      manual:         ["var(--line)",         "var(--muted)",  "Manual"],
    };
    const [bg, color, label] = map[t] || map.manual;
    return <span style={{ background: bg, color, borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700 }}>{label}</span>;
  };

  const statusBadge = (s) => {
    const map = {
      pending:     ["var(--line)",       "var(--muted)",   "Pending"],
      in_progress: ["var(--warn-soft)",  "var(--warn)",    "In Progress"],
      completed:   ["var(--good-soft)",  "var(--good)",    "Completed"],
      failed:      ["#fef2f2",           "var(--bad)",     "Failed"],
    };
    const [bg, color, label] = map[s] || map.pending;
    return <span style={{ background: bg, color, borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700 }}>{label}</span>;
  };

  const executorLabel = (task) => {
    if (!task.publisher_id) return { icon: "👤", label: "Consultant" };
    if (task.executor_type === "external_api") return { icon: "🤖", label: "AI — API" };
    if (task.executor_type === "external_email" || task.executor_type === "email") return { icon: "🤖", label: "AI — Email" };
    return { icon: "👤", label: "Consultant" };
  };

  const filteredTasks = statusFilter === "all" ? tasks : tasks.filter(t => t.status === statusFilter);
  const totalTaskPages = Math.ceil(filteredTasks.length / TASK_PAGE_SIZE);
  const pagedTasks = filteredTasks.slice((taskPage - 1) * TASK_PAGE_SIZE, taskPage * TASK_PAGE_SIZE);

  if (loading) return <div style={{ color: "var(--muted)", padding: 24 }}>Loading tasks…</div>;

  return (
    <div>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 20, flexWrap: "wrap", gap: 10 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
          <span style={{ fontWeight: 700, fontSize: 15 }}>Tasks</span>
          {["all", "pending", "in_progress", "completed", "failed"].map(f => (
            <button key={f} onClick={() => { setStatusFilter(f); setTaskPage(1); }}
              style={{ background: statusFilter === f ? "var(--accent)" : "var(--line)", color: statusFilter === f ? "var(--accent-ink)" : "var(--muted)", border: "none", borderRadius: 20, padding: "4px 12px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
              {f === "all" ? `All (${tasks.length})` : f.replace("_", " ")}
            </button>
          ))}
        </div>
        <button onClick={() => setShowCreate(true)}
          style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "8px 16px", fontWeight: 600, cursor: "pointer", fontSize: 13 }}>
          + Add Task
        </button>
      </div>

      {filteredTasks.length === 0 ? (
        <div style={{ textAlign: "center", padding: 64, color: "var(--muted)" }}>
          <div style={{ fontSize: 28, marginBottom: 12 }}>📋</div>
          <div style={{ fontWeight: 600 }}>No tasks yet</div>
          <div style={{ fontSize: 14, marginTop: 6 }}>
            Promote AI recommendations or peer insights to tasks, or add one manually.
          </div>
        </div>
      ) : (
        <>
        <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden", marginBottom: 16 }}>
          {/* Table header */}
          <div style={{ display: "grid", gridTemplateColumns: "100px 1fr 160px 140px 110px", gap: 0, padding: "9px 16px", background: "var(--panel-2)", borderBottom: "1px solid var(--line)", fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>
            <div>Source</div>
            <div>Title</div>
            <div>Target</div>
            <div>Executed by</div>
            <div style={{ textAlign: "right" }}>Status</div>
          </div>
          {pagedTasks.map((task, i) => {
            const exec = executorLabel(task);
            return (
              <div
                key={task.id}
                onClick={() => window.__nav("workspace-task", `${workspaceId}__${task.id}`)}
                style={{
                  display: "grid", gridTemplateColumns: "100px 1fr 160px 140px 110px",
                  alignItems: "center", padding: "12px 16px", cursor: "pointer",
                  borderBottom: i < pagedTasks.length - 1 ? "1px solid var(--line-2)" : "none",
                  background: "var(--panel)",
                  transition: "background .1s",
                }}
                onMouseEnter={e => { e.currentTarget.style.background = "var(--panel-2)"; }}
                onMouseLeave={e => { e.currentTarget.style.background = "var(--panel)"; }}
              >
                <div>{srcBadge(task.source_type)}</div>
                <div style={{ fontWeight: 600, fontSize: 13, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", paddingRight: 12 }}>{task.title}</div>
                <div style={{ fontSize: 12, color: "var(--muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {task.publisher_name || (task.target_email ? task.target_email : "Own Site")}
                </div>
                <div style={{ fontSize: 12, display: "flex", alignItems: "center", gap: 5 }}>
                  <span>{exec.icon}</span>
                  <span style={{ color: "var(--ink)" }}>{exec.label}</span>
                </div>
                <div style={{ display: "flex", justifyContent: "flex-end" }}>{statusBadge(task.status)}</div>
              </div>
            );
          })}
        </div>

        {/* Tasks pagination */}
        {totalTaskPages > 1 && (
          <div style={{ display: "flex", alignItems: "center", gap: 8, justifyContent: "center", marginBottom: 16 }}>
            <button onClick={() => setTaskPage(p => Math.max(1, p - 1))} disabled={taskPage === 1}
              style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", cursor: taskPage > 1 ? "pointer" : "not-allowed", color: taskPage > 1 ? "var(--ink)" : "var(--muted)", fontSize: 13 }}>← Prev</button>
            <span style={{ fontSize: 13, color: "var(--muted)" }}>Page {taskPage} of {totalTaskPages} · {filteredTasks.length} tasks</span>
            <button onClick={() => setTaskPage(p => Math.min(totalTaskPages, p + 1))} disabled={taskPage === totalTaskPages}
              style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", cursor: taskPage < totalTaskPages ? "pointer" : "not-allowed", color: taskPage < totalTaskPages ? "var(--ink)" : "var(--muted)", fontSize: 13 }}>Next →</button>
          </div>
        )}
        </>
      )}

      {/* Manual create modal */}
      {showCreate && (
        <AddToTasksModal
          workspaceId={workspaceId}
          sourceType="manual"
          title=""
          description=""
          onClose={() => setShowCreate(false)}
          onSaved={() => { setShowCreate(false); reload(); }}
        />
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// AddToTasksModal — shared: used from Tasks, Recommendations, Peer Review
// ---------------------------------------------------------------------------
function AddToTasksModal({ workspaceId, sourceType, sourceId, sourceIdField, title: initialTitle, description: initialDesc, platform: initialPlatform, aiPrompt: initialAiPrompt, onClose, onSaved }) {
  const [form, setForm] = React.useState({
    title: initialTitle || "",
    description: initialDesc || "",
    publisher_id: "",
    target_email: "",
    platform: initialPlatform || "",
    ai_prompt: initialAiPrompt || "",
    language: "English",
    execution_mode: "assisted",
  });
  const [publishers, setPublishers] = React.useState([]);
  const [contacts, setContacts] = React.useState([]);
  const [platforms, setPlatforms] = React.useState([]);
  const [saving, setSaving] = React.useState(false);
  const [err, setErr] = React.useState("");

  React.useEffect(() => {
    api.call("listPublishers").then(r => setPublishers((r || []).filter(p => p.is_active))).catch(() => {});
    api.tcall("listPlatformCatalog", {}).then(r => setPlatforms(r || [])).catch(() => {});
  }, []);

  // When publisher changes, load saved contacts for this tenant+publisher pair
  React.useEffect(() => {
    if (!form.publisher_id) { setContacts([]); setForm(p => ({ ...p, target_email: "" })); return; }
    api.tcall("listPublisherContacts", { publisher_id: form.publisher_id }).then(r => {
      const list = r || [];
      setContacts(list);
      setForm(p => ({ ...p, target_email: list.length > 0 ? list[0].contact_email : "" }));
    }).catch(() => {});
  }, [form.publisher_id]);

  const save = async () => {
    if (!form.title.trim()) { setErr("Title is required"); return; }
    setSaving(true);
    setErr("");
    try {
      const body = {
        title: form.title,
        description: form.description || null,
        source_type: sourceType,
        publisher_id: form.publisher_id || null,
        target_email: form.target_email || null,
        platform: form.platform || null,
        ai_prompt: form.ai_prompt || null,
        language: form.language || "English",
        execution_mode: form.execution_mode || "assisted",
      };
      if (sourceId && sourceIdField) body[sourceIdField] = sourceId;
      await api.tcall("createWorkspaceTask", { workspaceId }, body);

      // Persist contact email for future use (only if new)
      if (form.publisher_id && form.target_email) {
        const alreadySaved = contacts.some(c => c.contact_email === form.target_email);
        if (!alreadySaved) {
          await api.tcall("addPublisherContact", {}, {
            publisher_id: form.publisher_id,
            contact_email: form.target_email,
          }).catch(() => {});
        }
      }

      onSaved();
    } catch (e) {
      setErr(e.message || "Failed to create task");
    }
    setSaving(false);
  };

  const selectedPub = publishers.find(p => p.id === form.publisher_id);

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,.45)", zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center" }}>
      <div style={{ background: "var(--panel)", borderRadius: 16, padding: 28, width: 540, boxShadow: "var(--shadow-modal)", maxHeight: "90vh", overflowY: "auto" }}>
        <div style={{ fontWeight: 700, fontSize: 18, marginBottom: 4 }}>Add to My Tasks</div>
        <div style={{ fontSize: 13, color: "var(--muted)", marginBottom: 20 }}>
          {sourceType === "recommendation" ? "From AI Recommendation" : sourceType === "peer_event" ? "From Peer Activity" : "Manual task"}
        </div>

        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Title *</label>
            <input value={form.title} onChange={e => setForm(p => ({ ...p, title: e.target.value }))}
              placeholder="What needs to be done?"
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }} />
          </div>
          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Description</label>
            <textarea value={form.description} onChange={e => setForm(p => ({ ...p, description: e.target.value }))}
              rows={2} placeholder="More context…"
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)", resize: "vertical" }} />
          </div>

          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Platform</label>
            <select
              value={form.platform}
              onChange={e => setForm(p => ({ ...p, platform: e.target.value }))}
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
            >
              <option value="">Generic article (no specific platform)</option>
              {platforms.map(p => (
                <option key={p.platform} value={p.platform}>{p.label} ({p.content_kind})</option>
              ))}
            </select>
            <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 4 }}>
              Content is tailored to this platform's format. AI suggests one; you can change it.
            </div>
          </div>

          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>
              Content brief <span style={{ fontWeight: 400, color: "var(--muted)" }}>(AI prompt for this task)</span>
            </label>
            <textarea value={form.ai_prompt} onChange={e => setForm(p => ({ ...p, ai_prompt: e.target.value }))}
              rows={3} placeholder="The angle, key points, proof, and CTA for this piece. Brand details are added automatically."
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)", resize: "vertical" }} />
          </div>

          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Language</label>
            <select
              value={form.language}
              onChange={e => setForm(p => ({ ...p, language: e.target.value }))}
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
            >
              {CONTENT_LANGUAGES.map(l => <option key={l} value={l}>{l}</option>)}
            </select>
            <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 4 }}>
              AI writes the content in this language. You can change it later on the task.
            </div>
          </div>

          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Execution</label>
            <select
              value={form.execution_mode}
              onChange={e => setForm(p => ({ ...p, execution_mode: e.target.value }))}
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
            >
              <option value="assisted">Consultant posts (AI drafts, you publish)</option>
              <option value="ai_auto">AI auto-publishes (own site / API / email)</option>
            </select>
            <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 4 }}>
              Social platforms always need your login, so AI drafts and you post regardless.
            </div>
          </div>

          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Target publisher</label>
            <select
              value={form.publisher_id}
              onChange={e => setForm(p => ({ ...p, publisher_id: e.target.value }))}
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
            >
              <option value="">Client's Own Site (push via AI SEO)</option>
              {publishers.map(p => {
                const meta = [p.tier ? `Tier ${p.tier}` : null, p.region].filter(Boolean).join(" · ");
                return (
                  <option key={p.id} value={p.id}>{p.name}{meta ? ` — ${meta}` : (p.website ? ` — ${p.website}` : "")}</option>
                );
              })}
            </select>
            {selectedPub && (
              <div style={{ marginTop: 6, fontSize: 12, color: "var(--muted)", display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
                <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 4, padding: "1px 7px", fontWeight: 700, fontSize: 11 }}>
                  {selectedPub.publisher_type === "api" ? "API" : "Email"}
                </span>
                {(selectedPub.min_words || selectedPub.max_words) && (
                  <span>{selectedPub.min_words && selectedPub.max_words ? `${selectedPub.min_words}–${selectedPub.max_words}w` : selectedPub.min_words ? `${selectedPub.min_words}w+` : `≤${selectedPub.max_words}w`}</span>
                )}
                {selectedPub.max_backlinks != null && <span>≤{selectedPub.max_backlinks} link{selectedPub.max_backlinks !== 1 ? "s" : ""}</span>}
                {selectedPub.requires_exclusivity && <span style={{ fontWeight: 700 }}>· Exclusive</span>}
                {selectedPub.best_for && <span>· {selectedPub.best_for}</span>}
              </div>
            )}
          </div>

          {form.publisher_id && (
            <div>
              <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>
                Contact email
                {contacts.length > 0 && <span style={{ fontWeight: 400, color: "var(--good)", marginLeft: 8, fontSize: 12 }}>pre-filled from saved contacts</span>}
              </label>
              {contacts.length > 1 && (
                <select
                  value={form.target_email}
                  onChange={e => setForm(p => ({ ...p, target_email: e.target.value }))}
                  style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)", marginBottom: 6 }}
                >
                  <option value="">Select or type below…</option>
                  {contacts.map(c => <option key={c.id} value={c.contact_email}>{c.contact_email}</option>)}
                </select>
              )}
              <input
                type="email"
                value={form.target_email}
                onChange={e => setForm(p => ({ ...p, target_email: e.target.value }))}
                placeholder="editor@publisher.com"
                style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
              />
              <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 4 }}>
                This will be saved for next time you use this publisher with this client.
              </div>
            </div>
          )}
        </div>

        {err && <div style={{ color: "var(--bad)", fontSize: 13, marginTop: 12 }}>{err}</div>}

        <div style={{ display: "flex", gap: 10, marginTop: 24 }}>
          <button onClick={save} disabled={saving}
            style={{ flex: 1, background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px", fontWeight: 700, cursor: "pointer" }}>
            {saving ? "Adding…" : "Add to My Tasks"}
          </button>
          <button onClick={onClose}
            style={{ background: "none", border: "1px solid var(--line)", borderRadius: 8, padding: "12px 20px", cursor: "pointer", color: "var(--muted)" }}>
            Cancel
          </button>
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// WorkspaceTaskDetailPage — full-screen overlay task detail
// ---------------------------------------------------------------------------
function WorkspaceTaskDetailPage({ task: initialTask, workspaceId, onClose, onRefresh }) {
  const [task, setTask] = React.useState(initialTask);
  const [generating, setGenerating] = React.useState(false);
  const [sending, setSending] = React.useState(false);
  const [polling, setPolling] = React.useState(false);
  const [editingContent, setEditingContent] = React.useState(false);
  const [contentDraft, setContentDraft] = React.useState(initialTask.generated_content || "");
  const [savingContent, setSavingContent] = React.useState(false);
  const [copied, setCopied] = React.useState(false);
  const [language, setLanguage] = React.useState(initialTask.language || "English");
  const [promptDraft, setPromptDraft] = React.useState(initialTask.ai_prompt || "");
  const [mediaModel, setMediaModel] = React.useState(initialTask.media_model || "");
  const [mediaOptions, setMediaOptions] = React.useState([]);

  // Image/video tasks let the consultant pick the generation model.
  const mediaKind = (task.content_kind === "image" || task.content_kind === "video") ? task.content_kind : null;
  React.useEffect(() => {
    if (!mediaKind) return;
    api.tcall("listMediaModels", {})
      .then(r => setMediaOptions((r && r[mediaKind]) || []))
      .catch(() => {});
  }, [mediaKind]);

  const refreshTask = async () => {
    const t = await api.tcall("getWorkspaceTask", { workspaceId, taskId: task.id });
    if (t) {
      setTask(t);
      setContentDraft(t.generated_content || "");
      setLanguage(t.language || "English");
      setPromptDraft(t.ai_prompt || "");
      setMediaModel(t.media_model || "");
    }
    return t;
  };

  const startPoll = () => {
    setPolling(true);
    let attempts = 0;
    const poll = async () => {
      await new Promise(r => setTimeout(r, 2500));
      const t = await refreshTask();
      attempts++;
      if (t && t.status === "in_progress" && attempts < 20) setTimeout(poll, 2500);
      else setPolling(false);
    };
    poll();
  };

  const generate = async () => {
    setGenerating(true);
    try {
      await api.tcall("generateTaskContent", { workspaceId, taskId: task.id }, {
        ai_prompt: promptDraft || null,
        language: language || "English",
        ...(mediaKind ? { media_model: mediaModel || "" } : {}),
      });
      startPoll();
    } catch (e) {}
    setGenerating(false);
  };

  const saveContent = async () => {
    setSavingContent(true);
    try {
      await api.tcall("updateWorkspaceTask", { workspaceId, taskId: task.id }, { generated_content: contentDraft });
      await refreshTask();
      setEditingContent(false);
    } catch (e) {}
    setSavingContent(false);
  };

  const send = async () => {
    setSending(true);
    try { await api.tcall("sendTask", { workspaceId, taskId: task.id }); startPoll(); } catch (e) {}
    setSending(false);
  };

  const copyContent = () => {
    if (task.generated_content) {
      navigator.clipboard.writeText(task.generated_content).catch(() => {});
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }
  };

  const downloadContent = () => {
    const blob = new Blob([task.generated_content || ""], { type: "text/plain" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `${task.title.replace(/[^a-z0-9]/gi, "_").toLowerCase()}.txt`;
    a.click();
    URL.revokeObjectURL(url);
  };

  const srcLabel    = { recommendation: "AI Recommendation", peer_event: "Peer Insight", manual: "Manual" };
  const statusColor = { pending: "muted", in_progress: "warn", completed: "good", failed: "bad" };
  const hasContent  = !!task.generated_content;
  const isPending   = task.status === "pending" || task.status === "in_progress";
  const executorLabel = !task.publisher_id ? "Consultant"
    : task.executor_type === "external_api" ? "AI — API"
    : "AI — Email";

  const Section = ({ title, children }) => (
    <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, marginBottom: 16, overflow: "hidden" }}>
      <div style={{ padding: "12px 20px", borderBottom: "1px solid var(--line)", fontWeight: 700, fontSize: 13, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em", background: "var(--panel-2)" }}>
        {title}
      </div>
      <div style={{ padding: "18px 20px" }}>{children}</div>
    </div>
  );

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,.55)", zIndex: 1000, display: "flex", alignItems: "flex-start", justifyContent: "center", overflowY: "auto", padding: "32px 24px" }}>
      <div style={{ background: "var(--bg)", borderRadius: 16, width: "100%", maxWidth: 820, boxShadow: "var(--shadow-modal)", position: "relative" }}>

        {/* Header */}
        <div style={{ padding: "20px 28px", borderBottom: "1px solid var(--line)", display: "flex", alignItems: "flex-start", gap: 16 }}>
          <button onClick={onClose} style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", fontSize: 13, padding: 0, marginTop: 2, whiteSpace: "nowrap" }}>← Back</button>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 12, color: "var(--muted)", marginBottom: 4 }}>{srcLabel[task.source_type] || task.source_type}</div>
            <div style={{ fontWeight: 700, fontSize: 20, lineHeight: 1.3 }}>{task.title}</div>
          </div>
          <button onClick={onClose} style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", fontSize: 20, lineHeight: 1, padding: 4 }}>✕</button>
        </div>

        <div style={{ padding: "24px 28px" }}>
          {/* Meta row */}
          <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 20 }}>
            <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 6, padding: "4px 12px", fontSize: 12, fontWeight: 600 }}>
              {srcLabel[task.source_type] || task.source_type}
            </span>
            <span style={{
              background: task.status === "completed" ? "var(--good-soft)" : task.status === "failed" ? "#fef2f2" : task.status === "in_progress" ? "var(--warn-soft)" : "var(--line)",
              color: `var(--${statusColor[task.status] || "muted"})`,
              borderRadius: 6, padding: "4px 12px", fontSize: 12, fontWeight: 700,
            }}>{task.status?.replace("_", " ")}</span>
            <span style={{ background: "var(--line)", color: "var(--ink)", borderRadius: 6, padding: "4px 12px", fontSize: 12, fontWeight: 600 }}>
              {task.publisher_id ? (task.publisher_name || "Publisher") : "Own Site"}
            </span>
            <span style={{ background: "var(--panel)", border: "1px solid var(--line)", color: "var(--muted)", borderRadius: 6, padding: "4px 12px", fontSize: 12 }}>
              Executor: <b style={{ color: "var(--ink)" }}>{executorLabel}</b>
            </span>
            {polling && <span style={{ fontSize: 12, color: "var(--warn)", fontWeight: 600, display: "flex", alignItems: "center" }}>⟳ Processing…</span>}
          </div>

          {/* Description */}
          {task.description && (
            <Section title="Description">
              <div style={{ fontSize: 14, color: "var(--ink-2)", lineHeight: 1.7 }}>{task.description}</div>
            </Section>
          )}

          {/* AI Prompt + Language — editable before and after generation */}
          <Section title="AI Prompt & Language">
            <div style={{ marginBottom: 14 }}>
              <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Language</label>
              <select
                value={language}
                onChange={e => setLanguage(e.target.value)}
                disabled={generating || polling}
                style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
              >
                {(CONTENT_LANGUAGES.includes(language) ? CONTENT_LANGUAGES : [language, ...CONTENT_LANGUAGES])
                  .map(l => <option key={l} value={l}>{l}</option>)}
              </select>
            </div>
            {mediaKind && (
              <div style={{ marginBottom: 14 }}>
                <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>
                  {mediaKind === "image" ? "Image model" : "Video model"}
                </label>
                <select
                  value={mediaModel}
                  onChange={e => setMediaModel(e.target.value)}
                  disabled={generating || polling}
                  style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
                >
                  <option value="">Auto (recommended)</option>
                  {mediaOptions.map(m => <option key={m.slug} value={m.slug}>{m.label}</option>)}
                </select>
                <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 6 }}>
                  {mediaOptions.length
                    ? "Only providers with a configured API key are listed."
                    : "No media models are configured yet — add a provider API key to enable selection."}
                </div>
              </div>
            )}
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>
              Content brief <span style={{ fontWeight: 400, color: "var(--muted)" }}>(AI prompt for this task)</span>
            </label>
            <textarea
              value={promptDraft}
              onChange={e => setPromptDraft(e.target.value)}
              disabled={generating || polling}
              rows={4}
              placeholder="The angle, key points, proof, and CTA for this piece. Brand details are added automatically."
              style={{ width: "100%", padding: "10px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, fontFamily: "var(--mono)", background: "var(--panel-2)", color: "var(--ink)", lineHeight: 1.6, resize: "vertical", boxSizing: "border-box" }}
            />
            <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 6 }}>
              Edit the prompt or language, then {hasContent ? "Regenerate" : "Generate"} below to (re)create the content.
            </div>
          </Section>

          {/* AI Output */}
          <Section title="AI Output">
            {!hasContent && isPending && (
              <div>
                <div style={{ fontSize: 13, color: "var(--muted)", marginBottom: 14 }}>
                  AI will generate publication-ready content for this task. Review before sending.
                </div>
                <button
                  onClick={generate}
                  disabled={generating || polling}
                  style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px 24px", fontWeight: 700, cursor: "pointer", fontSize: 14 }}
                >{generating ? "Generating…" : polling ? "Generating…" : "Generate Content"}</button>
              </div>
            )}
            {!hasContent && !isPending && (
              <div style={{ color: "var(--muted)", fontSize: 13 }}>No content generated.</div>
            )}
            {hasContent && (
              <div>
                <div style={{ display: "flex", gap: 8, marginBottom: 12, flexWrap: "wrap" }}>
                  <button onClick={generate} disabled={generating || polling}
                    style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 700, cursor: "pointer", opacity: (generating || polling) ? 0.6 : 1 }}>
                    {generating || polling ? "Regenerating…" : "Regenerate"}
                  </button>
                  <button onClick={copyContent}
                    style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
                    {copied ? "Copied!" : "Copy"}
                  </button>
                  {editingContent ? (
                    <button onClick={saveContent} disabled={savingContent}
                      style={{ background: "#128a5b", color: "#fff", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 700, cursor: "pointer", opacity: savingContent ? 0.6 : 1 }}>
                      {savingContent ? "Saving…" : "Save"}
                    </button>
                  ) : null}
                  <button onClick={() => { setEditingContent(!editingContent); setContentDraft(task.generated_content); }}
                    style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
                    {editingContent ? "Cancel Edit" : "Edit"}
                  </button>
                  <button onClick={downloadContent}
                    style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
                    Download .txt
                  </button>
                  {task.generated_at && (
                    <span style={{ fontSize: 11, color: "var(--muted-2)", display: "flex", alignItems: "center", marginLeft: 4 }}>
                      Generated {new Date(task.generated_at).toLocaleString()}
                    </span>
                  )}
                </div>
                {editingContent ? (
                  <textarea
                    value={contentDraft}
                    onChange={e => setContentDraft(e.target.value)}
                    rows={12}
                    style={{ width: "100%", padding: "12px 14px", borderRadius: 8, border: "1px solid var(--accent)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)", lineHeight: 1.7, resize: "vertical", boxSizing: "border-box" }}
                  />
                ) : (
                  <div style={{ background: "var(--panel-2)", borderRadius: 8, padding: "14px 16px", fontSize: 13, lineHeight: 1.8, color: "var(--ink-2)", maxHeight: 320, overflowY: "auto", whiteSpace: "pre-wrap" }}>
                    {task.generated_content}
                  </div>
                )}
              </div>
            )}
          </Section>

          {/* Execute */}
          <Section title="Execute">
            {task.target_email && (
              <div style={{ background: "var(--panel-2)", borderRadius: 8, padding: "10px 14px", marginBottom: 16, fontSize: 13 }}>
                <span style={{ color: "var(--muted)" }}>Send to:</span> <b>{task.target_email}</b>
                {task.publisher_name && <span style={{ color: "var(--muted)", marginLeft: 8 }}>via {task.publisher_name}</span>}
              </div>
            )}
            <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
              {task.executor_type === "external_api" && (
                <button
                  onClick={send}
                  disabled={!hasContent || sending || polling || task.status === "completed"}
                  style={{ background: hasContent && !sending ? "var(--accent)" : "var(--line)", color: hasContent && !sending ? "var(--accent-ink)" : "var(--muted)", border: "none", borderRadius: 8, padding: "10px 20px", fontWeight: 700, cursor: "pointer", fontSize: 13, opacity: task.status === "completed" ? 0.5 : 1 }}
                >{sending ? "Publishing…" : "Publish via API"}</button>
              )}
              {(task.executor_type === "external_email" || task.executor_type === "email" || task.target_email) && (
                <button
                  onClick={send}
                  disabled={!hasContent || sending || polling || task.status === "completed"}
                  style={{ background: hasContent && !sending ? "#128a5b" : "var(--line)", color: hasContent && !sending ? "#fff" : "var(--muted)", border: "none", borderRadius: 8, padding: "10px 20px", fontWeight: 700, cursor: "pointer", fontSize: 13, opacity: task.status === "completed" ? 0.5 : 1 }}
                >{sending ? "Sending…" : "Send Email"}</button>
              )}
              <button
                onClick={downloadContent}
                disabled={!hasContent}
                style={{ background: "var(--line)", border: "none", borderRadius: 8, padding: "10px 20px", fontWeight: 600, cursor: hasContent ? "pointer" : "not-allowed", fontSize: 13, color: hasContent ? "var(--ink)" : "var(--muted)", opacity: hasContent ? 1 : 0.5 }}
              >Download File</button>
            </div>

            {/* Completion / awaiting states */}
            {task.status === "completed" && task.completed_by_name && (
              <div style={{ marginTop: 14, background: "var(--good-soft)", borderRadius: 8, padding: "12px 16px", border: "1px solid var(--good)" }}>
                <div style={{ fontWeight: 600, color: "var(--good)", fontSize: 13, marginBottom: 4 }}>Published</div>
                <div style={{ fontSize: 13, color: "var(--ink-2)" }}>
                  By: <b>{task.completed_by_name}</b>
                  {task.completed_at && <span> · {new Date(task.completed_at).toLocaleString()}</span>}
                  {task.completed_url && <> · <a href={task.completed_url} target="_blank" rel="noopener noreferrer" style={{ color: "var(--accent)" }}>{task.completed_url}</a></>}
                </div>
              </div>
            )}
            {task.status === "in_progress" && task.completion_token && !polling && (
              <div style={{ marginTop: 14, background: "var(--warn-soft)", borderRadius: 8, padding: "10px 14px", border: "1px solid var(--warn)", fontSize: 13, color: "var(--warn)" }}>
                Email sent · awaiting publisher confirmation
              </div>
            )}
          </Section>

          {task.notes && (
            <Section title="Notes">
              <div style={{ fontSize: 13, color: "var(--muted)", lineHeight: 1.6, whiteSpace: "pre-wrap" }}>{task.notes}</div>
            </Section>
          )}

          <div style={{ display: "flex", gap: 10, justifyContent: "flex-end", marginTop: 8 }}>
            <button onClick={() => refreshTask()}
              style={{ background: "var(--line)", border: "none", borderRadius: 8, padding: "9px 20px", cursor: "pointer", color: "var(--ink)", fontWeight: 600, fontSize: 13 }}>
              Refresh
            </button>
            <button onClick={onClose}
              style={{ background: "none", border: "1px solid var(--line)", borderRadius: 8, padding: "9px 20px", cursor: "pointer", color: "var(--muted)" }}>
              Close
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Tab: Recommendations
// ---------------------------------------------------------------------------
function WorkspaceRecommendationsTab({ workspaceId }) {
  const [recs, setRecs] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [filter, setFilter] = React.useState("all");
  const [showModal, setShowModal] = React.useState(false);
  const [taskTarget, setTaskTarget] = React.useState(null);
  const [recPage, setRecPage] = React.useState(1);
  const REC_PAGE_SIZE = 20;
  const [form, setForm] = React.useState({ title: "", rationale: "", factor_key: "", effort: "medium", content_type: "article", estimated_gain: 0 });
  const [saving, setSaving] = React.useState(false);
  const [generatingFull, setGeneratingFull] = React.useState(false);
  const [openCats, setOpenCats] = React.useState({});

  const reload = () => {
    api.tcall("workspaceRecommendations", { workspaceId }).then(r => {
      setRecs(r || []);
      setLoading(false);
    }).catch(() => setLoading(false));
  };

  // On-demand exhaustive run — fans out per category server-side and ADDS new
  // (non-duplicate) recs. Poll for a while since it runs in the background.
  const generateFull = async () => {
    setGeneratingFull(true);
    try {
      await api.tcall("generateFullRecommendations", { workspaceId });
      for (let i = 0; i < 12; i++) {
        await new Promise(r => setTimeout(r, 5000));
        const r = await api.tcall("workspaceRecommendations", { workspaceId }).catch(() => null);
        if (r) setRecs(r);
      }
    } catch (e) {}
    setGeneratingFull(false);
  };

  React.useEffect(() => { reload(); }, [workspaceId]);

  const addManual = async () => {
    if (!form.title.trim()) return;
    setSaving(true);
    try {
      await api.tcall("addManualRecommendation", { workspaceId }, form);
      setShowModal(false);
      setForm({ title: "", rationale: "", factor_key: "", effort: "medium", content_type: "article", estimated_gain: 0 });
      reload();
    } catch (e) {}
    setSaving(false);
  };

  const filtered = recs.filter(r => filter === "all" || r.source === filter);
  const totalRecPages = Math.ceil(filtered.length / REC_PAGE_SIZE);
  const pagedRecs = filtered.slice((recPage - 1) * REC_PAGE_SIZE, recPage * REC_PAGE_SIZE);

  const effortColor = { low: ["var(--good-soft)", "var(--good)"], medium: ["var(--warn-soft)", "var(--warn)"], high: ["#fef2f2", "var(--bad)"] };
  const impactColor = { high: ["var(--accent-soft)", "var(--accent)"], medium: ["var(--warn-soft)", "var(--warn)"], low: ["var(--line)", "var(--muted)"] };
  const CAT_ORDER = ["website", "links", "mentions", "content", "social", "reviews", "ai_visibility", "profiles"];
  const CAT_LABELS = { website: "Website & Technical", links: "Links & Listings", mentions: "Mentions & PR", content: "Content & Thought Leadership", social: "Social & Community", reviews: "Reviews & Trust", ai_visibility: "AI Visibility", profiles: "Profiles & Listings" };
  const TIER_ORDER = ["high", "medium", "low"];
  const fmtD = d => (d ? new Date(d).toLocaleDateString() : null);

  // Group the filtered recs by category, then by impact tier.
  const byCat = {};
  filtered.forEach(r => { const c = CAT_LABELS[r.category] ? r.category : "content"; (byCat[c] = byCat[c] || []).push(r); });
  const cats = CAT_ORDER.filter(c => (byCat[c] || []).length);
  const otherCats = Object.keys(byCat).filter(c => !CAT_ORDER.includes(c));
  const orderedCats = [...cats, ...otherCats];

  if (loading) return <div style={{ color: "var(--muted)", padding: 24 }}>Loading recommendations…</div>;

  return (
    <div>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 20, gap: 12, flexWrap: "wrap" }}>
        <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
          {["all", "ai", "manual"].map(f => (
            <button key={f} onClick={() => { setFilter(f); setRecPage(1); }}
              style={{ background: filter === f ? "var(--accent)" : "var(--line)", color: filter === f ? "var(--accent-ink)" : "var(--muted)", border: "none", borderRadius: 20, padding: "5px 14px", fontSize: 13, fontWeight: 600, cursor: "pointer" }}
            >{f === "all" ? "All" : f === "ai" ? "AI" : "Manual"}</button>
          ))}
          <span style={{ color: "var(--muted-2)", fontSize: 12, display: "flex", alignItems: "center", marginLeft: 4 }}>{filtered.length} total</span>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          <button onClick={generateFull} disabled={generatingFull}
            style={{ background: generatingFull ? "var(--line)" : "var(--accent-soft)", color: "var(--accent)", border: "1px solid var(--accent)", borderRadius: 8, padding: "8px 16px", fontWeight: 700, cursor: generatingFull ? "wait" : "pointer", fontSize: 13 }}>
            {generatingFull ? "⟳ Generating…" : "✨ Generate full recommendations"}
          </button>
          <button onClick={() => setShowModal(true)}
            style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "8px 16px", fontWeight: 600, cursor: "pointer", fontSize: 13 }}>
            + Add
          </button>
        </div>
      </div>

      {filtered.length === 0 ? (
        <div style={{ textAlign: "center", padding: 64, color: "var(--muted)" }}>
          <div style={{ fontSize: 28, marginBottom: 12 }}>💡</div>
          <div style={{ fontWeight: 600 }}>No recommendations yet</div>
          <div style={{ fontSize: 14, marginTop: 6 }}>Run an analysis for quick wins, or click <b>Generate full recommendations</b> for an exhaustive, categorized set.</div>
        </div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
          {orderedCats.map(cat => {
            const items = byCat[cat];
            const isOpen = openCats[cat] !== false;
            const byTier = {};
            items.forEach(r => { const t = impactColor[r.impact_tier] ? r.impact_tier : "low"; (byTier[t] = byTier[t] || []).push(r); });
            return (
              <div key={cat} style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 14, overflow: "hidden" }}>
                <div onClick={() => setOpenCats(p => ({ ...p, [cat]: !isOpen }))}
                  style={{ padding: "14px 20px", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "space-between", background: "var(--panel-2)" }}>
                  <div style={{ fontWeight: 700, fontSize: 15 }}>
                    {CAT_LABELS[cat] || cat}
                    <span style={{ fontWeight: 400, color: "var(--muted)", fontSize: 13, marginLeft: 8 }}>{items.length} item{items.length !== 1 ? "s" : ""}</span>
                  </div>
                  <span style={{ color: "var(--muted)", fontSize: 14 }}>{isOpen ? "▲" : "▼"}</span>
                </div>
                {isOpen && (
                  <div>
                    {TIER_ORDER.filter(t => (byTier[t] || []).length).map(tier => {
                      const [tBg, tClr] = impactColor[tier];
                      return (
                        <div key={tier}>
                          <div style={{ padding: "7px 20px", background: "var(--bg)", borderTop: "1px solid var(--line-2)", display: "flex", alignItems: "center", gap: 8 }}>
                            <span style={{ background: tBg, color: tClr, borderRadius: 4, padding: "2px 8px", fontSize: 10, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.04em" }}>{tier} impact</span>
                            <span style={{ color: "var(--muted-2)", fontSize: 11 }}>{byTier[tier].length}</span>
                          </div>
                          {byTier[tier].map(rec => {
                            const [efBg, efClr] = effortColor[rec.effort] || ["var(--line)", "var(--muted)"];
                            return (
                              <div key={rec.id} style={{ display: "flex", alignItems: "flex-start", gap: 12, padding: "13px 20px", borderTop: "1px solid var(--line-2)" }}>
                                <div style={{ flex: 1, minWidth: 0 }}>
                                  <div style={{ display: "flex", alignItems: "center", gap: 7, marginBottom: 4, flexWrap: "wrap" }}>
                                    <span style={{ fontWeight: 600, fontSize: 13 }}>{rec.title}</span>
                                    <span style={{ fontSize: 10, fontWeight: 700, borderRadius: 4, padding: "1px 6px", background: rec.source === "ai" ? "var(--accent-soft)" : "var(--good-soft)", color: rec.source === "ai" ? "var(--accent)" : "var(--good)" }}>{rec.source === "ai" ? "AI" : "Manual"}</span>
                                    {rec.rec_type === "action" && <span style={{ fontSize: 10, fontWeight: 700, borderRadius: 4, padding: "1px 6px", background: "var(--line)", color: "var(--muted)" }}>action</span>}
                                  </div>
                                  {rec.rationale && <div style={{ fontSize: 12, color: "var(--muted)", lineHeight: 1.5 }}>{rec.rationale}</div>}
                                  <div style={{ display: "flex", gap: 8, flexWrap: "wrap", alignItems: "center", marginTop: 6 }}>
                                    {rec.factor_key && <span style={{ fontSize: 11, background: "var(--line)", color: "var(--muted)", borderRadius: 4, padding: "1px 7px" }}>{rec.factor_key}</span>}
                                    {rec.content_type && <span style={{ fontSize: 11, color: "var(--muted)" }}>{rec.content_type.replace(/_/g, " ")}</span>}
                                    <span style={{ fontSize: 11, color: "var(--muted-2)" }}>
                                      Recommended {fmtD(rec.created_at) || "—"}{rec.implemented_at ? ` · ✓ Implemented ${fmtD(rec.implemented_at)}` : ""}
                                    </span>
                                  </div>
                                </div>
                                <div style={{ textAlign: "right", fontWeight: 700, color: "var(--good)", fontSize: 13, whiteSpace: "nowrap" }}>+{rec.estimated_gain?.toFixed(1)}</div>
                                <div><span style={{ background: efBg, color: efClr, borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700 }}>{rec.effort}</span></div>
                                <button onClick={e => { e.stopPropagation(); setTaskTarget(rec); }}
                                  style={{ background: "var(--accent-soft)", color: "var(--accent)", border: "1px solid var(--accent)", borderRadius: 6, padding: "4px 10px", fontSize: 11, fontWeight: 700, cursor: "pointer", whiteSpace: "nowrap" }}>
                                  → Tasks
                                </button>
                              </div>
                            );
                          })}
                        </div>
                      );
                    })}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}

      {taskTarget && (
        <AddToTasksModal
          workspaceId={workspaceId}
          sourceType="recommendation"
          sourceId={taskTarget.id}
          sourceIdField="source_rec_id"
          title={taskTarget.title}
          description={taskTarget.rationale || ""}
          platform={taskTarget.platform || ""}
          aiPrompt={taskTarget.ai_prompt || ""}
          onClose={() => setTaskTarget(null)}
          onSaved={() => setTaskTarget(null)}
        />
      )}

      {/* Add Recommendation Modal */}
      {showModal && (
        <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.4)", zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center" }}>
          <div style={{ background: "var(--panel)", borderRadius: 16, padding: 28, width: 520, boxShadow: "var(--shadow-modal)" }}>
            <div style={{ fontWeight: 700, fontSize: 18, marginBottom: 20 }}>Add Recommendation</div>
            <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
              {[
                { label: "Title *", key: "title", type: "text", placeholder: "What should the client do?" },
                { label: "Rationale", key: "rationale", type: "text", placeholder: "Why does this matter?" },
                { label: "Factor key", key: "factor_key", type: "text", placeholder: "e.g. media_coverage" },
                { label: "Estimated gain (pts)", key: "estimated_gain", type: "number", placeholder: "0" },
              ].map(({ label, key, type, placeholder }) => (
                <div key={key}>
                  <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>{label}</label>
                  <input
                    type={type}
                    value={form[key]}
                    onChange={e => setForm(p => ({ ...p, [key]: type === "number" ? parseFloat(e.target.value) || 0 : e.target.value }))}
                    placeholder={placeholder}
                    style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
                  />
                </div>
              ))}
              <div style={{ display: "flex", gap: 12 }}>
                <div style={{ flex: 1 }}>
                  <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Effort</label>
                  <select value={form.effort} onChange={e => setForm(p => ({ ...p, effort: e.target.value }))}
                    style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}>
                    <option value="low">Low</option>
                    <option value="medium">Medium</option>
                    <option value="high">High</option>
                  </select>
                </div>
                <div style={{ flex: 1 }}>
                  <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>Content type</label>
                  <select value={form.content_type} onChange={e => setForm(p => ({ ...p, content_type: e.target.value }))}
                    style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}>
                    {["article","social_post","image","video_script","web_copy","press_release"].map(t => (
                      <option key={t} value={t}>{t.replace("_", " ")}</option>
                    ))}
                  </select>
                </div>
              </div>
            </div>
            <div style={{ display: "flex", gap: 10, marginTop: 24 }}>
              <button
                onClick={addManual}
                disabled={saving}
                style={{ flex: 1, background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px", fontWeight: 700, cursor: "pointer" }}
              >{saving ? "Saving…" : "Save Recommendation"}</button>
              <button
                onClick={() => setShowModal(false)}
                style={{ background: "none", border: "1px solid var(--line)", borderRadius: 8, padding: "12px 20px", cursor: "pointer", color: "var(--muted)" }}
              >Cancel</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Tab: Peer Analysis — benchmark scores + competitor activity feed
// ---------------------------------------------------------------------------
function WorkspacePeerAnalysisTab({ workspace, workspaceId }) {
  const [events, setEvents] = React.useState([]);
  const [benchmark, setBenchmark] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [taskTarget, setTaskTarget] = React.useState(null);
  const [eventsOpen, setEventsOpen] = React.useState(false);
  const [eventPage, setEventPage] = React.useState(1);
  const PAGE_SIZE = 15;

  React.useEffect(() => {
    setLoading(true);
    Promise.all([
      api.tcall("workspaceBenchmark", { workspaceId }).catch(() => []),
      api.tcall("workspacePeerEvents", { workspaceId }).catch(() => []),
    ]).then(([b, e]) => {
      setBenchmark(b || []);
      setEvents(e || []);
      setLoading(false);
    });
  }, [workspaceId]);

  if (loading) return <div style={{ color: "var(--muted)", padding: 24 }}>Loading peer data…</div>;

  const changeColor = { changed: "warn", new: "good", removed: "bad" };
  const meaningfulCount = events.filter(e => e.is_meaningful).length;
  const competitors = benchmark.filter(r => !r.is_client).sort((a, b) => (b.final_score || 0) - (a.final_score || 0));

  // Paginated events
  const totalPages = Math.ceil(events.length / PAGE_SIZE);
  const pagedEvents = events.slice((eventPage - 1) * PAGE_SIZE, eventPage * PAGE_SIZE);

  return (
    <div>
      {/* ── Competitor Presence Table ── */}
      <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 16 }}>Competitor Digital Presence</div>
      {competitors.length === 0 ? (
          <div style={{ textAlign: "center", padding: 64, color: "var(--muted)" }}>
            <div style={{ fontSize: 28, marginBottom: 10 }}>📊</div>
            <div style={{ fontWeight: 600 }}>No competitor data yet</div>
            <div style={{ fontSize: 13, marginTop: 6 }}>Run an analysis to populate peer scores.</div>
          </div>
        ) : (
          <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden", marginBottom: 28 }}>
            <div style={{ display: "grid", gridTemplateColumns: "1.8fr 90px 90px 110px 110px 110px", padding: "9px 16px", background: "var(--panel-2)", borderBottom: "1px solid var(--line)", fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>
              <div>Competitor</div>
              <div style={{ textAlign: "right" }}>Authority Score</div>
              <div style={{ textAlign: "right" }}>Band</div>
              <div style={{ textAlign: "right" }}>Common Auth</div>
              <div style={{ textAlign: "right" }}>Industry Auth</div>
              <div style={{ textAlign: "right" }}>Momentum</div>
            </div>
            {competitors.map((row, i) => (
              <div key={row.company_id} style={{ display: "grid", gridTemplateColumns: "1.8fr 90px 90px 110px 110px 110px", alignItems: "center", padding: "12px 16px", borderBottom: i < competitors.length - 1 ? "1px solid var(--line-2)" : "none" }}>
                <div style={{ fontWeight: 600, fontSize: 13 }}>{row.company_name}</div>
                <div style={{ textAlign: "right", fontWeight: 700, fontSize: 13 }}>{row.final_score?.toFixed(1) ?? "—"}</div>
                <div style={{ textAlign: "right" }}>
                  {row.score_band && <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 6, padding: "2px 8px", fontSize: 11, fontWeight: 600 }}>{row.score_band}</span>}
                </div>
                <div style={{ textAlign: "right", color: "var(--muted)", fontSize: 13 }}>{row.common_score?.toFixed(1) ?? "—"}</div>
                <div style={{ textAlign: "right", color: "var(--muted)", fontSize: 13 }}>{row.industry_score?.toFixed(1) ?? "—"}</div>
                <div style={{ textAlign: "right", color: "var(--muted)", fontSize: 13 }}>{row.momentum_score?.toFixed(1) ?? "—"}</div>
              </div>
            ))}
          </div>
        )}

      {/* ── Recent Competitor Changes (collapsible) ── */}
      <div style={{ border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden" }}>
        <button
          onClick={() => setEventsOpen(o => !o)}
          style={{ width: "100%", display: "flex", alignItems: "center", justifyContent: "space-between", padding: "14px 20px", background: "var(--panel-2)", border: "none", cursor: "pointer", fontWeight: 700, fontSize: 14 }}
        >
          <span>Recent Competitor Changes {meaningfulCount > 0 && <span style={{ background: "var(--warn-soft)", color: "var(--warn)", borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700, marginLeft: 8 }}>{meaningfulCount} flagged</span>}</span>
          <span style={{ color: "var(--muted)", fontSize: 12 }}>{eventsOpen ? "▲ Hide" : "▼ Show"}</span>
        </button>
        {eventsOpen && (
        events.length === 0 ? (
          <div style={{ padding: 32, textAlign: "center", color: "var(--muted)" }}>
            <div style={{ fontSize: 28, marginBottom: 12 }}>👁️</div>
            <div style={{ fontWeight: 600 }}>No competitor activity yet</div>
            <div style={{ fontSize: 13, marginTop: 6, maxWidth: 400, margin: "6px auto 0" }}>
              Set up monitors in the <b>Monitoring</b> screen — Firecrawl will detect meaningful changes automatically.
            </div>
          </div>
        ) : (
          <div>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 16, padding: "16px 20px 0" }}>
              <div style={{ fontSize: 13, color: "var(--muted)" }}>{events.length} events · {meaningfulCount} flagged as meaningful</div>
            </div>

            <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 16, padding: "0 20px" }}>
              {pagedEvents.map(ev => (
                <div key={ev.id} style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 10, padding: "14px 18px", borderLeft: ev.is_meaningful ? "4px solid var(--accent)" : "4px solid var(--line)" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: ev.diff_summary ? 8 : 0, flexWrap: "wrap" }}>
                    {ev.company_name && <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 6, padding: "2px 10px", fontSize: 12, fontWeight: 700 }}>{ev.company_name}</span>}
                    {ev.change_status && <span style={{ background: `var(--${changeColor[ev.change_status] || "muted"}-soft)`, color: `var(--${changeColor[ev.change_status] || "muted"})`, borderRadius: 6, padding: "2px 8px", fontSize: 11, fontWeight: 600, textTransform: "uppercase" }}>{ev.change_status}</span>}
                    {ev.is_meaningful && <span style={{ background: "var(--warn-soft)", color: "var(--warn)", borderRadius: 4, padding: "1px 7px", fontSize: 11, fontWeight: 700 }}>MEANINGFUL</span>}
                    {ev.page_url && <span style={{ fontSize: 12, color: "var(--muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: 260 }}>{ev.page_url}</span>}
                    <span style={{ marginLeft: "auto", color: "var(--muted-2)", fontSize: 11, flexShrink: 0 }}>{ev.created_at ? new Date(ev.created_at).toLocaleString() : ""}</span>
                  </div>
                  {ev.diff_summary && (
                    <div style={{ fontSize: 13, color: "var(--ink-2)", background: "var(--panel-2)", borderRadius: 6, padding: "8px 12px", lineHeight: 1.5 }}>
                      {ev.diff_summary.slice(0, 300)}{ev.diff_summary.length > 300 ? "…" : ""}
                    </div>
                  )}
                  {ev.is_meaningful && (
                    <div style={{ marginTop: 10, display: "flex", justifyContent: "flex-end" }}>
                      <button onClick={() => setTaskTarget(ev)} style={{ background: "var(--accent-soft)", color: "var(--accent)", border: "1px solid var(--accent)", borderRadius: 6, padding: "4px 12px", fontSize: 12, fontWeight: 700, cursor: "pointer" }}>→ Add to Tasks</button>
                    </div>
                  )}
                </div>
              ))}
            </div>

            {/* Pagination */}
            {totalPages > 1 && (
              <div style={{ display: "flex", alignItems: "center", gap: 8, justifyContent: "center", padding: "0 20px 16px" }}>
                <button onClick={() => setEventPage(p => Math.max(1, p - 1))} disabled={eventPage === 1}
                  style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", cursor: eventPage > 1 ? "pointer" : "not-allowed", color: eventPage > 1 ? "var(--ink)" : "var(--muted)", fontSize: 13 }}>← Prev</button>
                <span style={{ fontSize: 13, color: "var(--muted)" }}>Page {eventPage} of {totalPages}</span>
                <button onClick={() => setEventPage(p => Math.min(totalPages, p + 1))} disabled={eventPage === totalPages}
                  style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", cursor: eventPage < totalPages ? "pointer" : "not-allowed", color: eventPage < totalPages ? "var(--ink)" : "var(--muted)", fontSize: 13 }}>Next →</button>
              </div>
            )}
          </div>
        )
        )}
      </div>

      {taskTarget && (
        <AddToTasksModal
          workspaceId={workspaceId}
          sourceType="peer_event"
          sourceId={taskTarget.id}
          sourceIdField="source_event_id"
          title={`Respond to: ${taskTarget.company_name || "competitor"} page ${taskTarget.change_status || "change"}`}
          description={taskTarget.diff_summary ? taskTarget.diff_summary.slice(0, 200) : ""}
          onClose={() => setTaskTarget(null)}
          onSaved={() => { setTaskTarget(null); }}
        />
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Tab: Plans — AI-generated monthly/weekly/daily action plans
// ---------------------------------------------------------------------------
function WorkspacePlansTab({ workspace, workspaceId }) {
  const [plans, setPlans] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [periodFilter, setPeriodFilter] = React.useState("all");
  const [showGenerate, setShowGenerate] = React.useState(false);
  const [generating, setGenerating] = React.useState(false);
  const [expandedPlan, setExpandedPlan] = React.useState(null);
  const [expandedDays, setExpandedDays] = React.useState({});
  const [planPage, setPlanPage] = React.useState(1);
  const PLANS_PAGE_SIZE = 10;

  const reload = () => {
    setLoading(true);
    const params = periodFilter !== "all" ? { period_type: periodFilter } : {};
    api.tcall("listWorkspacePlans", { ...params, workspaceId }).then(r => {
      setPlans(r || []);
      setLoading(false);
    }).catch(() => setLoading(false));
  };

  React.useEffect(() => { reload(); setPlanPage(1); }, [workspaceId, periodFilter]);

  const deletePlan = async (planId) => {
    if (!confirm("Delete this plan?")) return;
    await api.tcall("deleteWorkspacePlan", { workspaceId, planId }).catch(() => {});
    reload();
  };

  const regenerate = async (planId) => {
    await api.tcall("regeneratePlan", { workspaceId, planId }).catch(() => {});
    reload();
    setExpandedPlan(null);
  };

  const effortStyle = { low: ["var(--good-soft)", "var(--good)", "LOW"], medium: ["var(--warn-soft)", "var(--warn)", "MED"], high: ["#fef2f2", "var(--bad)", "HIGH"] };
  const statusMap   = { pending: "Pending", in_progress: "In Progress", completed: "Done", skipped: "Skipped" };
  const statusColor = { pending: "muted", in_progress: "warn", completed: "good", skipped: "muted" };

  const periodLabel = { daily: "Daily", weekly: "Weekly", monthly: "Monthly" };
  const filters = ["all", "daily", "weekly", "monthly"];

  // Pagination over plans list
  const totalPages = Math.ceil(plans.length / PLANS_PAGE_SIZE);
  const pagedPlans = plans.slice((planPage - 1) * PLANS_PAGE_SIZE, planPage * PLANS_PAGE_SIZE);

  if (loading) return <div style={{ color: "var(--muted)", padding: 24 }}>Loading plans…</div>;

  return (
    <div>
      {/* Header */}
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 20 }}>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
          {filters.map(f => (
            <button key={f} onClick={() => setPeriodFilter(f)}
              style={{ background: periodFilter === f ? "var(--accent)" : "var(--line)", color: periodFilter === f ? "var(--accent-ink)" : "var(--muted)", border: "none", borderRadius: 20, padding: "5px 14px", fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
              {f === "all" ? "All" : periodLabel[f]}
            </button>
          ))}
          <span style={{ color: "var(--muted-2)", fontSize: 12, display: "flex", alignItems: "center", marginLeft: 4 }}>{plans.length} plan{plans.length !== 1 ? "s" : ""}</span>
        </div>
        <button onClick={() => setShowGenerate(true)}
          style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "9px 18px", fontWeight: 600, cursor: "pointer", fontSize: 13 }}>
          + Generate Plan
        </button>
      </div>

      {plans.length === 0 ? (
        <div style={{ textAlign: "center", padding: 64, color: "var(--muted)" }}>
          <div style={{ fontSize: 32, marginBottom: 12 }}>📅</div>
          <div style={{ fontWeight: 600 }}>No plans yet</div>
          <div style={{ fontSize: 13, marginTop: 6 }}>Generate an AI plan to get a structured weekly or monthly action calendar for this client.</div>
          <button onClick={() => setShowGenerate(true)}
            style={{ marginTop: 20, background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "10px 24px", fontWeight: 600, cursor: "pointer" }}>
            Generate First Plan
          </button>
        </div>
      ) : (
        <div>
          <div style={{ display: "flex", flexDirection: "column", gap: 16, marginBottom: 20 }}>
            {pagedPlans.map(plan => (
              <PlanCard
                key={plan.id}
                plan={plan}
                workspaceId={workspaceId}
                expanded={expandedPlan === plan.id}
                expandedDays={expandedDays}
                onToggle={() => {
                  if (expandedPlan === plan.id) { setExpandedPlan(null); }
                  else { setExpandedPlan(plan.id); }
                }}
                onToggleDay={(day) => setExpandedDays(prev => ({ ...prev, [day]: !prev[day] }))}
                onDelete={() => deletePlan(plan.id)}
                onRegenerate={() => regenerate(plan.id)}
                onTaskUpdate={reload}
              />
            ))}
          </div>

          {/* Pagination */}
          {totalPages > 1 && (
            <div style={{ display: "flex", alignItems: "center", gap: 8, justifyContent: "center" }}>
              <button onClick={() => setPlanPage(p => Math.max(1, p - 1))} disabled={planPage === 1}
                style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", cursor: planPage > 1 ? "pointer" : "not-allowed", color: planPage > 1 ? "var(--ink)" : "var(--muted)", fontSize: 13 }}>← Prev</button>
              <span style={{ fontSize: 13, color: "var(--muted)" }}>Page {planPage} of {totalPages}</span>
              <button onClick={() => setPlanPage(p => Math.min(totalPages, p + 1))} disabled={planPage === totalPages}
                style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", cursor: planPage < totalPages ? "pointer" : "not-allowed", color: planPage < totalPages ? "var(--ink)" : "var(--muted)", fontSize: 13 }}>Next →</button>
            </div>
          )}
        </div>
      )}

      {showGenerate && (
        <PlanGenerateModal
          workspaceId={workspaceId}
          generating={generating}
          onGenerate={async (periodType, periodStart) => {
            setGenerating(true);
            try {
              await api.tcall("createWorkspacePlan", { workspaceId }, { period_type: periodType, period_start: periodStart });
              setShowGenerate(false);
              reload();
            } catch (e) {}
            setGenerating(false);
          }}
          onClose={() => setShowGenerate(false)}
        />
      )}
    </div>
  );
}

function PlanCard({ plan, workspaceId, expanded, expandedDays, onToggle, onToggleDay, onDelete, onRegenerate, onTaskUpdate }) {
  const [detail, setDetail] = React.useState(null);
  const [loadingDetail, setLoadingDetail] = React.useState(false);

  React.useEffect(() => {
    if (expanded && !detail) {
      setLoadingDetail(true);
      api.tcall("getWorkspacePlan", { workspaceId, planId: plan.id }).then(r => {
        setDetail(r);
        setLoadingDetail(false);
      }).catch(() => setLoadingDetail(false));
    }
  }, [expanded]);

  const periodLabel = { daily: "Daily", weekly: "Weekly", monthly: "Monthly" };
  const pct = plan.task_count > 0 ? Math.round((plan.completed_count / plan.task_count) * 100) : 0;
  const fmtDate = (d) => new Date(d).toLocaleDateString(undefined, { month: "short", day: "numeric", year: "numeric" });

  // Group tasks by scheduled_date
  const tasksByDay = React.useMemo(() => {
    if (!detail?.tasks) return {};
    return detail.tasks.reduce((acc, t) => {
      const day = t.scheduled_date?.slice(0, 10) || "unscheduled";
      if (!acc[day]) acc[day] = [];
      acc[day].push(t);
      return acc;
    }, {});
  }, [detail]);

  const sortedDays = Object.keys(tasksByDay).sort();

  return (
    <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 14, overflow: "hidden" }}>
      {/* Plan header */}
      <div style={{ padding: "16px 20px", cursor: "pointer" }} onClick={onToggle}>
        <div style={{ display: "flex", alignItems: "flex-start", gap: 12 }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4, flexWrap: "wrap" }}>
              <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 6, padding: "2px 10px", fontSize: 11, fontWeight: 700 }}>{periodLabel[plan.period_type]}</span>
              {plan.is_auto && <span style={{ background: "var(--line)", color: "var(--muted)", borderRadius: 6, padding: "2px 8px", fontSize: 11, fontWeight: 600 }}>Auto</span>}
              <span style={{ fontSize: 12, color: "var(--muted)" }}>{fmtDate(plan.period_start)} – {fmtDate(plan.period_end)}</span>
            </div>
            <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 4 }}>{plan.title}</div>
            <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
              <span style={{ fontSize: 13, color: "var(--muted)" }}>{plan.task_count} task{plan.task_count !== 1 ? "s" : ""} · {plan.completed_count} completed</span>
              {/* Progress bar */}
              <div style={{ flex: 1, maxWidth: 160, height: 6, background: "var(--line)", borderRadius: 3, overflow: "hidden" }}>
                <div style={{ height: "100%", width: `${pct}%`, background: pct === 100 ? "var(--good)" : "var(--accent)", borderRadius: 3, transition: "width .3s" }} />
              </div>
              <span style={{ fontSize: 12, color: "var(--muted)" }}>{pct}%</span>
            </div>
          </div>
          <div style={{ display: "flex", gap: 8, alignItems: "center", flexShrink: 0 }} onClick={e => e.stopPropagation()}>
            <button onClick={onRegenerate} style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 12px", fontSize: 12, cursor: "pointer", color: "var(--ink)", fontWeight: 600 }}>Regenerate</button>
            <button onClick={onDelete} style={{ background: "none", border: "1px solid var(--bad)", borderRadius: 6, padding: "5px 10px", fontSize: 12, cursor: "pointer", color: "var(--bad)" }}>Delete</button>
            <span style={{ fontSize: 18, color: "var(--muted)", userSelect: "none" }}>{expanded ? "▲" : "▼"}</span>
          </div>
        </div>
      </div>

      {/* Expanded tasks */}
      {expanded && (
        <div style={{ borderTop: "1px solid var(--line)" }}>
          {loadingDetail ? (
            <div style={{ padding: 24, color: "var(--muted)", fontSize: 13 }}>Loading tasks…</div>
          ) : detail?.summary ? (
            <div>
              <div style={{ padding: "12px 20px", background: "var(--panel-2)", fontSize: 13, color: "var(--muted)", lineHeight: 1.6, borderBottom: "1px solid var(--line)" }}>
                {detail.summary}
              </div>
              {/* Task table header */}
              <div style={{ display: "grid", gridTemplateColumns: "90px 1fr 120px 120px 110px 80px 120px", padding: "8px 20px", background: "var(--panel-2)", borderBottom: "1px solid var(--line)", fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>
                <div>Effort</div>
                <div>Task</div>
                <div>Platform</div>
                <div>Scheduled</div>
                <div>Status</div>
                <div style={{ textAlign: "right" }}>Media</div>
                <div style={{ textAlign: "right" }}>Action</div>
              </div>
              {sortedDays.map(day => (
                <div key={day}>
                  {/* Day group header */}
                  <div
                    onClick={() => onToggleDay(day)}
                    style={{ padding: "9px 20px", background: "var(--panel-2)", fontWeight: 700, fontSize: 13, cursor: "pointer", display: "flex", alignItems: "center", gap: 8, borderBottom: "1px solid var(--line-2)", userSelect: "none" }}
                  >
                    <span style={{ color: "var(--accent)" }}>
                      {day === "unscheduled" ? "Unscheduled" : new Date(day + "T12:00:00").toLocaleDateString(undefined, { weekday: "short", month: "short", day: "numeric" })}
                    </span>
                    <span style={{ fontWeight: 400, color: "var(--muted)", fontSize: 12 }}>{tasksByDay[day].length} task{tasksByDay[day].length !== 1 ? "s" : ""}</span>
                    <span style={{ marginLeft: "auto", fontSize: 14, color: "var(--muted)" }}>{expandedDays[day] === false ? "▶" : "▼"}</span>
                  </div>
                  {/* Tasks — collapsed by default only if explicitly set false */}
                  {expandedDays[day] !== false && tasksByDay[day].map((task, i) => (
                    <PlanTaskRow
                      key={task.id}
                      task={task}
                      workspaceId={workspaceId}
                      planId={plan.id}
                      isLast={i === tasksByDay[day].length - 1 && day === sortedDays[sortedDays.length - 1]}
                      onUpdate={() => {
                        api.tcall("getWorkspacePlan", { workspaceId, planId: plan.id }).then(r => setDetail(r)).catch(() => {});
                        onTaskUpdate();
                      }}
                    />
                  ))}
                </div>
              ))}
            </div>
          ) : (
            <div style={{ padding: 24, color: "var(--muted)", fontSize: 13 }}>No tasks in this plan.</div>
          )}
        </div>
      )}
    </div>
  );
}

function PlanTaskRow({ task, workspaceId, planId, isLast, onUpdate }) {
  const [status, setStatus] = React.useState(task.status);
  const [generatingMedia, setGeneratingMedia] = React.useState(false);
  const [mediaUrl, setMediaUrl] = React.useState(task.generated_media_url || "");
  const [showAddModal, setShowAddModal] = React.useState(false);

  const effortStyle = { low: ["var(--good-soft)", "var(--good)", "LOW"], medium: ["var(--warn-soft)", "var(--warn)", "MED"], high: ["#fef2f2", "var(--bad)", "HIGH"] };
  const statusColor = { pending: "var(--muted)", in_progress: "var(--warn)", completed: "var(--good)", skipped: "var(--muted-2)" };
  const [effortBg, effortClr, effortTxt] = effortStyle[task.effort] || effortStyle.medium;

  const updateStatus = async (newStatus) => {
    setStatus(newStatus);
    await api.tcall("updatePlanTask", { workspaceId, planId, taskId: task.id }, { status: newStatus }).catch(() => {});
    onUpdate();
  };

  const triggerMedia = async () => {
    setGeneratingMedia(true);
    await api.tcall("generateTaskMedia", { workspaceId, planId, taskId: task.id }).catch(() => {});
    // Poll for result
    let attempts = 0;
    const poll = async () => {
      await new Promise(r => setTimeout(r, 3000));
      const plan = await api.tcall("getWorkspacePlan", { workspaceId, planId }).catch(() => null);
      if (plan) {
        const t = plan.tasks?.find(t => t.id === task.id);
        if (t?.generated_media_url) { setMediaUrl(t.generated_media_url); setGeneratingMedia(false); return; }
        if (t?.generated_text && !t?.generated_media_url) { setMediaUrl("text"); setGeneratingMedia(false); return; }
      }
      attempts++;
      if (attempts < 15) setTimeout(poll, 3000);
      else setGeneratingMedia(false);
    };
    poll();
  };

  const contentIcon = { article: "📄", social_post: "💬", image: "🖼️", video_script: "🎬", web_copy: "🌐", press_release: "📰" };

  return (
    <>
    <div style={{ display: "grid", gridTemplateColumns: "90px 1fr 120px 120px 110px 80px 120px", alignItems: "center", padding: "10px 20px", borderBottom: isLast ? "none" : "1px solid var(--line-2)", background: "var(--panel)" }}>
      <div>
        <span style={{ background: effortBg, color: effortClr, borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700 }}>{effortTxt}</span>
      </div>
      <div style={{ paddingRight: 12 }}>
        <div style={{ fontWeight: 600, fontSize: 13, lineHeight: 1.3 }}>{task.title}</div>
        {task.description && <div style={{ fontSize: 11, color: "var(--muted)", marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: 360 }}>{task.description}</div>}
        {(mediaUrl && mediaUrl !== "text") && (
          <a href={mediaUrl} target="_blank" rel="noopener noreferrer" style={{ fontSize: 11, color: "var(--accent)", display: "block", marginTop: 3, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", maxWidth: 360 }}>View generated media →</a>
        )}
        {mediaUrl === "text" && <span style={{ fontSize: 11, color: "var(--good)", display: "block", marginTop: 3 }}>Text content generated</span>}
      </div>
      <div style={{ fontSize: 12 }}>
        {task.content_type && (
          <span style={{ display: "flex", alignItems: "center", gap: 4 }}>
            <span>{contentIcon[task.content_type] || "📋"}</span>
            <span style={{ color: "var(--muted)" }}>{task.target_platform || task.content_type?.replace("_", " ")}</span>
          </span>
        )}
      </div>
      <div style={{ fontSize: 12, color: "var(--muted)" }}>
        {task.scheduled_date ? new Date(task.scheduled_date + "T12:00:00").toLocaleDateString(undefined, { month: "short", day: "numeric" }) : "—"}
      </div>
      <div>
        <select
          value={status}
          onChange={e => updateStatus(e.target.value)}
          style={{ fontSize: 12, padding: "4px 8px", borderRadius: 6, border: "1px solid var(--line)", background: "var(--panel)", color: statusColor[status] || "var(--muted)", fontWeight: 600, cursor: "pointer", width: "100%" }}
        >
          <option value="pending">Pending</option>
          <option value="in_progress">In Progress</option>
          <option value="completed">Done</option>
          <option value="skipped">Skip</option>
        </select>
      </div>
      <div style={{ display: "flex", justifyContent: "flex-end" }}>
        {!mediaUrl ? (
          <button
            onClick={triggerMedia}
            disabled={generatingMedia}
            title="Generate media for this task"
            style={{ background: generatingMedia ? "var(--line)" : "var(--accent-soft)", color: generatingMedia ? "var(--muted)" : "var(--accent)", border: "none", borderRadius: 6, padding: "5px 9px", fontSize: 13, cursor: generatingMedia ? "not-allowed" : "pointer" }}
          >{generatingMedia ? "⟳" : "🎨"}</button>
        ) : (
          <span style={{ fontSize: 16 }} title="Media ready">✅</span>
        )}
      </div>
      <div style={{ display: "flex", justifyContent: "flex-end" }}>
        <button
          onClick={() => setShowAddModal(true)}
          style={{ background: "var(--accent-soft)", color: "var(--accent)", border: "1px solid var(--accent)", borderRadius: 6, padding: "4px 10px", fontSize: 11, fontWeight: 700, cursor: "pointer", whiteSpace: "nowrap" }}
        >+ Add to Tasks</button>
      </div>
    </div>
    {showAddModal && (
      <AddToTasksModal
        workspaceId={workspaceId}
        sourceType="manual"
        title={task.title}
        description={task.description || ""}
        onClose={() => setShowAddModal(false)}
        onSaved={() => { setShowAddModal(false); window.__toast && window.__toast("Task added to workspace tasks"); }}
      />
    )}
    </>
  );
}

function PlanGenerateModal({ workspaceId, generating, onGenerate, onClose }) {
  const [periodType, setPeriodType] = React.useState("weekly");
  const [periodStart, setPeriodStart] = React.useState(() => {
    // Default to nearest Monday
    const d = new Date();
    const day = d.getDay();
    const diff = day === 0 ? 1 : (day === 1 ? 0 : 8 - day);
    d.setDate(d.getDate() + diff);
    return d.toISOString().slice(0, 10);
  });

  const periodHelp = {
    daily:   "Generates tasks for a single day.",
    weekly:  "Generates 7 days of tasks with 60% low / 30% medium / 10% high effort mix.",
    monthly: "Generates a full month of tasks spread evenly across 4 weeks.",
  };

  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,.5)", zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center" }}>
      <div style={{ background: "var(--panel)", borderRadius: 16, padding: 28, width: 460, boxShadow: "var(--shadow-modal)" }}>
        <div style={{ fontWeight: 700, fontSize: 18, marginBottom: 4 }}>Generate AI Plan</div>
        <div style={{ fontSize: 13, color: "var(--muted)", marginBottom: 20 }}>
          AI will create a structured action calendar from gap recommendations using a 60/30/10 effort distribution.
        </div>

        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 8 }}>Period Type</label>
            <div style={{ display: "flex", gap: 8 }}>
              {["daily", "weekly", "monthly"].map(p => (
                <button key={p} onClick={() => setPeriodType(p)}
                  style={{ flex: 1, background: periodType === p ? "var(--accent)" : "var(--line)", color: periodType === p ? "var(--accent-ink)" : "var(--muted)", border: "none", borderRadius: 8, padding: "9px", fontWeight: 600, cursor: "pointer", fontSize: 13, textTransform: "capitalize" }}>
                  {p}
                </button>
              ))}
            </div>
            <div style={{ fontSize: 12, color: "var(--muted)", marginTop: 8 }}>{periodHelp[periodType]}</div>
          </div>

          <div>
            <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 8 }}>
              {periodType === "daily" ? "Date" : periodType === "weekly" ? "Week Start (Monday)" : "Month Start (1st)"}
            </label>
            <input
              type="date"
              value={periodStart}
              onChange={e => setPeriodStart(e.target.value)}
              style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)", boxSizing: "border-box" }}
            />
          </div>
        </div>

        <div style={{ display: "flex", gap: 10, marginTop: 24 }}>
          <button
            onClick={() => onGenerate(periodType, periodStart + "T00:00:00Z")}
            disabled={generating || !periodStart}
            style={{ flex: 1, background: generating ? "var(--line)" : "var(--accent)", color: generating ? "var(--muted)" : "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px", fontWeight: 700, cursor: generating ? "not-allowed" : "pointer", fontSize: 14 }}
          >{generating ? "Generating… (may take 15–30s)" : "Generate Plan"}</button>
          <button onClick={onClose} disabled={generating}
            style={{ background: "none", border: "1px solid var(--line)", borderRadius: 8, padding: "12px 20px", cursor: "pointer", color: "var(--muted)" }}>
            Cancel
          </button>
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Tab: Actions (content generation + publishing)
// ---------------------------------------------------------------------------
function WorkspaceActionsTab({ workspaceId }) {
  const [recs, setRecs] = React.useState([]);
  const [actions, setActions] = React.useState([]);
  const [selectedRec, setSelectedRec] = React.useState(null);
  const [generating, setGenerating] = React.useState(null);
  const [publishing, setPublishing] = React.useState(null);
  const [loading, setLoading] = React.useState(true);

  React.useEffect(() => {
    Promise.all([
      api.tcall("workspaceRecommendations", { workspaceId }),
      api.tcall("listWorkspaceActions", { workspaceId }),
    ]).then(([r, a]) => {
      setRecs(r || []);
      setActions(a || []);
      setLoading(false);
    }).catch(() => setLoading(false));
  }, [workspaceId]);

  const createAction = async (recId, contentType) => {
    const action = await api.tcall("createContentAction", { workspaceId, recId }, { content_type: contentType });
    setActions(prev => [...prev, action]);
    return action;
  };

  const generate = async (action) => {
    setGenerating(action.id);
    try {
      const updated = await api.tcall("generateContent", { workspaceId, recId: action.recommendation_id, actionId: action.id });
      setActions(prev => prev.map(a => a.id === action.id ? updated : a));
    } catch (e) {}
    setGenerating(null);
  };

  const publish = async (action) => {
    setPublishing(action.id);
    try {
      const updated = await api.tcall("publishContent", { workspaceId, recId: action.recommendation_id, actionId: action.id });
      setActions(prev => prev.map(a => a.id === action.id ? updated : a));
    } catch (e) {}
    setPublishing(null);
  };

  const statusColor = { draft: "muted", generating: "warn", generated: "info-ink", publishing: "warn", published: "good", email_sent: "good", failed: "bad" };

  if (loading) return <div style={{ color: "var(--muted)", padding: 24 }}>Loading…</div>;

  return (
    <div>
      {/* Quick-create action from rec */}
      <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 20, marginBottom: 24 }}>
        <div style={{ fontWeight: 700, fontSize: 15, marginBottom: 12 }}>Create Content Action</div>
        <div style={{ display: "flex", gap: 10 }}>
          <select
            value={selectedRec || ""}
            onChange={e => setSelectedRec(e.target.value)}
            style={{ flex: 2, padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
          >
            <option value="">Select recommendation…</option>
            {recs.map(r => <option key={r.id} value={r.id}>{r.title}</option>)}
          </select>
          {["article", "social_post", "web_copy"].map(ct => (
            <button
              key={ct}
              disabled={!selectedRec}
              onClick={() => createAction(selectedRec, ct)}
              style={{ background: "var(--accent-soft)", color: "var(--accent)", border: "1px solid var(--accent)", borderRadius: 8, padding: "8px 14px", fontSize: 13, fontWeight: 600, cursor: selectedRec ? "pointer" : "not-allowed", opacity: selectedRec ? 1 : 0.5 }}
            >{ct.replace("_", " ")}</button>
          ))}
        </div>
      </div>

      {/* Actions table */}
      {actions.length === 0 ? (
        <div style={{ textAlign: "center", padding: 48, color: "var(--muted)" }}>
          <div>No content actions yet. Create one from a recommendation above.</div>
        </div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
          {actions.map(action => (
            <div key={action.id} style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 10, padding: "16px 20px" }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: action.generated_text ? 10 : 0 }}>
                <span style={{ fontSize: 13, fontWeight: 600 }}>{action.content_type?.replace("_", " ")}</span>
                <span style={{
                  fontSize: 11, fontWeight: 700, borderRadius: 4, padding: "2px 7px",
                  background: `var(--${statusColor[action.publish_status] || "muted"}-soft, var(--line))`,
                  color: `var(--${statusColor[action.publish_status] || "muted"})`
                }}>{action.publish_status}</span>
                {action.publish_url && (
                  <a href={action.publish_url} target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: "var(--accent)", marginLeft: 4 }}>View →</a>
                )}
                <div style={{ marginLeft: "auto", display: "flex", gap: 8 }}>
                  {!action.generated_text && (
                    <button
                      onClick={() => generate(action)}
                      disabled={generating === action.id}
                      style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}
                    >{generating === action.id ? "Generating…" : "Generate"}</button>
                  )}
                  {action.generated_text && action.publish_status !== "published" && (
                    <button
                      onClick={() => publish(action)}
                      disabled={publishing === action.id}
                      style={{ background: "var(--good)", color: "#fff", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}
                    >{publishing === action.id ? "Publishing…" : "Publish"}</button>
                  )}
                </div>
              </div>
              {action.generated_text && (
                <div style={{ fontSize: 13, color: "var(--muted)", background: "var(--panel-2)", borderRadius: 6, padding: "10px 14px", lineHeight: 1.6, maxHeight: 120, overflow: "hidden" }}>
                  {action.generated_text.slice(0, 400)}{action.generated_text.length > 400 ? "…" : ""}
                </div>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Tab: Authority — credibility surfaces and proof assets for this workspace's client
// ---------------------------------------------------------------------------
function WorkspaceAuthorityTab({ workspace, workspaceId }) {
  const [surfaces, setSurfaces] = React.useState([]);
  const [assignments, setAssignments] = React.useState([]);
  const [assets, setAssets] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [activeSection, setActiveSection] = React.useState("surfaces");

  React.useEffect(() => {
    Promise.all([
      api.tcall("listAuthoritySurfaces").catch(() => []),
      api.tcall("listSurfaceAssignments").catch(() => []),
      api.tcall("listProofAssets").catch(() => []),
    ]).then(([s, a, p]) => {
      setSurfaces(s || []);
      setAssignments(a || []);
      setAssets(p || []);
      setLoading(false);
    });
  }, [workspaceId]);

  const statusColor = {
    active: ["var(--good-soft)", "var(--good)"],
    pending: ["var(--warn-soft)", "var(--warn)"],
    inactive: ["var(--line)", "var(--muted)"],
    draft: ["var(--line)", "var(--muted)"],
    published: ["var(--good-soft)", "var(--good)"],
    in_review: ["var(--warn-soft)", "var(--warn)"],
  };

  const badge = (status) => {
    const [bg, color] = statusColor[status] || ["var(--line)", "var(--muted)"];
    return (
      <span style={{ background: bg, color, borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700 }}>
        {status?.replace("_", " ")}
      </span>
    );
  };

  if (loading) return <div style={{ color: "var(--muted)", padding: 24 }}>Loading authority data…</div>;

  const sections = [
    { id: "surfaces", label: `Surfaces (${surfaces.length})` },
    { id: "assignments", label: `Assignments (${assignments.length})` },
    { id: "assets", label: `Proof Assets (${assets.length})` },
  ];

  return (
    <div>
      <div style={{ marginBottom: 20 }}>
        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 4 }}>Authority Profile</div>
        <div style={{ fontSize: 13, color: "var(--muted)" }}>
          Credibility surfaces, content assignments, and proof assets for <b>{workspace?.client_company_name}</b>.
        </div>
      </div>

      {/* Section tabs */}
      <div style={{ display: "flex", gap: 6, marginBottom: 20, borderBottom: "1px solid var(--line)", paddingBottom: 0 }}>
        {sections.map(s => (
          <button key={s.id} onClick={() => setActiveSection(s.id)}
            style={{
              background: "none", border: "none", cursor: "pointer", padding: "8px 16px",
              fontWeight: activeSection === s.id ? 700 : 500,
              color: activeSection === s.id ? "var(--accent)" : "var(--muted)",
              borderBottom: activeSection === s.id ? "2px solid var(--accent)" : "2px solid transparent",
              fontSize: 13, marginBottom: -1,
            }}>{s.label}</button>
        ))}
      </div>

      {/* Surfaces */}
      {activeSection === "surfaces" && (
        surfaces.length === 0 ? (
          <div style={{ textAlign: "center", padding: 48, color: "var(--muted)" }}>
            <div style={{ fontSize: 28, marginBottom: 10 }}>🏛️</div>
            <div style={{ fontWeight: 600 }}>No authority surfaces yet</div>
            <div style={{ fontSize: 13, marginTop: 6 }}>Authority surfaces define the credibility channels for this brand (press, awards, certifications, etc.).</div>
          </div>
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {surfaces.map(s => (
              <div key={s.id} style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 10, padding: "14px 18px", display: "flex", alignItems: "center", gap: 14 }}>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, marginBottom: 3 }}>{s.name || s.surface_type}</div>
                  {s.description && <div style={{ fontSize: 13, color: "var(--muted)" }}>{s.description}</div>}
                </div>
                <div style={{ display: "flex", gap: 8, alignItems: "center", flexShrink: 0 }}>
                  {s.weight != null && <span style={{ fontSize: 12, color: "var(--muted)" }}>Weight: {s.weight}</span>}
                  {badge(s.status || "active")}
                </div>
              </div>
            ))}
          </div>
        )
      )}

      {/* Assignments */}
      {activeSection === "assignments" && (
        assignments.length === 0 ? (
          <div style={{ textAlign: "center", padding: 48, color: "var(--muted)" }}>
            <div style={{ fontSize: 28, marginBottom: 10 }}>📋</div>
            <div style={{ fontWeight: 600 }}>No surface assignments</div>
            <div style={{ fontSize: 13, marginTop: 6 }}>Assignments map recommendations to specific authority surfaces.</div>
          </div>
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {assignments.map(a => (
              <div key={a.id} style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 10, padding: "14px 18px", display: "flex", alignItems: "center", gap: 14 }}>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, marginBottom: 3 }}>{a.surface_name || a.surface_id}</div>
                  {a.notes && <div style={{ fontSize: 13, color: "var(--muted)" }}>{a.notes}</div>}
                </div>
                {badge(a.status || "pending")}
              </div>
            ))}
          </div>
        )
      )}

      {/* Proof Assets */}
      {activeSection === "assets" && (
        assets.length === 0 ? (
          <div style={{ textAlign: "center", padding: 48, color: "var(--muted)" }}>
            <div style={{ fontSize: 28, marginBottom: 10 }}>🗂️</div>
            <div style={{ fontWeight: 600 }}>No proof assets yet</div>
            <div style={{ fontSize: 13, marginTop: 6 }}>Proof assets are the actual content pieces — articles, awards, certifications — that demonstrate authority.</div>
          </div>
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {assets.map(a => (
              <div key={a.id} style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 10, padding: "14px 18px", display: "flex", alignItems: "center", gap: 14 }}>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, marginBottom: 3 }}>{a.title || a.asset_type}</div>
                  {a.url && <a href={a.url} target="_blank" rel="noopener noreferrer" style={{ fontSize: 12, color: "var(--accent)" }}>{a.url}</a>}
                  {a.description && <div style={{ fontSize: 13, color: "var(--muted)", marginTop: 2 }}>{a.description}</div>}
                </div>
                <div style={{ display: "flex", gap: 8, alignItems: "center", flexShrink: 0 }}>
                  {a.asset_type && <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700 }}>{a.asset_type}</span>}
                  {badge(a.status || "draft")}
                </div>
              </div>
            ))}
          </div>
        )
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// WorkspaceTaskPage — standalone URL-addressable task detail page
// Route: /workspace-task?id=workspaceId__taskId
// ---------------------------------------------------------------------------
function WorkspaceTaskPage({ workspaceId, taskId }) {
  const [task, setTask] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [generating, setGenerating] = React.useState(false);
  const [sending, setSending] = React.useState(false);
  const [polling, setPolling] = React.useState(false);
  const [editingContent, setEditingContent] = React.useState(false);
  const [contentDraft, setContentDraft] = React.useState("");
  const [copied, setCopied] = React.useState(false);
  const [opening, setOpening] = React.useState(false);
  const [browserMsg, setBrowserMsg] = React.useState("");
  const [emailTo, setEmailTo] = React.useState("");
  const [emailing, setEmailing] = React.useState(false);
  const [emailMsg, setEmailMsg] = React.useState("");
  const [execMode, setExecMode] = React.useState("assisted");
  const [savingMode, setSavingMode] = React.useState(false);
  const [browserJob, setBrowserJob] = React.useState(null);
  const [mediaModel, setMediaModel] = React.useState("");
  const [mediaOptions, setMediaOptions] = React.useState([]);

  // Image/video tasks let the consultant pick the generation model.
  const mediaKind = task && (task.content_kind === "image" || task.content_kind === "video")
    ? task.content_kind : null;
  React.useEffect(() => {
    if (!mediaKind) return;
    api.tcall("listMediaModels", {})
      .then(r => setMediaOptions((r && r[mediaKind]) || []))
      .catch(() => {});
  }, [mediaKind]);

  const load = async () => {
    try {
      const t = await api.tcall("getWorkspaceTask", { workspaceId, taskId });
      setTask(t);
      setContentDraft(t?.generated_content || "");
      setExecMode(t?.execution_mode || "assisted");
      setMediaModel(t?.media_model || "");
    } catch (_) {}
    try {
      const j = await api.tcall("getTaskBrowserJob", { workspaceId, taskId });
      if (j && j.status) setBrowserJob(j);
    } catch (_) {}
    setLoading(false);
  };

  React.useEffect(() => { load(); }, [workspaceId, taskId]);

  const refreshTask = async () => {
    const t = await api.tcall("getWorkspaceTask", { workspaceId, taskId });
    if (t) { setTask(t); setContentDraft(t.generated_content || ""); setExecMode(t.execution_mode || "assisted"); setMediaModel(t.media_model || ""); }
    return t;
  };

  const setExecutionMode = async (mode) => {
    setSavingMode(true);
    setExecMode(mode);
    try { await api.tcall("updateWorkspaceTask", { workspaceId, taskId }, { execution_mode: mode }); await refreshTask(); } catch (_) {}
    setSavingMode(false);
  };

  const pollBrowserJob = () => {
    let attempts = 0;
    const poll = async () => {
      await new Promise(r => setTimeout(r, 3000));
      let j = null;
      try { j = await api.tcall("getTaskBrowserJob", { workspaceId, taskId }); } catch (_) {}
      if (j && j.status) setBrowserJob(j);
      attempts++;
      if (j && (j.status === "queued" || j.status === "running") && attempts < 40) setTimeout(poll, 3000);
    };
    poll();
  };

  const startPoll = () => {
    setPolling(true);
    let attempts = 0;
    const poll = async () => {
      await new Promise(r => setTimeout(r, 2500));
      const t = await refreshTask();
      attempts++;
      if (t && t.status === "in_progress" && attempts < 20) setTimeout(poll, 2500);
      else setPolling(false);
    };
    poll();
  };

  const generate = async () => {
    setGenerating(true);
    try {
      await api.tcall("generateTaskContent", { workspaceId, taskId },
        mediaKind ? { media_model: mediaModel || "" } : {});
      startPoll();
    } catch (_) {}
    setGenerating(false);
  };

  const send = async () => {
    setSending(true);
    try { await api.tcall("sendTask", { workspaceId, taskId }); startPoll(); } catch (_) {}
    setSending(false);
  };

  const openBrowser = async () => {
    setOpening(true);
    setBrowserMsg("");
    try {
      await api.tcall("openTaskBrowser", { workspaceId, taskId });
      setBrowserMsg("");
      setBrowserJob({ status: "queued" });
      pollBrowserJob();
    } catch (e) {
      setBrowserMsg(e.message || "Could not open the browser.");
    }
    setOpening(false);
  };

  const emailContent = async () => {
    if (!emailTo.trim()) { setEmailMsg("Enter at least one recipient email."); return; }
    setEmailing(true);
    setEmailMsg("");
    try {
      const r = await api.tcall("emailTask", { workspaceId, taskId }, { to_email: emailTo, subject: task.title });
      setEmailMsg((r && r.message) || "Email sent.");
      if (r && r.ok) setEmailTo("");
    } catch (e) {
      setEmailMsg(e.message || "Could not send email.");
    }
    setEmailing(false);
  };

  const downloadContent = () => {
    const blob = new Blob([task.generated_content || ""], { type: "text/plain" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `${(task.title || "task").replace(/[^a-z0-9]/gi, "_").toLowerCase()}.txt`;
    a.click();
    URL.revokeObjectURL(url);
  };

  const copyContent = () => {
    if (task?.generated_content) {
      navigator.clipboard.writeText(task.generated_content).catch(() => {});
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }
  };

  if (loading) return <div style={{ padding: 48, color: "var(--muted)" }}>Loading task…</div>;
  if (!task) return <div style={{ padding: 48, color: "var(--bad)" }}>Task not found.</div>;

  const hasContent = !!task.generated_content;
  const isPending  = task.status === "pending" || task.status === "in_progress";
  const statusColor = { pending: "var(--muted)", in_progress: "var(--warn)", completed: "var(--good)", failed: "var(--bad)" };
  const srcLabel = { recommendation: "AI Recommendation", peer_event: "Peer Insight", manual: "Manual" };

  const Section = ({ title, children }) => (
    <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, marginBottom: 16, overflow: "hidden" }}>
      <div style={{ padding: "11px 20px", borderBottom: "1px solid var(--line)", fontWeight: 700, fontSize: 12, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.06em", background: "var(--panel-2)" }}>{title}</div>
      <div style={{ padding: "18px 20px" }}>{children}</div>
    </div>
  );

  return (
    <div style={{ padding: "var(--pad)", maxWidth: 860 }}>
      {/* Back link */}
      <button
        onClick={() => window.__nav("client-detail", workspaceId)}
        style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", fontSize: 13, padding: 0, marginBottom: 20 }}
      >← Back to Workspace</button>

      {/* Header */}
      <div style={{ marginBottom: 24 }}>
        <div style={{ fontSize: 12, color: "var(--muted)", marginBottom: 6 }}>
          {srcLabel[task.source_type] || task.source_type}
          {task.platform && <span style={{ marginLeft: 8, background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 4, padding: "1px 8px", fontWeight: 700, fontSize: 11 }}>{task.platform.replace(/_/g, " ")}</span>}
        </div>
        <div style={{ display: "flex", alignItems: "flex-start", gap: 12, flexWrap: "wrap" }}>
          <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0, flex: 1 }}>{task.title}</h1>
          <span style={{
            background: task.status === "completed" ? "var(--good-soft)" : task.status === "failed" ? "#fef2f2" : task.status === "in_progress" ? "var(--warn-soft)" : "var(--line)",
            color: statusColor[task.status] || "var(--muted)",
            borderRadius: 8, padding: "5px 14px", fontSize: 13, fontWeight: 700, whiteSpace: "nowrap",
          }}>{task.status?.replace("_", " ")}</span>
          {polling && <span style={{ fontSize: 13, color: "var(--warn)", fontWeight: 600, display: "flex", alignItems: "center" }}>⟳ Processing…</span>}
        </div>
      </div>

      {/* Description */}
      {task.description && (
        <Section title="Brief">
          <div style={{ fontSize: 14, color: "var(--ink-2)", lineHeight: 1.8 }}>{task.description}</div>
        </Section>
      )}

      {/* AI Prompt */}
      {task.ai_prompt && (
        <Section title="AI Prompt Used">
          <div style={{ fontFamily: "var(--mono)", fontSize: 13, color: "var(--muted)", lineHeight: 1.6, whiteSpace: "pre-wrap", background: "var(--panel-2)", borderRadius: 8, padding: "12px 14px" }}>
            {task.ai_prompt}
          </div>
        </Section>
      )}

      {/* Execution mode — AI independent vs consultant-assisted */}
      <Section title="Execution">
        {(() => {
          const isBrowser = ["linkedin_post","linkedin_video","linkedin_image","medium_article",
            "facebook_post","facebook_image","twitter_thread","twitter_image"].includes(task.platform || "");
          const modeBtn = (val, label) => (
            <button key={val} disabled={savingMode} onClick={() => setExecutionMode(val)}
              style={{
                flex: 1, padding: "10px 14px", borderRadius: 8, fontSize: 13, fontWeight: 700, cursor: "pointer",
                border: execMode === val ? "1px solid var(--accent)" : "1px solid var(--line)",
                background: execMode === val ? "var(--accent-soft)" : "var(--panel-2)",
                color: execMode === val ? "var(--accent)" : "var(--ink)",
              }}>{label}</button>
          );
          return (
            <div>
              <div style={{ display: "flex", gap: 10, marginBottom: 10 }}>
                {modeBtn("assisted", "🧑 Consultant posts")}
                {modeBtn("ai_auto", "🤖 AI auto-publishes")}
              </div>
              <div style={{ fontSize: 12.5, color: "var(--muted)", lineHeight: 1.6 }}>
                {execMode === "ai_auto"
                  ? (isBrowser
                      ? "This is a social/browser platform — it always needs your logged-in session, so AI will draft it and you post it (auto-publish doesn't apply here)."
                      : "AI publishes this automatically right after generation (own site / API / email). No manual step needed.")
                  : "AI drafts the content; you review and publish it yourself (incl. social platforms via your own Chrome)."}
              </div>
              <div style={{ marginTop: 12, display: "flex", gap: 8, flexWrap: "wrap", fontSize: 11.5, color: "var(--muted-2)" }}>
                <span style={{ background: "var(--panel-2)", borderRadius: 6, padding: "3px 10px" }}>Language: <b style={{ color: "var(--ink)" }}>{task.language || "English"}</b></span>
                <span style={{ background: "var(--panel-2)", borderRadius: 6, padding: "3px 10px" }}>Route: <b style={{ color: "var(--ink)" }}>{task.publisher_name || (task.platform ? task.platform.replace(/_/g, " ") : "own site")}</b></span>
                {task.generated_at && <span style={{ background: "var(--panel-2)", borderRadius: 6, padding: "3px 10px" }}>Generated: <b style={{ color: "var(--ink)" }}>{new Date(task.generated_at).toLocaleString()}</b></span>}
              </div>
            </div>
          );
        })()}
      </Section>

      {/* Generated Content */}
      <Section title="Generated Content">
        {!hasContent && isPending && (
          <div>
            <div style={{ fontSize: 14, color: "var(--muted)", marginBottom: 16 }}>AI will generate publication-ready content for this task. Review before sending.</div>
            {mediaKind && (
              <div style={{ marginBottom: 16, maxWidth: 360 }}>
                <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5 }}>
                  {mediaKind === "image" ? "Image model" : "Video model"}
                </label>
                <select
                  value={mediaModel}
                  onChange={e => setMediaModel(e.target.value)}
                  disabled={generating || polling}
                  style={{ width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
                >
                  <option value="">Auto (recommended)</option>
                  {mediaOptions.map(m => <option key={m.slug} value={m.slug}>{m.label}</option>)}
                </select>
              </div>
            )}
            <button
              onClick={generate}
              disabled={generating || polling}
              style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px 24px", fontWeight: 700, cursor: "pointer", fontSize: 14 }}
            >{generating || polling ? "Generating…" : "Generate Content"}</button>
          </div>
        )}
        {!hasContent && !isPending && <div style={{ color: "var(--muted)", fontSize: 14 }}>No content generated yet.</div>}
        {hasContent && (
          <div>
            <div style={{ display: "flex", gap: 8, marginBottom: 12, flexWrap: "wrap" }}>
              <button onClick={copyContent} style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
                {copied ? "Copied!" : "Copy"}
              </button>
              <button onClick={() => { setEditingContent(!editingContent); setContentDraft(task.generated_content); }}
                style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
                {editingContent ? "Cancel Edit" : "Edit"}
              </button>
              <button onClick={downloadContent}
                style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
                Download .txt
              </button>
              {task.generated_at && (
                <span style={{ fontSize: 11, color: "var(--muted-2)", display: "flex", alignItems: "center", marginLeft: 4 }}>
                  Generated {new Date(task.generated_at).toLocaleString()}
                </span>
              )}
            </div>
            {editingContent ? (
              <textarea
                value={contentDraft}
                onChange={e => setContentDraft(e.target.value)}
                rows={14}
                style={{ width: "100%", padding: "12px 14px", borderRadius: 8, border: "1px solid var(--accent)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)", lineHeight: 1.7, resize: "vertical", boxSizing: "border-box" }}
              />
            ) : (
              <div style={{ background: "var(--panel-2)", borderRadius: 8, padding: "14px 16px", fontSize: 14, lineHeight: 1.8, color: "var(--ink-2)", whiteSpace: "pre-wrap" }}>
                {task.generated_content}
              </div>
            )}
          </div>
        )}
      </Section>

      {/* Actions */}
      <Section title="Actions">
        {hasContent && (
          <div style={{ display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap" }}>
            <button onClick={copyContent} style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
              {copied ? "Copied!" : "Copy"}
            </button>
            <button onClick={() => { setEditingContent(!editingContent); setContentDraft(task.generated_content); }}
              style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
              {editingContent ? "Cancel Edit" : "Edit"}
            </button>
            <button onClick={downloadContent} style={{ background: "var(--line)", border: "none", borderRadius: 6, padding: "6px 14px", fontSize: 12, fontWeight: 600, cursor: "pointer", color: "var(--ink)" }}>
              Download .txt
            </button>
          </div>
        )}
        {task.target_email && (
          <div style={{ background: "var(--panel-2)", borderRadius: 8, padding: "10px 14px", marginBottom: 16, fontSize: 13 }}>
            <span style={{ color: "var(--muted)" }}>Send to:</span> <b>{task.target_email}</b>
            {task.publisher_name && <span style={{ color: "var(--muted)", marginLeft: 8 }}>via {task.publisher_name}</span>}
          </div>
        )}
        <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
          {task.executor_type === "external_api" && (
            <button onClick={send} disabled={!hasContent || sending || polling || task.status === "completed"}
              style={{ background: hasContent && !sending ? "var(--accent)" : "var(--line)", color: hasContent && !sending ? "var(--accent-ink)" : "var(--muted)", border: "none", borderRadius: 8, padding: "10px 20px", fontWeight: 700, cursor: "pointer", fontSize: 13 }}>
              {sending ? "Publishing…" : "Publish via API"}
            </button>
          )}
          {(task.executor_type === "external_email" || task.executor_type === "email" || task.target_email) && (
            <button onClick={send} disabled={!hasContent || sending || polling || task.status === "completed"}
              style={{ background: hasContent && !sending ? "#128a5b" : "var(--line)", color: hasContent && !sending ? "#fff" : "var(--muted)", border: "none", borderRadius: 8, padding: "10px 20px", fontWeight: 700, cursor: "pointer", fontSize: 13 }}>
              {sending ? "Sending…" : "Send Email"}
            </button>
          )}
          <button onClick={openBrowser} disabled={!hasContent || opening}
            style={{ background: hasContent && !opening ? "#0a66c2" : "var(--line)", color: hasContent && !opening ? "#fff" : "var(--muted)", border: "none", borderRadius: 8, padding: "10px 20px", fontWeight: 700, cursor: hasContent ? "pointer" : "not-allowed", fontSize: 13, opacity: hasContent ? 1 : 0.5 }}>
            {opening ? "Opening…" : "Open Browser & Add Content"}
          </button>
          <button onClick={() => refreshTask()}
            style={{ background: "var(--line)", border: "none", borderRadius: 8, padding: "10px 20px", cursor: "pointer", color: "var(--ink)", fontWeight: 600, fontSize: 13 }}>
            Refresh
          </button>
        </div>

        {/* Email content to client-specific address(es) */}
        <div style={{ marginTop: 18, paddingTop: 16, borderTop: "1px solid var(--line)" }}>
          <label style={{ display: "block", fontWeight: 600, fontSize: 13, marginBottom: 6 }}>
            Email content to client
            <span style={{ fontWeight: 400, color: "var(--muted)", marginLeft: 6 }}>(comma-separate multiple addresses)</span>
          </label>
          <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
            <input
              type="text"
              value={emailTo}
              onChange={e => setEmailTo(e.target.value)}
              placeholder="client@company.com, marketing@company.com"
              disabled={!hasContent}
              style={{ flex: 1, minWidth: 220, padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" }}
            />
            <button onClick={emailContent} disabled={!hasContent || emailing || !emailTo.trim()}
              style={{ background: hasContent && !emailing && emailTo.trim() ? "#128a5b" : "var(--line)", color: hasContent && !emailing && emailTo.trim() ? "#fff" : "var(--muted)", border: "none", borderRadius: 8, padding: "10px 20px", fontWeight: 700, cursor: hasContent && emailTo.trim() ? "pointer" : "not-allowed", fontSize: 13 }}>
              {emailing ? "Sending…" : "Send as Email"}
            </button>
          </div>
          {emailMsg && <div style={{ marginTop: 8, fontSize: 13, color: "var(--muted)" }}>{emailMsg}</div>}
        </div>

        {browserMsg && (
          <div style={{ marginTop: 12, background: "var(--panel-2)", borderRadius: 8, padding: "10px 14px", fontSize: 13, color: "var(--muted)" }}>
            {browserMsg}
          </div>
        )}

        {browserJob && browserJob.status && (() => {
          const map = {
            queued:  { c: "var(--warn)", bg: "var(--warn-soft)", t: "Queued for your host agent" },
            running: { c: "var(--warn)", bg: "var(--warn-soft)", t: "Running on your machine — Chrome is opening…" },
            done:    { c: "var(--good)", bg: "var(--good-soft)", t: "Opened in your Chrome — review and click Post." },
            failed:  { c: "var(--bad)",  bg: "#fef2f2",          t: "Host agent failed" },
          };
          const s = map[browserJob.status] || map.queued;
          return (
            <div style={{ marginTop: 12, background: s.bg, borderRadius: 8, padding: "10px 14px", fontSize: 13, color: s.c, border: `1px solid ${s.c}` }}>
              <b>{s.t}</b>
              {(browserJob.status === "queued" || browserJob.status === "running") && (
                <div style={{ marginTop: 4, color: "var(--muted)", fontFamily: "var(--mono)", fontSize: 11.5 }}>
                  Run on your Mac (Chrome installed, normal Chrome quit):{" "}
                  <code>python -m app.cli.host_agent</code>
                </div>
              )}
              {browserJob.status === "failed" && browserJob.detail && (
                <div style={{ marginTop: 4, color: "var(--muted)", fontSize: 12 }}>{browserJob.detail}</div>
              )}
            </div>
          );
        })()}
        {task.status === "completed" && task.completed_by_name && (
          <div style={{ marginTop: 16, background: "var(--good-soft)", borderRadius: 8, padding: "12px 16px", border: "1px solid var(--good)" }}>
            <div style={{ fontWeight: 700, color: "var(--good)", fontSize: 13, marginBottom: 4 }}>Published</div>
            <div style={{ fontSize: 13, color: "var(--ink-2)" }}>
              By: <b>{task.completed_by_name}</b>
              {task.completed_at && <span> · {new Date(task.completed_at).toLocaleString()}</span>}
              {task.completed_url && <> · <a href={task.completed_url} target="_blank" rel="noopener noreferrer" style={{ color: "var(--accent)" }}>{task.completed_url}</a></>}
            </div>
          </div>
        )}
        {task.status === "in_progress" && task.completion_token && !polling && (
          <div style={{ marginTop: 14, background: "var(--warn-soft)", borderRadius: 8, padding: "10px 14px", border: "1px solid var(--warn)", fontSize: 13, color: "var(--warn)" }}>
            Email sent · awaiting publisher confirmation
          </div>
        )}
      </Section>
    </div>
  );
}

// ---------------------------------------------------------------------------
// ClientOverviewScreen — full client overview: scores, peers, workspaces, tasks
// Route: /client-overview?id=tenantId
// ---------------------------------------------------------------------------
function ClientOverviewScreen({ tenantId }) {
  const [workspaces, setWorkspaces] = React.useState([]);
  const [benchmark, setBenchmark] = React.useState([]);
  const [allTasks, setAllTasks] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [clientName, setClientName] = React.useState("");

  React.useEffect(() => {
    if (!tenantId) return;
    window.session.setTenant(tenantId);

    const load = async () => {
      try {
        // Load workspaces
        const wsList = await api.tcall("listWorkspaces").catch(() => []);
        setWorkspaces(wsList || []);

        // Try to get client name from first workspace
        if (wsList && wsList.length > 0) {
          setClientName(wsList[0].client_company_name || "");
        }

        // Load benchmark from most-recently-refreshed workspace
        const sorted = [...(wsList || [])].sort((a, b) => {
          if (!a.last_refreshed_at) return 1;
          if (!b.last_refreshed_at) return -1;
          return new Date(b.last_refreshed_at) - new Date(a.last_refreshed_at);
        });
        if (sorted.length > 0) {
          const bench = await api.tcall("workspaceBenchmark", { workspaceId: sorted[0].id }).catch(() => []);
          setBenchmark(bench || []);
        }

        // Load tasks across all workspaces
        const taskArrays = await Promise.all(
          (wsList || []).map(w =>
            api.tcall("listWorkspaceTasks", { workspaceId: w.id })
              .then(r => (r || []).map(t => ({ ...t, workspaceName: w.name, workspaceId: w.id })))
              .catch(() => [])
          )
        );
        const merged = taskArrays.flat().sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
        setAllTasks(merged);
      } catch (_) {}
      setLoading(false);
    };
    load();
  }, [tenantId]);

  if (loading) return <div style={{ padding: 48, color: "var(--muted)" }}>Loading client overview…</div>;

  // Derive score card values from benchmark
  const clientRow = benchmark.find(r => r.is_client);
  const sortedBench = [...benchmark].sort((a, b) => (b.final_score || 0) - (a.final_score || 0));
  const clientRank = sortedBench.findIndex(r => r.is_client) + 1;

  const statusBadge = (s) => {
    const map = { active: ["good", "Active"], analyzing: ["warn", "Analyzing"], failed: ["bad", "Failed"] };
    const [color, label] = map[s] || ["muted", s || "Unknown"];
    return <span style={{ background: `var(--${color}-soft)`, color: `var(--${color})`, borderRadius: 6, padding: "2px 8px", fontSize: 12, fontWeight: 600 }}>{label}</span>;
  };

  const taskStatusBadge = (s) => {
    const map = { pending: ["var(--line)", "var(--muted)", "Pending"], in_progress: ["var(--warn-soft)", "var(--warn)", "In Progress"], completed: ["var(--good-soft)", "var(--good)", "Completed"], failed: ["#fef2f2", "var(--bad)", "Failed"] };
    const [bg, color, label] = map[s] || map.pending;
    return <span style={{ background: bg, color, borderRadius: 4, padding: "2px 8px", fontSize: 11, fontWeight: 700 }}>{label}</span>;
  };

  return (
    <div style={{ padding: "var(--pad)", maxWidth: 1200 }}>
      {/* Back + Header */}
      <button
        onClick={() => window.__nav("clients")}
        style={{ background: "none", border: "none", cursor: "pointer", color: "var(--muted)", fontSize: 13, padding: 0, marginBottom: 16 }}
      >← Back to Clients</button>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 28 }}>
        <h1 style={{ fontSize: 24, fontWeight: 700, margin: 0 }}>{clientName || "Client Overview"}</h1>
        <button
          onClick={() => window.__nav("new-client", tenantId)}
          style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "10px 18px", fontWeight: 600, cursor: "pointer", fontSize: 14 }}
        >+ New Workspace</button>
      </div>

      {/* Score Cards */}
      {clientRow && (
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 16, marginBottom: 28 }}>
          {[
            { label: "Authority Score", value: clientRow.final_score?.toFixed(1) ?? "—", sub: "out of 100" },
            { label: "Score Band", value: clientRow.score_band || "—", sub: "performance tier" },
            { label: "Peer Rank", value: clientRank > 0 ? `#${clientRank}` : "—", sub: `of ${sortedBench.length} peers` },
          ].map(card => (
            <div key={card.label} style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: "20px 24px" }}>
              <div style={{ fontSize: 12, color: "var(--muted)", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.06em", marginBottom: 8 }}>{card.label}</div>
              <div style={{ fontSize: 32, fontWeight: 800, color: "var(--accent)" }}>{card.value}</div>
              <div style={{ fontSize: 12, color: "var(--muted-2)", marginTop: 4 }}>{card.sub}</div>
            </div>
          ))}
        </div>
      )}

      {/* Peer Rankings Table */}
      {sortedBench.length > 0 && (
        <div style={{ marginBottom: 32 }}>
          <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 14 }}>Peer Rankings</div>
          <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden" }}>
            <div style={{ display: "grid", gridTemplateColumns: "60px 1.8fr 90px 90px 110px 110px 110px", padding: "9px 16px", background: "var(--panel-2)", borderBottom: "1px solid var(--line)", fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>
              <div>Rank</div>
              <div>Company</div>
              <div style={{ textAlign: "right" }}>Score</div>
              <div style={{ textAlign: "right" }}>Band</div>
              <div style={{ textAlign: "right" }}>Common</div>
              <div style={{ textAlign: "right" }}>Industry</div>
              <div style={{ textAlign: "right" }}>Momentum</div>
            </div>
            {sortedBench.map((row, i) => (
              <div key={row.company_id} style={{ display: "grid", gridTemplateColumns: "60px 1.8fr 90px 90px 110px 110px 110px", alignItems: "center", padding: "12px 16px", borderBottom: i < sortedBench.length - 1 ? "1px solid var(--line-2)" : "none", background: row.is_client ? "var(--accent-soft)" : "var(--panel)" }}>
                <div style={{ fontSize: 13, fontWeight: 700, color: "var(--muted-2)" }}>#{i + 1}</div>
                <div style={{ fontWeight: row.is_client ? 700 : 400, fontSize: 13, color: row.is_client ? "var(--accent)" : "var(--ink)" }}>
                  {row.company_name}{row.is_client && <span style={{ fontSize: 11, marginLeft: 6, background: "var(--accent)", color: "var(--accent-ink)", borderRadius: 4, padding: "1px 6px", fontWeight: 700 }}>Client</span>}
                </div>
                <div style={{ textAlign: "right", fontWeight: 700, fontSize: 13 }}>{row.final_score?.toFixed(1) ?? "—"}</div>
                <div style={{ textAlign: "right" }}>
                  {row.score_band && <span style={{ background: "var(--line)", color: "var(--ink)", borderRadius: 6, padding: "2px 8px", fontSize: 11, fontWeight: 600 }}>{row.score_band}</span>}
                </div>
                <div style={{ textAlign: "right", color: "var(--muted)", fontSize: 13 }}>{row.common_score?.toFixed(1) ?? "—"}</div>
                <div style={{ textAlign: "right", color: "var(--muted)", fontSize: 13 }}>{row.industry_score?.toFixed(1) ?? "—"}</div>
                <div style={{ textAlign: "right", color: "var(--muted)", fontSize: 13 }}>{row.momentum_score?.toFixed(1) ?? "—"}</div>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Workspaces */}
      <div style={{ marginBottom: 32 }}>
        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 14 }}>Workspaces ({workspaces.length})</div>
        {workspaces.length === 0 ? (
          <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 32, textAlign: "center", color: "var(--muted)" }}>
            No workspaces yet. <button onClick={() => window.__nav("new-client", tenantId)} style={{ color: "var(--accent)", background: "none", border: "none", cursor: "pointer", fontWeight: 600 }}>Create one →</button>
          </div>
        ) : (
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {workspaces.map(w => (
              <div key={w.id}
                onClick={() => window.__nav("client-detail", w.id)}
                style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: "16px 20px", cursor: "pointer", display: "flex", alignItems: "center", gap: 16, transition: "background .1s" }}
                onMouseEnter={e => e.currentTarget.style.background = "var(--hover)"}
                onMouseLeave={e => e.currentTarget.style.background = "var(--panel)"}
              >
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, fontSize: 15 }}>{w.name}</div>
                  <div style={{ color: "var(--muted)", fontSize: 13, marginTop: 2 }}>
                    {w.competitor_count ?? 0} competitor{w.competitor_count !== 1 ? "s" : ""}
                    {w.last_refreshed_at && <span style={{ marginLeft: 10 }}>· Refreshed {new Date(w.last_refreshed_at).toLocaleDateString()}</span>}
                  </div>
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
                  {statusBadge(w.status)}
                  <span style={{ color: "var(--accent)", fontSize: 13, fontWeight: 600 }}>Open →</span>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* All Tasks */}
      <div>
        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 14 }}>All Tasks ({allTasks.length})</div>
        {allTasks.length === 0 ? (
          <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, padding: 32, textAlign: "center", color: "var(--muted)" }}>
            No tasks yet across any workspace.
          </div>
        ) : (
          <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden" }}>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 160px 160px 110px 120px", padding: "9px 20px", background: "var(--panel-2)", borderBottom: "1px solid var(--line)", fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>
              <div>Task</div>
              <div>Workspace</div>
              <div>Publisher</div>
              <div style={{ textAlign: "right" }}>Status</div>
              <div style={{ textAlign: "right" }}>Date</div>
            </div>
            {allTasks.slice(0, 50).map((task, i) => (
              <div key={task.id}
                onClick={() => window.__nav("workspace-task", `${task.workspaceId}__${task.id}`)}
                style={{ display: "grid", gridTemplateColumns: "1fr 160px 160px 110px 120px", alignItems: "center", padding: "12px 20px", borderBottom: i < Math.min(allTasks.length, 50) - 1 ? "1px solid var(--line-2)" : "none", cursor: "pointer", transition: "background .1s" }}
                onMouseEnter={e => e.currentTarget.style.background = "var(--hover)"}
                onMouseLeave={e => e.currentTarget.style.background = ""}
              >
                <div style={{ fontWeight: 600, fontSize: 13, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", paddingRight: 12 }}>{task.title}</div>
                <div style={{ fontSize: 12, color: "var(--muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{task.workspaceName}</div>
                <div style={{ fontSize: 12, color: "var(--muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{task.publisher_name || (task.target_email ? task.target_email : "Own Site")}</div>
                <div style={{ display: "flex", justifyContent: "flex-end" }}>{taskStatusBadge(task.status)}</div>
                <div style={{ textAlign: "right", fontSize: 12, color: "var(--muted-2)" }}>{task.created_at ? new Date(task.created_at).toLocaleDateString() : "—"}</div>
              </div>
            ))}
            {allTasks.length > 50 && (
              <div style={{ padding: "12px 20px", fontSize: 13, color: "var(--muted)", textAlign: "center", borderTop: "1px solid var(--line-2)" }}>
                Showing 50 of {allTasks.length} tasks. Open a workspace to see all.
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// TaskCompletionPage — public page (no login required), opened from email link
// URL format: /complete?token=TOKEN
// ---------------------------------------------------------------------------
function TaskCompletionPage() {
  const { params } = window.parseHash ? window.parseHash() : { params: {} };
  const token = params.token || new URLSearchParams(window.location.search).get("token") || "";

  const [taskInfo, setTaskInfo] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState("");
  const [form, setForm] = React.useState({ name: "", url: "" });
  const [submitting, setSubmitting] = React.useState(false);
  const [done, setDone] = React.useState(false);
  const [showContent, setShowContent] = React.useState(false);

  React.useEffect(() => {
    if (!token) { setError("No completion token found in the URL."); setLoading(false); return; }
    // Use raw fetch — no auth header needed for public endpoint
    const base = (window.API_CONFIG?.baseUrl) || "http://localhost:8001";
    fetch(`${base}/api/v1/complete/${token}`, { headers: { Accept: "application/json" } })
      .then(r => r.ok ? r.json() : r.json().then(d => Promise.reject(d?.detail || "Invalid link")))
      .then(d => { setTaskInfo(d); setLoading(false); })
      .catch(e => { setError(typeof e === "string" ? e : "This link is invalid or has expired."); setLoading(false); });
  }, [token]);

  const submit = async () => {
    if (!form.name.trim()) return;
    setSubmitting(true);
    const base = (window.API_CONFIG?.baseUrl) || "http://localhost:8001";
    try {
      const r = await fetch(`${base}/api/v1/complete/${token}`, {
        method: "POST",
        headers: { "Content-Type": "application/json", Accept: "application/json" },
        body: JSON.stringify({ completed_by_name: form.name, completed_url: form.url || null }),
      });
      if (!r.ok) { const d = await r.json(); throw d?.detail || "Failed"; }
      setDone(true);
    } catch (e) { setError(typeof e === "string" ? e : "Failed to submit. Please try again."); }
    setSubmitting(false);
  };

  const s = {
    page: { minHeight: "100vh", background: "#f6f7f9", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "sans-serif", padding: 24 },
    card: { background: "#fff", borderRadius: 16, padding: "40px 44px", maxWidth: 600, width: "100%", boxShadow: "0 4px 32px rgba(0,0,0,.08)" },
    brand: { fontSize: 12, fontWeight: 700, color: "#5b5bf5", letterSpacing: ".5px", marginBottom: 24 },
    h1: { fontSize: 22, fontWeight: 700, color: "#0b0d12", margin: "0 0 8px" },
    sub: { fontSize: 14, color: "#6b7280", marginBottom: 24 },
    label: { display: "block", fontWeight: 600, fontSize: 13, marginBottom: 5, color: "#2b2f38" },
    input: { width: "100%", padding: "10px 14px", borderRadius: 8, border: "1px solid #e6e8ee", fontSize: 14, color: "#0b0d12", boxSizing: "border-box", marginBottom: 14 },
    btn: { width: "100%", background: "#5b5bf5", color: "#fff", border: "none", borderRadius: 8, padding: "13px", fontWeight: 700, fontSize: 15, cursor: "pointer" },
    success: { textAlign: "center", padding: "32px 0" },
  };

  if (loading) return (
    <div style={s.page}><div style={s.card}><div style={s.brand}>CREDAXIS</div><div style={{ color: "#6b7280" }}>Loading task details…</div></div></div>
  );

  if (error) return (
    <div style={s.page}><div style={s.card}><div style={s.brand}>CREDAXIS</div><div style={{ color: "#c33", fontWeight: 600 }}>{error}</div></div></div>
  );

  if (done || (taskInfo && taskInfo.already_completed)) return (
    <div style={s.page}>
      <div style={s.card}>
        <div style={s.brand}>CREDAXIS</div>
        <div style={s.success}>
          <div style={{ fontSize: 48, marginBottom: 16 }}>✅</div>
          <h1 style={s.h1}>Thank you!</h1>
          <p style={s.sub}>
            {done
              ? `The task has been marked as published${form.name ? ` by ${form.name}` : ""}.`
              : `This task was already marked as published by ${taskInfo.completed_by_name}.`}
          </p>
          {(taskInfo?.completed_url || form.url) && (
            <p style={{ fontSize: 13, color: "#6b7280" }}>
              Published at: <a href={taskInfo?.completed_url || form.url} target="_blank" rel="noopener noreferrer" style={{ color: "#5b5bf5" }}>{taskInfo?.completed_url || form.url}</a>
            </p>
          )}
        </div>
      </div>
    </div>
  );

  return (
    <div style={s.page}>
      <div style={s.card}>
        <div style={s.brand}>CREDAXIS CONTENT DELIVERY</div>

        <h1 style={s.h1}>{taskInfo.title}</h1>
        <p style={s.sub}>
          {taskInfo.workspace_name && <><b>{taskInfo.workspace_name}</b> · </>}
          {taskInfo.client_company_name && <>{taskInfo.client_company_name}</>}
          {taskInfo.publisher_name && <> → {taskInfo.publisher_name}</>}
        </p>

        {taskInfo.generated_content && (
          <div style={{ marginBottom: 24 }}>
            <button
              onClick={() => setShowContent(s => !s)}
              style={{ background: "#f3f4f8", border: "1px solid #e6e8ee", borderRadius: 8, padding: "8px 16px", cursor: "pointer", fontSize: 13, fontWeight: 600, color: "#2b2f38", marginBottom: 10 }}
            >{showContent ? "Hide article content" : "View article content"}</button>
            {showContent && (
              <div style={{ background: "#f9fafb", borderRadius: 8, padding: "16px 20px", fontSize: 14, lineHeight: 1.7, color: "#2b2f38", maxHeight: 320, overflowY: "auto", whiteSpace: "pre-wrap", border: "1px solid #e6e8ee" }}>
                {taskInfo.generated_content}
              </div>
            )}
          </div>
        )}

        <hr style={{ border: "none", borderTop: "1px solid #e6e8ee", marginBottom: 24 }} />

        <div style={{ fontWeight: 700, fontSize: 16, marginBottom: 6 }}>Mark as Published</div>
        <p style={{ fontSize: 13, color: "#6b7280", marginBottom: 20 }}>Once you've published this content, please confirm below. This will notify the CredAxis team.</p>

        <div>
          <label style={s.label}>Your name *</label>
          <input
            value={form.name}
            onChange={e => setForm(p => ({ ...p, name: e.target.value }))}
            placeholder="Your full name"
            style={s.input}
          />
          <label style={s.label}>Published URL (optional)</label>
          <input
            value={form.url}
            onChange={e => setForm(p => ({ ...p, url: e.target.value }))}
            placeholder="https://yourblog.com/article-title"
            type="url"
            style={s.input}
          />
        </div>

        {error && <div style={{ color: "#c33", fontSize: 13, marginBottom: 12 }}>{error}</div>}

        <button onClick={submit} disabled={submitting || !form.name.trim()} style={{ ...s.btn, opacity: !form.name.trim() ? 0.6 : 1 }}>
          {submitting ? "Submitting…" : "✓ Mark as Published"}
        </button>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// PublisherManagementScreen — Global publisher catalog with per-tenant email contacts
// ---------------------------------------------------------------------------
function PublisherManagementScreen() {
  const [surfaces, setSurfaces] = React.useState([]);
  const [publishers, setPublishers] = React.useState([]);
  const [contacts, setContacts] = React.useState([]); // per-tenant contacts for current session tenant
  const [personas, setPersonas] = React.useState([]); // industry writer-voice catalog
  const [loading, setLoading] = React.useState(true);
  const [search, setSearch] = React.useState("");
  const [industryFilter, setIndustryFilter] = React.useState("");
  const [regionFilter, setRegionFilter] = React.useState("");
  const [tierFilter, setTierFilter] = React.useState("");
  const [section, setSection] = React.useState("surfaces"); // "surfaces" | "publishers" | "personas"
  const [expandedId, setExpandedId] = React.useState(null); // publisher row expanded for detail

  // Writer-persona editing
  const [personaDrafts, setPersonaDrafts] = React.useState({}); // id -> { persona, active }
  const [personaSaving, setPersonaSaving] = React.useState(null); // id being saved

  // Inline email editing
  const [editingKey, setEditingKey] = React.useState(null); // "surface:id" or "publisher:id"
  const [emailDraft, setEmailDraft] = React.useState("");
  const [saving, setSaving] = React.useState(false);

  // Add / edit external publisher form
  const EMPTY_PUB = {
    name: "", website: "", description: "", publisher_type: "email", industry: "",
    region: "", tier: "", route: "", best_for: "", backlink_expectation: "",
    submission_notes: "", min_words: "", max_words: "", max_backlinks: "",
    requires_exclusivity: false, voice_persona: "",
  };
  const [showAdd, setShowAdd] = React.useState(false);
  const [editId, setEditId] = React.useState(null); // when set, modal is editing an existing publisher
  const [addForm, setAddForm] = React.useState(EMPTY_PUB);
  const [adding, setAdding] = React.useState(false);
  const [addErr, setAddErr] = React.useState("");

  const INDUSTRIES = [
    { value: "", label: "All industries" },
    { value: "tech_saas_ai", label: "Tech / SaaS / AI" },
    { value: "manufacturing", label: "Manufacturing" },
    { value: "financial_services", label: "Financial Services" },
    { value: "healthcare_pharma", label: "Healthcare / Pharma" },
    { value: "consumer_d2c", label: "Consumer / D2C" },
  ];
  const INDUSTRY_LABEL = Object.fromEntries(INDUSTRIES.filter(i => i.value).map(i => [i.value, i.label]));

  const REGIONS = [
    { value: "", label: "All regions" },
    { value: "global", label: "Global" },
    { value: "india", label: "India" },
    { value: "gcc", label: "GCC / Middle East" },
    { value: "europe", label: "Europe" },
    { value: "sea", label: "South East Asia" },
    { value: "latam", label: "Latin America" },
  ];
  const REGION_LABEL = Object.fromEntries(REGIONS.map(r => [r.value, r.label]));

  const ROUTES = [
    { value: "", label: "—" },
    { value: "guest_post", label: "Guest post" },
    { value: "editorial_pitch", label: "Editorial pitch" },
    { value: "contributor", label: "Contributor" },
    { value: "self_publish", label: "Self-publish" },
    { value: "community", label: "Community" },
    { value: "pr", label: "PR / Press" },
    { value: "profile", label: "Profile" },
  ];
  const ROUTE_LABEL = Object.fromEntries(ROUTES.map(r => [r.value, r.label]));

  const TIER_STYLE = {
    1: { background: "var(--accent-soft)", color: "var(--accent)" },
    2: { background: "var(--info-soft)", color: "var(--info-ink)" },
    3: { background: "var(--line)", color: "var(--muted)" },
  };
  const wordWindow = (p) =>
    p.min_words && p.max_words ? `${p.min_words}–${p.max_words}w`
    : p.min_words ? `${p.min_words}w+`
    : p.max_words ? `≤${p.max_words}w` : null;

  const reload = () => {
    setLoading(true);
    Promise.all([
      api.call("catalogListSurfaces").catch(() => []),
      api.call("listPublishers").catch(() => []),
      api.tcall("listPublisherContacts").catch(() => []),
      api.call("listWriterPersonas").catch(() => []),
    ]).then(([s, p, c, pe]) => {
      setSurfaces(s || []);
      setPublishers((p || []).filter(x => x.is_active));
      setContacts(c || []);
      setPersonas(pe || []);
      setLoading(false);
    });
  };

  const savePersona = async (id) => {
    const draft = personaDrafts[id];
    if (!draft) return;
    setPersonaSaving(id);
    try {
      const saved = await api.call("updateWriterPersona", { personaId: id }, draft);
      setPersonas(prev => prev.map(x => (x.id === id ? saved : x)));
      setPersonaDrafts(prev => { const n = { ...prev }; delete n[id]; return n; });
    } catch (_) {}
    setPersonaSaving(null);
  };

  React.useEffect(() => { reload(); }, []);

  const getContact = (type, id) => contacts.find(c => (type === "surface" ? c.surface_id : c.publisher_id) === id);

  const startEdit = (type, item) => {
    const key = `${type}:${item.id}`;
    const existing = getContact(type, item.id);
    setEditingKey(key);
    setEmailDraft(existing ? existing.contact_email : (item.submission_email || ""));
  };

  const cancelEdit = () => { setEditingKey(null); setEmailDraft(""); };

  const saveContact = async (type, id) => {
    setSaving(true);
    try {
      const body = { contact_email: emailDraft };
      if (type === "surface") body.surface_id = id; else body.publisher_id = id;
      const saved = await api.tcall("addPublisherContact", {}, body);
      setContacts(prev => {
        const filtered = prev.filter(c => (type === "surface" ? c.surface_id : c.publisher_id) !== id);
        return [...filtered, saved];
      });
      setEditingKey(null);
    } catch (_) {}
    setSaving(false);
  };

  const openAdd = () => { setEditId(null); setAddForm(EMPTY_PUB); setAddErr(""); setShowAdd(true); };
  const openEdit = (p) => {
    setEditId(p.id);
    setAddForm({
      name: p.name || "", website: p.website || "", description: p.description || "",
      publisher_type: p.publisher_type || "email", industry: p.industry || "",
      region: p.region || "", tier: p.tier ?? "", route: p.route || "",
      best_for: p.best_for || "", backlink_expectation: p.backlink_expectation || "",
      submission_notes: p.submission_notes || "",
      min_words: p.min_words ?? "", max_words: p.max_words ?? "", max_backlinks: p.max_backlinks ?? "",
      requires_exclusivity: !!p.requires_exclusivity, voice_persona: p.voice_persona || "",
    });
    setAddErr(""); setShowAdd(true);
  };

  // Normalize numeric / empty fields before sending to the API.
  const cleanForm = () => {
    const f = { ...addForm };
    ["tier", "min_words", "max_words", "max_backlinks"].forEach(k => {
      f[k] = f[k] === "" || f[k] === null ? null : Number(f[k]);
    });
    ["website", "description", "industry", "region", "route", "best_for",
     "backlink_expectation", "submission_notes", "voice_persona"].forEach(k => {
      if (f[k] === "") f[k] = null;
    });
    return f;
  };

  const savePublisher = async () => {
    if (!addForm.name.trim()) { setAddErr("Name is required"); return; }
    setAdding(true); setAddErr("");
    try {
      const body = cleanForm();
      if (editId) {
        const pub = await api.call("updatePublisher", { publisherId: editId }, body);
        setPublishers(prev => prev.map(x => (x.id === editId ? pub : x)));
      } else {
        const pub = await api.call("createPublisher", {}, body);
        setPublishers(prev => [...prev, pub]);
      }
      setShowAdd(false);
      setEditId(null);
      setAddForm(EMPTY_PUB);
      setSection("publishers");
    } catch (e) { setAddErr(e.message || "Failed to save publisher"); }
    setAdding(false);
  };

  const filteredSurfaces = surfaces.filter(s => {
    if (industryFilter && !(s.industry_verticals || []).includes(industryFilter)) return false;
    if (search.trim()) return s.name.toLowerCase().includes(search.toLowerCase());
    return true;
  });

  const filteredPublishers = publishers.filter(p => {
    if (industryFilter && p.industry !== industryFilter) return false;
    if (regionFilter && p.region !== regionFilter) return false;
    if (tierFilter && String(p.tier) !== tierFilter) return false;
    if (search.trim()) return p.name.toLowerCase().includes(search.toLowerCase());
    return true;
  });

  const surfaceContactCount = contacts.filter(c => c.surface_id).length;
  const publisherContactCount = contacts.filter(c => c.publisher_id).length;

  if (loading) return <div style={{ padding: 48, color: "var(--muted)" }}>Loading publishers…</div>;

  const renderContactCell = (type, item) => {
    const key = `${type}:${item.id}`;
    const isEditing = editingKey === key;
    const existing = getContact(type, item.id);
    const email = existing?.contact_email;

    if (isEditing) {
      return (
        <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
          <input
            autoFocus
            type="email"
            value={emailDraft}
            onChange={e => setEmailDraft(e.target.value)}
            onKeyDown={e => { if (e.key === "Enter") saveContact(type, item.id); if (e.key === "Escape") cancelEdit(); }}
            placeholder="contact@publisher.com"
            style={{ flex: 1, padding: "5px 9px", borderRadius: 6, border: "1.5px solid var(--accent)", fontSize: 12, background: "var(--panel)", color: "var(--ink)", outline: "none" }}
          />
          <button onClick={() => saveContact(type, item.id)} disabled={saving}
            style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 5, padding: "5px 10px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
            {saving ? "…" : "Save"}
          </button>
          <button onClick={cancelEdit}
            style={{ background: "none", border: "1px solid var(--line)", borderRadius: 5, padding: "5px 8px", fontSize: 12, cursor: "pointer", color: "var(--muted)" }}>✕</button>
        </div>
      );
    }
    return (
      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
        {email ? (
          <span style={{ fontSize: 13, color: "var(--ink)" }}>{email}</span>
        ) : (
          <span style={{ fontSize: 12, color: "var(--muted-2)", fontStyle: "italic" }}>— no contact</span>
        )}
        <button onClick={() => startEdit(type, item)}
          style={{ background: "none", border: "1px solid var(--line)", borderRadius: 5, padding: "3px 10px", fontSize: 11, cursor: "pointer", color: "var(--muted)", flexShrink: 0 }}>
          {email ? "Edit" : "+ Add"}
        </button>
      </div>
    );
  };

  return (
    <div style={{ padding: "var(--pad)", maxWidth: 1140 }}>
      {/* Header */}
      <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 20 }}>
        <div>
          <h1 style={{ fontSize: 22, fontWeight: 700, margin: 0 }}>Publishers</h1>
          <div style={{ color: "var(--muted)", fontSize: 14, marginTop: 4 }}>
            Global publisher catalog — contact emails are saved per client.
          </div>
        </div>
        <button onClick={openAdd}
          style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "9px 18px", fontWeight: 600, cursor: "pointer", fontSize: 13 }}>
          + Add Publisher
        </button>
      </div>

      {/* Stats */}
      <div style={{ display: "flex", gap: 10, marginBottom: 18, flexWrap: "wrap" }}>
        {[
          { label: `${surfaces.length} authority surfaces`, bg: "var(--panel)", color: "var(--ink)" },
          { label: `${publishers.length} external publishers`, bg: "var(--panel)", color: "var(--ink)" },
          { label: `${surfaceContactCount + publisherContactCount} contacts saved for this client`, bg: "var(--good-soft)", color: "var(--good)" },
        ].map((s, i) => (
          <div key={i} style={{ background: s.bg, border: "1px solid var(--line)", borderRadius: 8, padding: "7px 14px", fontSize: 13, color: s.color, fontWeight: 600 }}>
            {s.label}
          </div>
        ))}
      </div>

      {/* Filters */}
      <div style={{ display: "flex", gap: 10, marginBottom: 16, flexWrap: "wrap", alignItems: "center" }}>
        <div style={{ display: "flex", gap: 2, background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 8, padding: 2 }}>
          {["surfaces", "publishers", "personas"].map(s => (
            <button key={s} onClick={() => setSection(s)}
              style={{ background: section === s ? "var(--accent)" : "none", color: section === s ? "var(--accent-ink)" : "var(--muted)", border: "none", borderRadius: 6, padding: "6px 16px", fontSize: 13, fontWeight: section === s ? 700 : 400, cursor: "pointer" }}>
              {s === "surfaces" ? `Authority Surfaces (${surfaces.length})`
                : s === "publishers" ? `External Publishers (${publishers.length})`
                : `Writer Personas (${personas.length})`}
            </button>
          ))}
        </div>

        {section !== "personas" && (
          <select value={industryFilter} onChange={e => setIndustryFilter(e.target.value)}
            style={{ padding: "7px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel)", color: "var(--ink)" }}>
            {INDUSTRIES.map(i => <option key={i.value} value={i.value}>{i.label}</option>)}
          </select>
        )}

        {section === "publishers" && (
          <>
            <select value={regionFilter} onChange={e => setRegionFilter(e.target.value)}
              style={{ padding: "7px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel)", color: "var(--ink)" }}>
              {REGIONS.map(r => <option key={r.value} value={r.value}>{r.label}</option>)}
            </select>
            <select value={tierFilter} onChange={e => setTierFilter(e.target.value)}
              style={{ padding: "7px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel)", color: "var(--ink)" }}>
              <option value="">All tiers</option>
              <option value="1">Tier 1 — Authority</option>
              <option value="2">Tier 2 — Pipeline</option>
              <option value="3">Tier 3 — Footprint</option>
            </select>
          </>
        )}

        <input value={search} onChange={e => setSearch(e.target.value)} placeholder="Search by name…"
          style={{ marginLeft: "auto", padding: "7px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel)", color: "var(--ink)", width: 220 }} />
      </div>

      {/* Table */}
      <div style={{ background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 12, overflow: "hidden" }}>
        {section !== "personas" && (
          <div style={{ display: "grid", gridTemplateColumns: "1fr 130px 130px 1fr", padding: "9px 16px", background: "var(--panel-2)", borderBottom: "1px solid var(--line)", fontSize: 11, fontWeight: 700, color: "var(--muted)", textTransform: "uppercase", letterSpacing: "0.05em" }}>
            <div>Name</div>
            <div>Type</div>
            <div>Industry</div>
            <div>Contact Email (this client)</div>
          </div>
        )}

        {section === "personas" && (
          <>
            <div style={{ padding: "12px 16px", fontSize: 13, color: "var(--muted)", borderBottom: "1px solid var(--line-2)" }}>
              The writer voice used when generating content. Chosen by the target publisher's industry first, then the client's industry. A publisher's own custom voice (set on the publisher) overrides these.
            </div>
            {personas.length === 0 ? (
              <div style={{ padding: 40, textAlign: "center", color: "var(--muted)" }}>No writer personas found.</div>
            ) : personas.map((pe, i) => {
              const draft = personaDrafts[pe.id];
              const text = draft ? draft.persona : pe.persona;
              const active = draft ? draft.active : pe.active;
              const dirty = !!draft;
              const setDraft = (patch) => setPersonaDrafts(prev => ({ ...prev, [pe.id]: { persona: text, active, ...prev[pe.id], ...patch } }));
              return (
                <div key={pe.id} style={{ padding: "14px 16px", borderBottom: i < personas.length - 1 ? "1px solid var(--line-2)" : "none" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 8 }}>
                    <span style={{ fontWeight: 700, fontSize: 14 }}>{pe.label}</span>
                    <span style={{ background: "var(--line)", borderRadius: 4, padding: "1px 7px", fontSize: 10, color: "var(--muted)" }}>
                      {INDUSTRY_LABEL[pe.industry] || pe.industry}
                    </span>
                    <label style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: 6, fontSize: 12, color: "var(--muted)", cursor: "pointer" }}>
                      <input type="checkbox" checked={active} onChange={e => setDraft({ active: e.target.checked })} />
                      Active
                    </label>
                  </div>
                  <textarea
                    value={text}
                    onChange={e => setDraft({ persona: e.target.value })}
                    rows={4}
                    style={{ width: "100%", padding: "10px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, lineHeight: 1.6, background: "var(--panel-2)", color: "var(--ink)", resize: "vertical", boxSizing: "border-box" }}
                  />
                  {dirty && (
                    <div style={{ display: "flex", gap: 8, marginTop: 8 }}>
                      <button onClick={() => savePersona(pe.id)} disabled={personaSaving === pe.id}
                        style={{ background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 6, padding: "6px 16px", fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
                        {personaSaving === pe.id ? "Saving…" : "Save"}
                      </button>
                      <button onClick={() => setPersonaDrafts(prev => { const n = { ...prev }; delete n[pe.id]; return n; })}
                        style={{ background: "none", border: "1px solid var(--line)", borderRadius: 6, padding: "6px 12px", fontSize: 12, cursor: "pointer", color: "var(--muted)" }}>
                        Cancel
                      </button>
                    </div>
                  )}
                </div>
              );
            })}
          </>
        )}

        {section === "surfaces" && (
          filteredSurfaces.length === 0 ? (
            <div style={{ padding: 40, textAlign: "center", color: "var(--muted)" }}>
              {search || industryFilter ? "No surfaces match your filters." : "No authority surfaces found."}
            </div>
          ) : filteredSurfaces.map((s, i) => (
            <div key={s.id} style={{
              display: "grid", gridTemplateColumns: "1fr 130px 130px 1fr",
              alignItems: "center", padding: "11px 16px",
              borderBottom: i < filteredSurfaces.length - 1 ? "1px solid var(--line-2)" : "none",
              background: editingKey === `surface:${s.id}` ? "var(--accent-soft)" : "var(--panel)",
            }}>
              <div>
                <div style={{ fontWeight: 600, fontSize: 13 }}>{s.name}</div>
                {s.url && <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 1, maxWidth: 260, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{s.url}</div>}
              </div>
              <div>
                <span style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 4, padding: "2px 7px", fontSize: 11, fontWeight: 700 }}>
                  {s.platform_type || "platform"}
                </span>
              </div>
              <div style={{ fontSize: 12, color: "var(--muted)" }}>
                {(s.industry_verticals || []).slice(0, 2).map(iv => (
                  <span key={iv} style={{ background: "var(--line)", borderRadius: 4, padding: "1px 6px", marginRight: 4, fontSize: 11 }}>
                    {iv.replace(/_/g, " ")}
                  </span>
                ))}
              </div>
              <div>{renderContactCell("surface", s)}</div>
            </div>
          ))
        )}

        {section === "publishers" && (
          filteredPublishers.length === 0 ? (
            <div style={{ padding: 40, textAlign: "center", color: "var(--muted)" }}>
              <div style={{ fontWeight: 600, marginBottom: 8 }}>No external publishers yet</div>
              <div style={{ fontSize: 13 }}>Click "+ Add Publisher" to add a custom publication.</div>
            </div>
          ) : filteredPublishers.map((p, i) => {
            const ww = wordWindow(p);
            const isOpen = expandedId === p.id;
            const hasDetail = p.best_for || p.backlink_expectation || p.submission_notes;
            return (
            <div key={p.id} style={{
              borderBottom: i < filteredPublishers.length - 1 ? "1px solid var(--line-2)" : "none",
              background: editingKey === `publisher:${p.id}` ? "var(--accent-soft)" : "var(--panel)",
            }}>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 130px 130px 1fr", alignItems: "center", padding: "11px 16px" }}>
                <div>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
                    <span style={{ fontWeight: 600, fontSize: 13 }}>{p.name}</span>
                    {p.tier && (
                      <span style={{ ...TIER_STYLE[p.tier], borderRadius: 4, padding: "1px 7px", fontSize: 10, fontWeight: 700 }}>
                        TIER {p.tier}
                      </span>
                    )}
                    {hasDetail && (
                      <button onClick={() => setExpandedId(isOpen ? null : p.id)}
                        style={{ background: "none", border: "none", color: "var(--muted)", cursor: "pointer", fontSize: 11, padding: 0 }}>
                        {isOpen ? "▾ hide" : "▸ details"}
                      </button>
                    )}
                  </div>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 3, flexWrap: "wrap" }}>
                    {p.region && <span style={{ fontSize: 11, color: "var(--muted)" }}>{REGION_LABEL[p.region] || p.region}</span>}
                    {p.route && <span style={{ background: "var(--line)", borderRadius: 4, padding: "1px 6px", fontSize: 10, color: "var(--muted)" }}>{ROUTE_LABEL[p.route] || p.route}</span>}
                    {ww && <span style={{ fontSize: 10, color: "var(--muted-2)" }}>{ww}</span>}
                    {p.max_backlinks != null && <span style={{ fontSize: 10, color: "var(--muted-2)" }}>≤{p.max_backlinks} link{p.max_backlinks !== 1 ? "s" : ""}</span>}
                    {p.requires_exclusivity && <span style={{ background: "var(--warn-soft, var(--line))", color: "var(--warn, var(--muted))", borderRadius: 4, padding: "1px 6px", fontSize: 10, fontWeight: 700 }}>EXCLUSIVE</span>}
                    {p.voice_persona && <span title="Custom writer voice set" style={{ background: "var(--accent-soft)", color: "var(--accent)", borderRadius: 4, padding: "1px 6px", fontSize: 10, fontWeight: 700 }}>★ VOICE</span>}
                  </div>
                  {p.website && <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 2 }}>{p.website}</div>}
                </div>
                <div>
                  <span style={{ background: p.publisher_type === "api" ? "var(--info-soft)" : "var(--good-soft)", color: p.publisher_type === "api" ? "var(--info-ink)" : "var(--good)", borderRadius: 4, padding: "2px 7px", fontSize: 11, fontWeight: 700 }}>
                    {p.publisher_type === "api" ? "API" : "Email"}
                  </span>
                  <button onClick={() => openEdit(p)}
                    style={{ display: "block", marginTop: 6, background: "none", border: "1px solid var(--line)", borderRadius: 5, padding: "2px 9px", fontSize: 10, cursor: "pointer", color: "var(--muted)" }}>
                    Edit
                  </button>
                </div>
                <div style={{ fontSize: 12, color: "var(--muted)" }}>
                  {p.industry ? (
                    <span style={{ background: "var(--line)", borderRadius: 4, padding: "1px 6px", fontSize: 11 }}>
                      {p.industry.replace(/_/g, " ")}
                    </span>
                  ) : (
                    <span style={{ color: "var(--muted-2)", fontStyle: "italic", fontSize: 11 }}>detecting…</span>
                  )}
                </div>
                <div>{renderContactCell("publisher", p)}</div>
              </div>
              {isOpen && hasDetail && (
                <div style={{ padding: "0 16px 14px 16px", display: "flex", flexDirection: "column", gap: 6, fontSize: 12 }}>
                  {p.best_for && <div><span style={{ color: "var(--muted)", fontWeight: 600 }}>Best for: </span><span style={{ color: "var(--ink)" }}>{p.best_for}</span></div>}
                  {p.backlink_expectation && <div><span style={{ color: "var(--muted)", fontWeight: 600 }}>Backlink: </span><span style={{ color: "var(--ink)" }}>{p.backlink_expectation}</span></div>}
                  {p.submission_notes && <div><span style={{ color: "var(--muted)", fontWeight: 600 }}>Guidelines: </span><span style={{ color: "var(--ink)" }}>{p.submission_notes}</span></div>}
                </div>
              )}
            </div>
            );
          })
        )}
      </div>

      {/* Add / Edit Publisher Modal */}
      {showAdd && (() => {
        const inputStyle = { width: "100%", padding: "9px 12px", borderRadius: 8, border: "1px solid var(--line)", fontSize: 13, background: "var(--panel-2)", color: "var(--ink)" };
        const labelStyle = { display: "block", fontWeight: 600, fontSize: 13, marginBottom: 4 };
        const set = (k, v) => setAddForm(p => ({ ...p, [k]: v }));
        return (
        <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,.45)", zIndex: 1000, display: "flex", alignItems: "center", justifyContent: "center" }}>
          <div style={{ background: "var(--panel)", borderRadius: 16, padding: 28, width: 560, maxHeight: "88vh", overflowY: "auto", boxShadow: "var(--shadow-modal)" }}>
            <div style={{ fontWeight: 700, fontSize: 18, marginBottom: 4 }}>{editId ? "Edit Publisher" : "Add Publisher"}</div>
            <div style={{ fontSize: 13, color: "var(--muted)", marginBottom: 20 }}>
              Editorial rules below are passed to the AI as hard constraints when generating content for this outlet.
            </div>
            <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
              {[
                { key: "name", label: "Name *", placeholder: "e.g. Inc42, Sifted" },
                { key: "website", label: "Website", placeholder: "https://inc42.com" },
                { key: "description", label: "Description", placeholder: "Brief description" },
              ].map(({ key, label, placeholder }) => (
                <div key={key}>
                  <label style={labelStyle}>{label}</label>
                  <input value={addForm[key]} onChange={e => set(key, e.target.value)} placeholder={placeholder} style={inputStyle} />
                </div>
              ))}

              <div style={{ display: "flex", gap: 12 }}>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Region</label>
                  <select value={addForm.region} onChange={e => set("region", e.target.value)} style={inputStyle}>
                    {REGIONS.map(r => <option key={r.value} value={r.value}>{r.value ? r.label : "—"}</option>)}
                  </select>
                </div>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Tier</label>
                  <select value={addForm.tier} onChange={e => set("tier", e.target.value)} style={inputStyle}>
                    <option value="">—</option>
                    <option value="1">Tier 1 — Authority</option>
                    <option value="2">Tier 2 — Pipeline</option>
                    <option value="3">Tier 3 — Footprint</option>
                  </select>
                </div>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Route</label>
                  <select value={addForm.route} onChange={e => set("route", e.target.value)} style={inputStyle}>
                    {ROUTES.map(r => <option key={r.value} value={r.value}>{r.label}</option>)}
                  </select>
                </div>
              </div>

              <div style={{ display: "flex", gap: 12 }}>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Type</label>
                  <select value={addForm.publisher_type} onChange={e => set("publisher_type", e.target.value)} style={inputStyle}>
                    <option value="email">Email submission</option>
                    <option value="api">API integration</option>
                  </select>
                </div>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Industry</label>
                  <select value={addForm.industry} onChange={e => set("industry", e.target.value)} style={inputStyle}>
                    {INDUSTRIES.map(i => <option key={i.value} value={i.value}>{i.value ? i.label : "Auto-detect"}</option>)}
                  </select>
                </div>
              </div>

              <div style={{ display: "flex", gap: 12 }}>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Min words</label>
                  <input type="number" min="0" value={addForm.min_words} onChange={e => set("min_words", e.target.value)} placeholder="500" style={inputStyle} />
                </div>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Max words</label>
                  <input type="number" min="0" value={addForm.max_words} onChange={e => set("max_words", e.target.value)} placeholder="1200" style={inputStyle} />
                </div>
                <div style={{ flex: 1 }}>
                  <label style={labelStyle}>Max backlinks</label>
                  <input type="number" min="0" value={addForm.max_backlinks} onChange={e => set("max_backlinks", e.target.value)} placeholder="2" style={inputStyle} />
                </div>
              </div>

              <label style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
                <input type="checkbox" checked={addForm.requires_exclusivity} onChange={e => set("requires_exclusivity", e.target.checked)} />
                Requires exclusive / original content
              </label>

              <div>
                <label style={labelStyle}>Best for (topics / angles)</label>
                <input value={addForm.best_for} onChange={e => set("best_for", e.target.value)} placeholder="Startups, SaaS, D2C, fintech, AI" style={inputStyle} />
              </div>
              <div>
                <label style={labelStyle}>Backlink expectation</label>
                <input value={addForm.backlink_expectation} onChange={e => set("backlink_expectation", e.target.value)} placeholder="Editorial backlink within guest-post limits" style={inputStyle} />
              </div>
              <div>
                <label style={labelStyle}>Submission notes / guidelines</label>
                <textarea value={addForm.submission_notes} onChange={e => set("submission_notes", e.target.value)} rows={3}
                  placeholder="Data-backed, original; max 2 backlinks including author bio." style={{ ...inputStyle, resize: "vertical" }} />
              </div>
              <div>
                <label style={labelStyle}>Custom writer voice — optional override</label>
                <textarea value={addForm.voice_persona} onChange={e => set("voice_persona", e.target.value)} rows={3}
                  placeholder="Leave blank to use the industry persona. e.g. You are a senior fintech correspondent writing for institutional investors…"
                  style={{ ...inputStyle, resize: "vertical" }} />
                <div style={{ fontSize: 11, color: "var(--muted-2)", marginTop: 4 }}>
                  When set, this voice is used instead of the industry persona for content written for this outlet.
                </div>
              </div>
            </div>
            {addErr && <div style={{ color: "var(--bad)", fontSize: 13, marginTop: 10 }}>{addErr}</div>}
            <div style={{ display: "flex", gap: 10, marginTop: 20 }}>
              <button onClick={savePublisher} disabled={adding}
                style={{ flex: 1, background: "var(--accent)", color: "var(--accent-ink)", border: "none", borderRadius: 8, padding: "12px", fontWeight: 700, cursor: "pointer" }}>
                {adding ? "Saving…" : (editId ? "Save changes" : "Add Publisher")}
              </button>
              <button onClick={() => { setShowAdd(false); setEditId(null); setAddErr(""); }}
                style={{ background: "none", border: "1px solid var(--line)", borderRadius: 8, padding: "12px 20px", cursor: "pointer", color: "var(--muted)" }}>
                Cancel
              </button>
            </div>
          </div>
        </div>
        );
      })()}
    </div>
  );
}
