// admin.jsx — Admin (freelancer/VA) side of Relay

// ─────────────────────────────────────────────────────────────────────
// Admin shell — sidebar + topbar
// ─────────────────────────────────────────────────────────────────────
function AdminShell({ children, view, setView, freelancer }) {
  const { clients, notifications } = useApp();
  const nav = [
    { id: "dashboard", label: "Dashboard",  icon: Icon.home,     count: null },
    { id: "clients",   label: "Clients",    icon: Icon.users,    count: clients.length || null },
    { id: "new",       label: "New client", icon: Icon.plus,     count: null, accent: true },
    { id: "templates", label: "Templates",  icon: Icon.template, count: null },
    { id: "inbox",     label: "Inbox",      icon: Icon.inbox,    count: (notifications && notifications.length) || null },
    { id: "settings",  label: "Settings",   icon: Icon.settings, count: null },
  ];

  return (
    <div style={{ display: "grid", gridTemplateColumns: "232px 1fr", minHeight: "100vh", background: "var(--bg)" }}>
      {/* Sidebar */}
      <aside style={{ borderRight: "1px solid var(--line)", background: "var(--surface-2)", display: "flex", flexDirection: "column" }}>
        <div style={{ padding: "16px 18px 12px", display: "flex", alignItems: "center", gap: 10 }}>
          <LogoMark size={26} color={freelancer.accent}/>
          <div className="col" style={{ lineHeight: 1.15 }}>
            <div style={{ fontSize: 14, fontWeight: 600, letterSpacing: "-0.01em" }}>{freelancer.brand}</div>
            <div className="muted" style={{ fontSize: 11 }}>{freelancer.tagline}</div>
          </div>
        </div>

        <div style={{ padding: "0 10px 8px" }}>
          <SidebarSearch setView={setView}/>
        </div>

        <nav style={{ padding: "4px 8px", display: "flex", flexDirection: "column", gap: 1 }}>
          {nav.map(n => (
            <NavItem key={n.id} item={n} active={view === n.id} onClick={() => setView(n.id)} accent={freelancer.accent}/>
          ))}
        </nav>

        <div style={{ marginTop: "auto", padding: 12, borderTop: "1px solid var(--line)" }}>
          <SidebarSyncButton/>
          <div className="row gap-8" style={{ padding: "6px 8px", borderRadius: 8 }}>
            <Avatar name={freelancer.name} size={28}/>
            <div className="col" style={{ lineHeight: 1.2, minWidth: 0, flex: 1 }}>
              <div style={{ fontSize: 12.5, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{freelancer.name}</div>
              <div className="muted" style={{ fontSize: 11 }}>{freelancer.title}</div>
            </div>
            {window.relayAuthUser && window.relayAuthUser() && (
              <button title="Sign out" onClick={() => window.relaySignOut()} className="btn btn-ghost btn-sm" style={{ padding: 6 }}>
                <Icon.external cls="ico-sm"/>
              </button>
            )}
          </div>
        </div>
      </aside>

      <main style={{ minWidth: 0, display: "flex", flexDirection: "column" }}>
        {children}
      </main>
    </div>
  );
}

function SidebarSyncButton() {
  const { toast } = useToast();
  const [state, setState] = React.useState("idle"); // idle | syncing | done | error
  const sync = async () => {
    setState("syncing");
    try {
      await window.flushAllWorkspaceWrites();      // flush any debounced edits
      await window.forceSyncFromLocal();           // then make cloud exactly match this laptop
      setState("done");
      toast("All edits synced to Firebase", { kind: "success" });
      setTimeout(() => setState("idle"), 2500);
    } catch (e) {
      setState("error");
      toast("Sync failed — check your connection", { kind: "warn" });
      setTimeout(() => setState("idle"), 2500);
    }
  };
  const label = state === "syncing" ? "Syncing…" : state === "done" ? "Synced ✓" : state === "error" ? "Retry sync" : "Force sync to cloud";
  return (
    <button onClick={sync} disabled={state === "syncing"} className="btn btn-sm" style={{
      width: "100%", justifyContent: "center", gap: 8, marginBottom: 8,
      background: state === "done" ? "var(--primary-soft-2)" : "var(--surface)",
      color: state === "done" ? "var(--primary)" : "var(--ink-2)",
      borderColor: state === "done" ? "var(--primary-soft)" : "var(--line)",
    }}>
      <Icon.refresh cls="ico-sm" style={state === "syncing" ? { animation: "spin 0.8s linear infinite" } : undefined}/>
      {label}
    </button>
  );
}

function SidebarSearch({ setView }) {
  const { clients, setActiveClientId } = useApp();
  const [q, setQ] = React.useState("");
  const [focus, setFocus] = React.useState(false);
  const matches = q.trim()
    ? clients.filter(c => `${c.company} ${c.contact} ${c.role_title} ${c.email}`.toLowerCase().includes(q.toLowerCase())).slice(0, 6)
    : [];
  const open = (c) => { setActiveClientId(c.id); setView("client-detail"); setQ(""); setFocus(false); };
  return (
    <div style={{ position: "relative" }}>
      <span style={{ position: "absolute", left: 9, top: 9, color: "var(--muted)", zIndex: 1 }}><Icon.search cls="ico-sm"/></span>
      <input className="input" placeholder="Search clients…" value={q}
        onChange={e => setQ(e.target.value)} onFocus={() => setFocus(true)} onBlur={() => setTimeout(() => setFocus(false), 150)}
        style={{ paddingLeft: 30, fontSize: 12.5, height: 32 }}/>
      {focus && q.trim() && (
        <div className="card" style={{ position: "absolute", top: 37, left: 0, right: 0, zIndex: 30, boxShadow: "var(--shadow-lg)", overflow: "hidden" }}>
          {matches.length === 0 ? (
            <div style={{ padding: 10, fontSize: 12, color: "var(--ink-3)" }}>No clients match "{q}"</div>
          ) : matches.map((c, i) => (
            <button key={c.id} onMouseDown={() => open(c)} className="row gap-8"
              style={{ width: "100%", padding: "8px 10px", border: 0, background: "transparent", cursor: "pointer", textAlign: "left", borderBottom: i < matches.length - 1 ? "1px solid var(--line-2)" : "none" }}>
              <Avatar name={c.company} size={24} bg={c.color[0]} fg={c.color[1]}/>
              <div className="col" style={{ lineHeight: 1.2, minWidth: 0 }}>
                <span style={{ fontSize: 12.5, fontWeight: 500 }}>{c.company}</span>
                <span className="ink-3" style={{ fontSize: 11, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{c.contact}</span>
              </div>
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

function NavItem({ item, active, onClick, accent }) {
  const Ico = item.icon;
  return (
    <button onClick={onClick}
      style={{
        display: "flex", alignItems: "center", gap: 10, padding: "7px 10px",
        background: active ? "var(--surface)" : "transparent",
        border: "1px solid " + (active ? "var(--line)" : "transparent"),
        boxShadow: active ? "var(--shadow-sm)" : "none",
        borderRadius: 7, color: active ? "var(--ink)" : "var(--ink-2)",
        fontSize: 13, fontWeight: active ? 500 : 400, letterSpacing: "-0.005em",
        cursor: "pointer", width: "100%", textAlign: "left",
      }}>
      <span style={{ color: active ? accent : "var(--ink-3)", display: "flex" }}><Ico cls="ico-sm"/></span>
      <span style={{ flex: 1 }}>{item.label}</span>
      {item.count != null && (
        <span style={{ background: "var(--bg-2)", color: "var(--ink-3)", fontSize: 11, padding: "1px 6px", borderRadius: 999, fontWeight: 500 }}>{item.count}</span>
      )}
      {item.accent && !item.count && (
        <span style={{ fontSize: 10, color: "var(--muted)" }}>⌘N</span>
      )}
    </button>
  );
}

// Page header used on inner pages
function PageHeader({ eyebrow, title, sub, right }) {
  return (
    <div style={{ padding: "28px 36px 18px", borderBottom: "1px solid var(--line)", background: "var(--bg)" }}>
      <div className="row" style={{ justifyContent: "space-between", alignItems: "flex-end", gap: 24 }}>
        <div className="col gap-6">
          {eyebrow && <div className="label" style={{ color: "var(--ink-3)" }}>{eyebrow}</div>}
          <div className="h-display" style={{ fontSize: 32, lineHeight: 1.1 }}>{title}</div>
          {sub && <div className="ink-3" style={{ fontSize: 13.5, maxWidth: 560 }}>{sub}</div>}
        </div>
        {right && <div className="row gap-8">{right}</div>}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Action Center — the one place that says "here's what needs you today"
// Built automatically from your to-dos + each client's state.
// ─────────────────────────────────────────────────────────────────────
function ActionCenter({ goTo }) {
  const { clients, setActiveClientId, updateClient } = useApp();

  const go = (c) => { setActiveClientId(c.id); goTo("client-detail"); };

  // 1. Your explicit to-dos (highest priority)
  const taskItems = [];
  clients.forEach(c => (c.tasks || []).filter(t => !t.done).forEach(t =>
    taskItems.push({ id: `t-${c.id}-${t.id}`, kind: "task", text: t.text, c, taskId: t.id, icon: Icon.check })
  ));

  // 2. Auto-flags from client state
  const flagItems = [];
  clients.forEach(c => {
    if (c.status === "new") {
      flagItems.push({ id: `f-new-${c.id}`, kind: "flag", text: "Hasn't started onboarding — send a nudge", c, icon: Icon.send, tone: "blue" });
      return;
    }
    if (c.docs) {
      if (c.docs.agreement === "draft") flagItems.push({ id: `f-ag-${c.id}`, kind: "flag", text: "Agreement still unsigned", c, icon: Icon.signature, tone: "warn" });
      if (c.docs.invoice && c.docs.invoice !== "paid") flagItems.push({ id: `f-inv-${c.id}`, kind: "flag", text: "Deposit invoice unpaid", c, icon: Icon.money, tone: "warn" });
    }
  });

  const items = [...taskItems, ...flagItems];
  const completeTask = (c, taskId) => updateClient(c.id, { tasks: (c.tasks || []).map(t => t.id === taskId ? { ...t, done: true } : t) });

  const toneStyle = (tone) => ({
    blue: { bg: "#DDE6F4", fg: "#2C4D8A" },
    warn: { bg: "#F4E8DB", fg: "#8A5E2C" },
    task: { bg: "var(--primary-soft)", fg: "var(--primary)" },
  }[tone] || { bg: "var(--primary-soft)", fg: "var(--primary)" });

  return (
    <Card pad={false}>
      <div className="row" style={{ padding: "16px 18px", borderBottom: "1px solid var(--line)", justifyContent: "space-between", alignItems: "center" }}>
        <div className="row gap-8" style={{ alignItems: "center" }}>
          <div style={{ width: 30, height: 30, borderRadius: 8, background: "var(--primary)", color: "#fff", display: "grid", placeItems: "center" }}><Icon.lightning cls="ico-sm"/></div>
          <div className="col" style={{ lineHeight: 1.25 }}>
            <div style={{ fontSize: 15, fontWeight: 600 }}>Needs your attention</div>
            <div className="ink-3" style={{ fontSize: 12 }}>Everything waiting on you, in one place.</div>
          </div>
        </div>
        {items.length > 0 && <span className="badge pill-pending" style={{ fontSize: 11 }}>{items.length} item{items.length === 1 ? "" : "s"}</span>}
      </div>

      {items.length === 0 ? (
        <div style={{ padding: 28, textAlign: "center", color: "var(--ink-3)" }}>
          <div style={{ width: 44, height: 44, borderRadius: 12, background: "var(--primary-soft)", color: "var(--primary)", display: "grid", placeItems: "center", margin: "0 auto 10px" }}><Icon.check cls="ico-lg"/></div>
          <div style={{ fontSize: 14, fontWeight: 500, color: "var(--ink)" }}>You're all caught up.</div>
          <div style={{ fontSize: 12.5, marginTop: 2 }}>Nothing needs you right now. Nice.</div>
        </div>
      ) : items.slice(0, 12).map((it, i, arr) => {
        const Ico = it.icon;
        const ts = toneStyle(it.kind === "task" ? "task" : it.tone);
        return (
          <div key={it.id} className="row gap-12" style={{ padding: "12px 18px", borderBottom: i < Math.min(12, arr.length) - 1 ? "1px solid var(--line-2)" : "none", alignItems: "center" }}>
            {it.kind === "task" ? (
              <button title="Mark done" onClick={() => completeTask(it.c, it.taskId)} style={{ width: 20, height: 20, borderRadius: 6, border: "1px solid var(--line)", background: "transparent", display: "grid", placeItems: "center", cursor: "pointer", flexShrink: 0, padding: 0 }}>
                <Icon.check cls="ico-sm" style={{ color: "var(--ink-3)", width: 13, height: 13 }}/>
              </button>
            ) : (
              <div style={{ width: 28, height: 28, borderRadius: 7, background: ts.bg, color: ts.fg, display: "grid", placeItems: "center", flexShrink: 0 }}><Ico cls="ico-sm"/></div>
            )}
            <div className="col" style={{ flex: 1, lineHeight: 1.3, minWidth: 0 }}>
              <div style={{ fontSize: 13.5, fontWeight: it.kind === "task" ? 500 : 400 }}>{it.text}</div>
              <div className="ink-3" style={{ fontSize: 12 }}>{it.c.company}{it.kind === "task" ? " · your to-do" : ""}</div>
            </div>
            <button className="btn btn-sm btn-ghost" onClick={() => go(it.c)}>Open <Icon.arrow cls="ico-sm"/></button>
          </div>
        );
      })}
      {items.length > 12 && (
        <div style={{ padding: "10px 18px", borderTop: "1px solid var(--line-2)", textAlign: "center" }}>
          <span className="ink-3" style={{ fontSize: 12 }}>+ {items.length - 12} more across your clients</span>
        </div>
      )}
    </Card>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Dashboard
// ─────────────────────────────────────────────────────────────────────
function AdminDashboard({ goTo }) {
  const { clients, activity, freelancer, setActiveClientId } = useApp();
  const { copyToClipboard, toast } = useToast();
  const cur = freelancer.currency;

  const leads = clients.filter(c => c.status === "lead");
  const stats = [
    { label: "Leads", value: leads.length, sub: "in pipeline", accent: "#92400E" },
    { label: "Active clients",   value: clients.filter(c => c.status === "active").length, sub: "this month" },
    { label: "Pending onboarding", value: clients.filter(c => c.status === "new" || c.status === "pending").length, sub: "awaiting client" },
    { label: "Pipeline MRR",     value: fmtMoney(clients.filter(c=>c.status!=="lead").reduce((s, c) => s + (c.hoursPerWeek ? c.rate : 0), 0), cur), sub: "monthly retainers" },
    { label: "Signed", value: clients.filter(c => c.signature).length, sub: "agreements" },
  ];

  return (
    <div className="col" style={{ minHeight: "100vh" }}>
      <PageHeader
        eyebrow="Dashboard"
        title={`Good morning, ${freelancer.name.split(" ")[0]}.`}
        sub={`${clients.filter(c => c.status === "pending" || c.status === "new").length} clients waiting on you. ${activity.length} updates today.`}
        right={<>
          <Button variant="primary" icon={<Icon.plus cls="ico-sm"/>} onClick={() => goTo("new")}>New client</Button>
        </>}
      />

      <div style={{ padding: "24px 36px 48px", display: "flex", flexDirection: "column", gap: 28 }}>
        {/* Action Center — what needs you today */}
        <ActionCenter goTo={goTo}/>

        {/* Stats */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 12 }}>
          {stats.map(s => <StatBlock key={s.label} {...s}/>)}
        </div>

        {/* Pipeline funnel bar */}
        {(() => {
          const stages = [
            { label: "Lead",    count: clients.filter(c=>c.status==="lead").length,    color: "#92400E", bg: "#FEF3C7", filter: "lead" },
            { label: "Invited", count: clients.filter(c=>c.status==="new").length,     color: "#2C4D8A", bg: "#DDE6F4", filter: "new" },
            { label: "Active",  count: clients.filter(c=>c.status==="active").length,  color: "#1B4332", bg: "#DCE8E1", filter: "active" },
            { label: "Done",    count: clients.filter(c=>c.status==="done").length,    color: "#5B635E", bg: "#E6E6E0", filter: "done" },
          ];
          return (
            <div className="row gap-6" style={{ alignItems: "stretch" }}>
              {stages.map((s, i) => (
                <React.Fragment key={s.label}>
                  <button onClick={() => goTo("clients")} className="col gap-4" style={{ flex: 1, padding: "10px 14px", background: s.bg, borderRadius: 8, border: "none", cursor: "pointer", textAlign: "left", transition: "opacity .15s" }}
                    onMouseEnter={e=>e.currentTarget.style.opacity=".85"} onMouseLeave={e=>e.currentTarget.style.opacity="1"}>
                    <span style={{ fontSize: 11, fontWeight: 600, color: s.color, textTransform: "uppercase", letterSpacing: ".04em" }}>{s.label}</span>
                    <span style={{ fontSize: 22, fontWeight: 700, color: s.color, lineHeight: 1 }}>{s.count}</span>
                  </button>
                  {i < stages.length - 1 && <div style={{ display: "flex", alignItems: "center", color: "var(--ink-3)", fontSize: 14 }}>→</div>}
                </React.Fragment>
              ))}
            </div>
          );
        })()}

        {/* Main split */}
        <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 20 }}>
          {/* Active onboarding clients */}
          <div className="col gap-12">
            <Section title="Onboarding in progress" sub="Clients currently working through the portal" right={
              <button className="btn-ghost btn btn-sm" onClick={() => goTo("clients")}>View all <Icon.arrow cls="ico-sm"/></button>
            }/>
            <Card pad={false}>
              <div style={{ display: "flex", flexDirection: "column" }}>
                {clients.filter(c => c.status !== "done").map((c, i, arr) => (
                  <ClientRow key={c.id} client={c} divider={i < arr.length - 1} onClick={() => { setActiveClientId(c.id); goTo("client-detail"); }}/>
                ))}
              </div>
            </Card>
          </div>

          {/* Activity */}
          <div className="col gap-12">
            <Section title="Recent activity"/>
            <Card pad={false}>
              <div style={{ display: "flex", flexDirection: "column" }}>
                {activity.length === 0
                  ? <div className="ink-3" style={{ padding: 16, fontSize: 12.5, lineHeight: 1.5 }}>No activity yet — this fills in as clients open their portal, complete intake, sign, and pay.</div>
                  : activity.map((a, i) => (
                      <ActivityRow key={a.id} a={a} last={i === activity.length - 1} onClick={() => { setActiveClientId(a.clientId); goTo("client-detail"); }}/>
                    ))}
              </div>
            </Card>
          </div>
        </div>

        {/* Invoice reminders — testable Brevo panel */}
        <InvoiceReminders goTo={goTo}/>

        {/* Quick links */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12 }}>
          <QuickLink icon={<Icon.template cls="ico-lg"/>} title="Edit your onboarding SOP" desc="Change steps, intake fields, agreement clauses — every new client uses your latest template." onClick={() => goTo("templates")}/>
          <QuickLink icon={<Icon.sparkle cls="ico-lg"/>} title="Paste a JD, get a client" desc="Drop in a job description and rate. We pre-fill SOW, agreement, and invoice for review." onClick={() => goTo("new")}/>
          <QuickLink icon={<Icon.inbox cls="ico-lg"/>} title="Inbox" desc="Every email, notification, and reminder the portal has sent — in one place." onClick={() => goTo("inbox")}/>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Invoice reminders — live Brevo-powered panel on the dashboard
// ─────────────────────────────────────────────────────────────────────
function InvoiceReminders({ goTo }) {
  const { clients, freelancer, paymentProviders } = useApp();
  const { toast } = useToast();
  const [cfg] = React.useState(loadBrevoConfig);
  const [sending, setSending] = React.useState(null);
  const [sentLog, setSentLog] = React.useState(() => lsLoad("reminder_log", []));
  const connected = (cfg.apiKey || cfg.proxyUrl) && cfg.senderEmail;

  // Unpaid invoices = clients whose deposit invoice isn't paid yet
  const unpaid = clients.filter(c => c.docs && c.docs.invoice && c.docs.invoice !== "paid");

  // Best available pay link from connected providers
  const payLink = (() => {
    const stripe = paymentProviders.find(p => p.id === "stripe" && p.paymentUrl);
    if (stripe) return stripe.paymentUrl;
    const pp = paymentProviders.find(p => p.id === "paypal" && p.paymentUrl);
    if (pp) return `https://www.${pp.paymentUrl}`;
    return null;
  })();

  const sendReminder = async (client, kind) => {
    const amount = client.hoursPerWeek ? client.rate : Math.round(client.rate * 0.5);
    const dueDate = client.startDate;
    const invoiceNo = `INV-${client.id.toUpperCase()}-001`;
    const { subject, html } = buildReminderEmail({
      client, freelancer, amount, currencyCode: freelancer.currency,
      dueDate, invoiceNo, payLink, kind,
    });

    if (!connected) {
      // No Brevo connected — show a preview instead so they can still test the flow
      const w = window.open("", "reminder-preview", "width=600,height=720,scrollbars=yes");
      if (w) { w.document.write(`<title>Reminder preview — ${subject}</title><div style="padding:20px;background:#f4f4f0;"><div style="font:13px sans-serif;color:#5B635E;margin-bottom:12px;">Subject: <b style="color:#0F1A14;">${subject}</b><br>To: ${client.email}</div>${html}</div>`); }
      toast("No Brevo key yet — showing email preview. Add your key in Settings → Notifications to actually send.", { kind: "warn", duration: 4500 });
      return;
    }

    setSending(client.id);
    try {
      await sendBrevoEmail({
        apiKey: cfg.apiKey, senderName: cfg.senderName || freelancer.brand, senderEmail: cfg.senderEmail,
        toEmail: client.email, toName: client.contact, subject, htmlContent: html,
      });
      const entry = { id: Date.now(), client: client.company, to: client.email, kind, when: new Date().toISOString() };
      const nextLog = [entry, ...sentLog].slice(0, 20);
      setSentLog(nextLog); lsSave("reminder_log", nextLog);
      toast(`Reminder sent to ${client.contact} at ${client.email}`, { kind: "success" });
    } catch (e) {
      const msg = String(e.message || e);
      if (msg.includes("Failed to fetch") || msg.includes("NetworkError")) {
        toast("Browser blocked Brevo (CORS) — needs a small proxy. Email preview still works.", { kind: "danger", duration: 5000 });
      } else {
        toast(msg, { kind: "danger", duration: 5000 });
      }
    } finally { setSending(null); }
  };

  return (
    <Card pad={false}>
      <div className="row" style={{ padding: "16px 18px", borderBottom: "1px solid var(--line)", justifyContent: "space-between", alignItems: "center" }}>
        <div className="col gap-2">
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <Icon.bell cls="ico-sm" style={{ color: "var(--primary)" }}/>
            <span style={{ fontSize: 14, fontWeight: 500 }}>Invoice reminders</span>
            {connected
              ? <span className="badge pill-active" style={{ fontSize: 10 }}>Brevo connected</span>
              : <span className="badge" style={{ fontSize: 10, background: "#FFF4E5", color: "#8A5E2C" }}>Preview mode</span>}
          </div>
          <div className="ink-3" style={{ fontSize: 12 }}>
            {unpaid.length} unpaid invoice{unpaid.length === 1 ? "" : "s"} · send a reminder now, or set up auto-schedule in Settings.
          </div>
        </div>
        <Button size="sm" variant="ghost" icon={<Icon.settings cls="ico-sm"/>} onClick={() => goTo("settings")}>Configure Brevo</Button>
      </div>

      {unpaid.length === 0 ? (
        <div style={{ padding: 28, textAlign: "center", color: "var(--ink-3)" }}>
          <Icon.check cls="ico-lg" style={{ color: "var(--success)" }}/>
          <div style={{ fontSize: 13.5, marginTop: 8 }}>No unpaid invoices — everyone's paid up.</div>
        </div>
      ) : unpaid.map((c, i) => {
        const amount = c.hoursPerWeek ? c.rate : Math.round(c.rate * 0.5);
        return (
          <div key={c.id} className="row gap-12" style={{ padding: "14px 18px", borderBottom: i < unpaid.length - 1 ? "1px solid var(--line-2)" : "none", alignItems: "center" }}>
            <Avatar name={c.company} size={36} bg={c.color[0]} fg={c.color[1]}/>
            <div className="col" style={{ flex: 1, lineHeight: 1.3, minWidth: 0 }}>
              <div style={{ fontSize: 13.5, fontWeight: 500 }}>{c.company}</div>
              <div className="ink-3" style={{ fontSize: 12 }}>{c.contact} · {c.email} · due {fmtDateShort(c.startDate)}</div>
            </div>
            <div className="col" style={{ textAlign: "right", minWidth: 90 }}>
              <span className="mono" style={{ fontSize: 14, fontWeight: 600 }}>{fmtMoney(amount, freelancer.currency)}</span>
              <span className="badge pill-pending" style={{ fontSize: 10, alignSelf: "flex-end" }}>Unpaid</span>
            </div>
            <div className="row gap-6">
              <Button size="sm" variant="ghost" disabled={sending === c.id} onClick={() => sendReminder(c, "before")}>Preview</Button>
              <Button size="sm" variant="primary" icon={<Icon.send cls="ico-sm"/>} disabled={sending === c.id} onClick={() => sendReminder(c, "after")}>
                {sending === c.id ? "Sending…" : "Send reminder"}
              </Button>
            </div>
          </div>
        );
      })}

      {sentLog.length > 0 && (
        <div style={{ padding: "10px 18px", borderTop: "1px solid var(--line)", background: "var(--surface-2)" }}>
          <div className="ink-3" style={{ fontSize: 11.5 }}>
            Last sent: <strong>{sentLog[0].client}</strong> ({sentLog[0].to}) · {fmtDate(sentLog[0].when)} · {sentLog.length} total
          </div>
        </div>
      )}
    </Card>
  );
}

function ClientRow({ client, divider, onClick }) {
  const stepLabel = ["Welcome", "Intake form", "Agreement", "Invoice", "Files", "Kickoff", "Active"][client.progress] || "Active";
  return (
    <div onClick={onClick} style={{ display: "grid", gridTemplateColumns: "1fr 130px 180px 80px", alignItems: "center", padding: "14px 18px", gap: 16, cursor: "pointer", borderBottom: divider ? "1px solid var(--line-2)" : "none" }}>
      <div className="row gap-12">
        <Avatar name={client.company} size={36} bg={client.color[0]} fg={client.color[1]}/>
        <div className="col" style={{ lineHeight: 1.25 }}>
          <div style={{ fontSize: 13.5, fontWeight: 500 }}>{client.company}</div>
          <div className="ink-3" style={{ fontSize: 12 }}>{client.role_title} · {client.rateLabel}</div>
        </div>
      </div>
      <Pill status={client.status}/>
      <div className="col gap-6">
        <div className="row" style={{ justifyContent: "space-between", fontSize: 11.5 }}>
          <span className="ink-3">{stepLabel}</span>
          <span className="ink-3 mono">{Math.min(6, client.progress)}/6</span>
        </div>
        <div style={{ height: 4, background: "var(--bg-2)", borderRadius: 999, overflow: "hidden" }}>
          <div style={{ width: `${Math.min(100, (client.progress/6)*100)}%`, height: "100%", background: "var(--primary)", borderRadius: 999 }}/>
        </div>
      </div>
      <div className="row" style={{ justifyContent: "flex-end" }}>
        <Icon.chevR cls="ico-sm" />
      </div>
    </div>
  );
}

function ActivityRow({ a, last, onClick }) {
  const map = {
    paid:         { ico: <Icon.money cls="ico-sm"/>, bg: "var(--primary-soft)", fg: "var(--primary)" },
    upload:       { ico: <Icon.upload cls="ico-sm"/>, bg: "#DDE6F4", fg: "#2C4D8A" },
    intake:       { ico: <Icon.doc cls="ico-sm"/>, bg: "#F4E8DB", fg: "#8A5E2C" },
    open:         { ico: <Icon.external cls="ico-sm"/>, bg: "var(--bg-2)", fg: "var(--ink-3)" },
    schedule:     { ico: <Icon.calendar cls="ico-sm"/>, bg: "#E8DEF0", fg: "#5B3F8A" },
    sign:         { ico: <Icon.signature cls="ico-sm"/>, bg: "var(--primary-soft)", fg: "var(--primary)" },
    lead_visit:   { ico: <Icon.globe cls="ico-sm"/>, bg: "#FEF3C7", fg: "#92400E" },
    lead_contact: { ico: <Icon.mail cls="ico-sm"/>, bg: "#FEF3C7", fg: "#92400E" },
  };
  const m = map[a.kind] || map.open;
  return (
    <div onClick={onClick} className="row gap-12" style={{ padding: "12px 16px", borderBottom: last ? "none" : "1px solid var(--line-2)", cursor: "pointer" }}>
      <div style={{ width: 28, height: 28, borderRadius: 7, background: m.bg, color: m.fg, display: "grid", placeItems: "center", flexShrink: 0 }}>{m.ico}</div>
      <div className="col" style={{ lineHeight: 1.3, flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 12.5 }}>
          <span style={{ fontWeight: 500 }}>{a.who}</span>
          <span className="ink-3"> · {a.company}</span>
        </div>
        <div className="ink-3" style={{ fontSize: 12 }}>{a.action} {a.amount && <span className="mono ink-2">· {a.amount}</span>}</div>
      </div>
      <div className="ink-3 mono" style={{ fontSize: 11 }}>{a.t}</div>
    </div>
  );
}

function QuickLink({ icon, title, desc, onClick }) {
  return (
    <button className="card" onClick={onClick} style={{ textAlign: "left", padding: 20, cursor: "pointer", display: "flex", flexDirection: "column", gap: 12, background: "var(--surface)", transition: "all .15s" }}
      onMouseEnter={e => e.currentTarget.style.borderColor = "var(--primary)"}
      onMouseLeave={e => e.currentTarget.style.borderColor = "var(--line)"}>
      <div style={{ width: 34, height: 34, borderRadius: 8, background: "var(--primary-soft)", color: "var(--primary)", display: "grid", placeItems: "center" }}>{icon}</div>
      <div className="col gap-4">
        <div style={{ fontSize: 13.5, fontWeight: 500 }}>{title}</div>
        <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.45 }}>{desc}</div>
      </div>
    </button>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Add Lead modal — quick capture before JD or full wizard
// ─────────────────────────────────────────────────────────────────────
function AddLeadModal({ onClose }) {
  const { updateClient } = useApp();
  const { toast, copyToClipboard } = useToast();
  const [name, setName] = React.useState("");
  const [email, setEmail] = React.useState("");
  const [company, setCompany] = React.useState("");
  const [source, setSource] = React.useState("OLJ");
  const [note, setNote] = React.useState("");
  const [saved, setSaved] = React.useState(null); // { id, link }

  const save = () => {
    if (!name.trim()) { toast("Name is required", { kind: "warn" }); return; }
    const id = "lead-" + Date.now();
    const link = generateReferralLink(id);
    updateClient(id, {
      id, contact: name.trim(), email: email.trim(), company: company.trim() || "—",
      status: "lead", leadSource: source, leadNote: note.trim(),
      leadAddedAt: new Date().toISOString(), referralLink: link,
      portfolioVisits: [], invitedAt: new Date().toISOString(),
      progress: 0, color: ["#FEF3C7", "#92400E"],
      docs: {}, skippedSteps: [], deliverables: [], milestones: [],
    });
    setTimeout(() => window.flushAllWorkspaceWrites && window.flushAllWorkspaceWrites(), 100);
    setSaved({ id, link });
  };

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(15,26,20,0.45)", backdropFilter: "blur(3px)", zIndex: 3000, display: "grid", placeItems: "center", padding: 24 }}>
      <div onClick={e => e.stopPropagation()} className="card fade-up" style={{ maxWidth: 460, width: "100%" }}>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "center", padding: "16px 20px", borderBottom: "1px solid var(--line)" }}>
          <div style={{ fontSize: 15, fontWeight: 600 }}>Add a lead</div>
          <button onClick={onClose} className="btn btn-ghost btn-sm" style={{ padding: 6 }}><Icon.x cls="ico-sm"/></button>
        </div>
        {saved ? (
          <div className="card-pad col gap-16">
            <div className="col gap-6">
              <div style={{ fontSize: 14, fontWeight: 500 }}>{name} added as a lead.</div>
              <div className="ink-3" style={{ fontSize: 13 }}>Send them this link when you message them — it tracks when they visit.</div>
            </div>
            <div className="col gap-6">
              <span className="label" style={{ fontSize: 10.5 }}>Referral link</span>
              <div className="row gap-8">
                <div className="input" style={{ flex: 1, fontSize: 12, color: "var(--ink-3)", wordBreak: "break-all", padding: "8px 12px" }}>{saved.link}</div>
                <Button size="sm" icon={<Icon.copy cls="ico-sm"/>} onClick={() => { copyToClipboard(saved.link); toast("Copied!", { kind: "success" }); }}>Copy</Button>
              </div>
            </div>
            <Button variant="primary" style={{ width: "100%", justifyContent: "center" }} onClick={onClose}>Done</Button>
          </div>
        ) : (
          <div className="card-pad col gap-12">
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
              <div className="col gap-4">
                <span className="label" style={{ fontSize: 10.5 }}>Name *</span>
                <input className="input" placeholder="Alex Rivera" value={name} onChange={e => setName(e.target.value)}/>
              </div>
              <div className="col gap-4">
                <span className="label" style={{ fontSize: 10.5 }}>Email</span>
                <input className="input" type="email" placeholder="alex@company.com" value={email} onChange={e => setEmail(e.target.value)}/>
              </div>
            </div>
            <div className="col gap-4">
              <span className="label" style={{ fontSize: 10.5 }}>Company (optional)</span>
              <input className="input" placeholder="Acme Corp" value={company} onChange={e => setCompany(e.target.value)}/>
            </div>
            <div className="col gap-4">
              <span className="label" style={{ fontSize: 10.5 }}>Where did you find them?</span>
              <select className="input" value={source} onChange={e => setSource(e.target.value)}>
                <option>OLJ</option>
                <option>LinkedIn</option>
                <option>Direct</option>
                <option>Referral</option>
                <option>Other</option>
              </select>
            </div>
            <div className="col gap-4">
              <span className="label" style={{ fontSize: 10.5 }}>Note (optional — just for you)</span>
              <textarea className="input" rows={2} placeholder="e.g. replied to my OLJ message, interested in OBM" value={note} onChange={e => setNote(e.target.value)} style={{ fontSize: 13, lineHeight: 1.5, resize: "none" }}/>
            </div>
            <div className="hr"/>
            <Button variant="primary" style={{ width: "100%", justifyContent: "center" }} onClick={save}>Add lead + get referral link</Button>
          </div>
        )}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Clients list
// ─────────────────────────────────────────────────────────────────────
function AdminClients({ goTo }) {
  const { clients, setActiveClientId, deleteClient } = useApp();
  const { toast } = useToast();
  const [filter, setFilter] = React.useState("all");
  const [showFilters, setShowFilters] = React.useState(false);
  const [showAddLead, setShowAddLead] = React.useState(false);
  const filtered = filter === "all" ? clients : clients.filter(c => c.status === filter);

  const removeClient = (e, c) => {
    e.stopPropagation();
    if (!confirm(`Delete ${c.company}? This permanently removes the client and their onboarding data from this device.`)) return;
    deleteClient(c.id);
    toast(`${c.company} deleted`, { kind: "warn" });
  };

  return (
    <div className="col" style={{ minHeight: "100vh" }}>
      {showAddLead && <AddLeadModal onClose={() => setShowAddLead(false)}/>}
      <PageHeader
        eyebrow="Clients"
        title="All clients"
        sub="Every client who's been sent a portal link, at every stage."
        right={<>
          <Button icon={<Icon.filter cls="ico-sm"/>} onClick={() => setShowFilters(s => !s)}>Filter {showFilters ? "↑" : "↓"}</Button>
          <Button icon={<Icon.flag cls="ico-sm"/>} onClick={() => setShowAddLead(true)}>+ Lead</Button>
          <Button variant="primary" icon={<Icon.plus cls="ico-sm"/>} onClick={() => goTo("new")}>New client</Button>
        </>}
      />
      <div style={{ padding: "20px 36px 48px" }}>
        {showFilters && (
          <Card className="fade-in" style={{ marginBottom: 14 }}>
            <div className="row gap-16">
              <div className="col gap-4" style={{ flex: 1 }}>
                <span className="label" style={{ fontSize: 10.5 }}>Engagement type</span>
                <select className="input" onChange={(e) => toast(`Filter: ${e.target.value}`)}>
                  <option>Any</option><option>Monthly retainer</option><option>Project</option><option>Hourly</option>
                </select>
              </div>
              <div className="col gap-4" style={{ flex: 1 }}>
                <span className="label" style={{ fontSize: 10.5 }}>Min. value</span>
                <input className="input" type="number" placeholder="$0" onChange={(e) => toast(`Min value: $${e.target.value}`)}/>
              </div>
              <div className="col gap-4" style={{ flex: 1 }}>
                <span className="label" style={{ fontSize: 10.5 }}>Invited</span>
                <select className="input" onChange={(e) => toast(`Date range: ${e.target.value}`)}>
                  <option>All time</option><option>Last 7 days</option><option>Last 30 days</option><option>Last 90 days</option>
                </select>
              </div>
            </div>
          </Card>
        )}
        <div className="row gap-6" style={{ marginBottom: 12 }}>
          {["lead", "all", "new", "pending", "active", "done"].map(f => (
            <button key={f} onClick={() => setFilter(f)} className="btn btn-sm" style={{
              background: filter === f ? (f === "lead" ? "#92400E" : "var(--ink)") : "transparent",
              color: filter === f ? "#fff" : (f === "lead" ? "#92400E" : "var(--ink-2)"),
              borderColor: filter === f ? (f === "lead" ? "#92400E" : "var(--ink)") : (f === "lead" ? "#D97706" : "var(--line)"),
              textTransform: "capitalize",
            }}>{f === "all" ? "All" : f === "lead" ? "Leads" : f} {filter !== f && <span style={{ opacity: .6 }}>·</span>} {filter !== f && <span style={{ opacity: .6 }}>{f === "all" ? clients.length : clients.filter(c => c.status === f).length}</span>}</button>
          ))}
        </div>
        <Card pad={false}>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 130px 1fr 130px 60px", padding: "10px 18px", borderBottom: "1px solid var(--line)", fontSize: 11, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: 0.04, fontWeight: 500 }}>
            <span>Client</span><span>Status</span><span>Onboarding</span><span>Started</span><span></span>
          </div>
          {filtered.map((c, i) => (
            <div key={c.id} onClick={() => { setActiveClientId(c.id); goTo("client-detail"); }}
              style={{ display: "grid", gridTemplateColumns: "1fr 130px 1fr 130px 60px", padding: "14px 18px", alignItems: "center", borderBottom: i < filtered.length - 1 ? "1px solid var(--line-2)" : "none", cursor: "pointer", gap: 16 }}>
              <div className="row gap-12">
                <Avatar name={c.company} size={32} bg={c.color[0]} fg={c.color[1]}/>
                <div className="col" style={{ lineHeight: 1.25, minWidth: 0 }}>
                  <div style={{ fontSize: 13.5, fontWeight: 500 }}>{c.company}</div>
                  <div className="ink-3" style={{ fontSize: 12 }}>{c.contact} · {c.role_title}</div>
                </div>
              </div>
              <Pill status={c.status}/>
              {c.status === "lead" ? (
                <div className="row gap-8" style={{ flexWrap: "wrap" }}>
                  <span style={{ fontSize: 11.5, padding: "2px 8px", borderRadius: 999, background: (c.portfolioVisits && c.portfolioVisits.length > 0) ? "#DCE8E1" : "var(--bg-2)", color: (c.portfolioVisits && c.portfolioVisits.length > 0) ? "#1B4332" : "var(--ink-3)" }}>
                    {(c.portfolioVisits && c.portfolioVisits.length > 0) ? `Visited ${c.portfolioVisits.length > 1 ? c.portfolioVisits.length + "×" : ""}` : "Not visited"}
                  </span>
                  {c.contactedDonnaAt && <span style={{ fontSize: 11.5, padding: "2px 8px", borderRadius: 999, background: "#FEF3C7", color: "#92400E" }}>Messaged</span>}
                  <span className="ink-3" style={{ fontSize: 11.5 }}>{c.leadSource || "—"}</span>
                </div>
              ) : (
                <div className="col gap-6" style={{ paddingRight: 24 }}>
                  <div style={{ height: 4, background: "var(--bg-2)", borderRadius: 999, overflow: "hidden" }}>
                    <div style={{ width: `${Math.min(100, (c.progress/6)*100)}%`, height: "100%", background: "var(--primary)", borderRadius: 999 }}/>
                  </div>
                  <div className="ink-3 mono" style={{ fontSize: 10.5 }}>{Math.min(6, c.progress)} / 6 steps</div>
                </div>
              )}
              <div className="ink-3" style={{ fontSize: 12 }}>{fmtDateShort(c.leadAddedAt || c.invitedAt)}</div>
              <div className="row gap-2" style={{ justifyContent: "flex-end" }}>
                <button className="btn btn-ghost btn-sm" title={`Delete ${c.company}`} onClick={(e) => removeClient(e, c)} style={{ padding: 5, color: "var(--ink-3)" }}><Icon.trash cls="ico-sm"/></button>
                <Icon.chevR cls="ico-sm"/>
              </div>
            </div>
          ))}
          {filtered.length === 0 && (
            <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)" }}>
              <Icon.users cls="ico-lg"/>
              <div style={{ fontSize: 13.5, marginTop: 8 }}>{filter === "lead" ? "No leads yet — add one when you message a prospect." : "No clients here yet."}</div>
              {filter === "lead"
                ? <Button icon={<Icon.flag cls="ico-sm"/>} onClick={() => setShowAddLead(true)} style={{ marginTop: 12 }}>Add a lead</Button>
                : <Button variant="primary" icon={<Icon.plus cls="ico-sm"/>} onClick={() => goTo("new")} style={{ marginTop: 12 }}>Add your first client</Button>}
            </div>
          )}
        </Card>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Client detail page — the freelancer's portal view of one client
// ─────────────────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────────────────
// Edit client — real, persisted editing of a client's details
// ─────────────────────────────────────────────────────────────────────
function EditClientModal({ client, onClose }) {
  const { updateClient } = useApp();
  const { toast } = useToast();
  const guessUnit = client.hoursPerWeek ? "month" : (/project/i.test(client.engagementType || "") ? "project" : "month");
  const [f, setF] = React.useState({
    company: client.company || "",
    contact: client.contact || "",
    email: client.email || "",
    role: client.role || "",
    role_title: client.role_title || "",
    engagementType: client.engagementType || "",
    rate: client.rate || 0,
    rateUnit: guessUnit,
    hoursPerWeek: client.hoursPerWeek || "",
    startDate: client.startDate ? new Date(client.startDate).toISOString().slice(0, 10) : "",
    timezone: client.timezone || "",
    website: client.website || "",
    industry: client.industry || "",
    size: client.size || "",
    deliverables: (client.deliverables || []).join("\n"),
  });
  const set = (k, v) => setF(s => ({ ...s, [k]: v }));

  const save = () => {
    const rateNum = Number(f.rate) || 0;
    updateClient(client.id, {
      company: f.company.trim() || client.company,
      contact: f.contact.trim(),
      email: f.email.trim(),
      role: f.role.trim(),
      role_title: f.role_title.trim(),
      engagementType: f.engagementType.trim(),
      rate: rateNum,
      rateLabel: `$${rateNum.toLocaleString()} / ${f.rateUnit}`,
      hoursPerWeek: f.hoursPerWeek ? Number(f.hoursPerWeek) : null,
      startDate: f.startDate ? new Date(f.startDate).toISOString() : client.startDate,
      timezone: f.timezone.trim() || client.timezone,
      website: f.website.trim(),
      industry: f.industry.trim(),
      size: f.size.trim(),
      deliverables: f.deliverables.split("\n").map(s => s.trim()).filter(Boolean),
    });
    setTimeout(() => window.flushAllWorkspaceWrites && window.flushAllWorkspaceWrites(), 100);
    toast("Client updated", { kind: "success" });
    onClose();
  };

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(15,26,20,0.45)", backdropFilter: "blur(3px)", zIndex: 3000, display: "grid", placeItems: "center", padding: 24 }}>
      <div onClick={e => e.stopPropagation()} className="card fade-up" style={{ maxWidth: 560, width: "100%", maxHeight: "88vh", overflowY: "auto" }}>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "center", padding: "16px 20px", borderBottom: "1px solid var(--line)", position: "sticky", top: 0, background: "var(--surface)", zIndex: 1 }}>
          <div style={{ fontSize: 15, fontWeight: 600 }}>Edit {client.company}</div>
          <button onClick={onClose} className="btn btn-ghost btn-sm" style={{ padding: 6 }}><Icon.x cls="ico-sm"/></button>
        </div>
        <div className="card-pad col gap-14">
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <Field label="Company"><input className="input" value={f.company} onChange={e => set("company", e.target.value)}/></Field>
            <Field label="Role / project title"><input className="input" value={f.role_title} onChange={e => set("role_title", e.target.value)}/></Field>
            <Field label="Contact name"><input className="input" value={f.contact} onChange={e => set("contact", e.target.value)}/></Field>
            <Field label="Contact email"><input className="input" type="email" value={f.email} onChange={e => set("email", e.target.value)}/></Field>
            <Field label="Contact role"><input className="input" value={f.role} onChange={e => set("role", e.target.value)} placeholder="e.g. Marketing Lead"/></Field>
            <Field label="Engagement type"><input className="input" value={f.engagementType} onChange={e => set("engagementType", e.target.value)} placeholder="e.g. Monthly retainer"/></Field>
            <Field label="Rate">
              <div className="row gap-8">
                <div style={{ position: "relative", flex: 1 }}>
                  <span style={{ position: "absolute", left: 12, top: 9, color: "var(--muted)", fontSize: 13 }}>$</span>
                  <input className="input" type="number" value={f.rate} onChange={e => set("rate", e.target.value)} style={{ paddingLeft: 22 }}/>
                </div>
                <select className="input" value={f.rateUnit} onChange={e => set("rateUnit", e.target.value)} style={{ width: 110 }}>
                  <option value="hour">/ hour</option>
                  <option value="week">/ week</option>
                  <option value="month">/ month</option>
                  <option value="project">/ project</option>
                </select>
              </div>
            </Field>
            <Field label="Hours / week"><input className="input" type="number" value={f.hoursPerWeek} onChange={e => set("hoursPerWeek", e.target.value)} placeholder="(blank for project)"/></Field>
            <Field label="Start date"><input className="input" type="date" value={f.startDate} onChange={e => set("startDate", e.target.value)}/></Field>
            <Field label="Timezone"><input className="input" value={f.timezone} onChange={e => set("timezone", e.target.value)} placeholder="e.g. PT, ET, PHT"/></Field>
            <Field label="Website"><input className="input" value={f.website} onChange={e => set("website", e.target.value)} placeholder="e.g. example.com"/></Field>
            <Field label="Industry"><input className="input" value={f.industry} onChange={e => set("industry", e.target.value)} placeholder="e.g. AI SaaS"/></Field>
          </div>
          <Field label="Deliverables (one per line)">
            <textarea className="input" rows={5} value={f.deliverables} onChange={e => set("deliverables", e.target.value)} style={{ fontSize: 13, lineHeight: 1.5 }}/>
          </Field>
        </div>
        <div className="row gap-8" style={{ padding: "14px 20px", borderTop: "1px solid var(--line)", justifyContent: "flex-end", position: "sticky", bottom: 0, background: "var(--surface)" }}>
          <Button onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={save}>Save changes</Button>
        </div>
      </div>
    </div>
  );
}

function AdminClientDetail({ goTo }) {
  const { clients, activeClientId, freelancer, updateClient, deleteClient, tweaks } = useApp();
  const { copyToClipboard, toast } = useToast();
  const client = clients.find(c => c.id === activeClientId) || clients[0];
  const [tab, setTab] = React.useState("overview");
  const [editing, setEditing] = React.useState(false);

  // All clients deleted → nothing to show
  if (!client) {
    return (
      <div className="col" style={{ minHeight: "100vh" }}>
        <PageHeader eyebrow="Clients" title="No clients yet" sub="You've cleared all clients. Add a real one to get started."/>
        <div style={{ padding: 36 }}>
          <Button variant="primary" icon={<Icon.plus cls="ico-sm"/>} onClick={() => goTo("new")}>New client</Button>
        </div>
      </div>
    );
  }

  const removeThisClient = () => {
    if (!confirm(`Delete ${client.company}? This permanently removes the client and their onboarding data from this device.`)) return;
    deleteClient(client.id);
    toast(`${client.company} deleted`, { kind: "warn" });
    goTo("clients");
  };
  const cur = freelancer.currency;
  const portalLink = generatePortalLink(client.company);
  const tabs = [
    { id: "overview", label: "Overview" },
    { id: "scope", label: "Scope & SOW" },
    { id: "docs", label: "Documents", count: 4 },
    { id: "access", label: "Access", count: (client.credentials || []).length || null },
    { id: "files", label: "Files", count: (client.files !== undefined ? client.files.length : (DEMO_FILE_IDS.includes(client.id) ? DEMO_FILES.length : 0)) || null },
    { id: "messages", label: "Messages", count: 2 },
    { id: "billing", label: "Billing" },
  ];

  const openAsClient = () => {
    // Mark this device as admin-previewing so the client code-gate is skipped,
    // then open the client's portal in a new tab.
    try { localStorage.setItem("relay_admin_preview", "1"); } catch {}
    window.open(`/?client=${clientSlug(client.company)}`, "_blank", "noopener");
    toast(`Opening ${client.company}'s portal in a new tab…`, { kind: "info" });
  };

  return (
    <div className="col" style={{ minHeight: "100vh" }}>
      {editing && <EditClientModal client={client} onClose={() => setEditing(false)}/>}
      <div style={{ padding: "20px 36px 0", background: "var(--bg)", borderBottom: "1px solid var(--line)" }}>
        <button onClick={() => goTo("clients")} className="btn btn-ghost btn-sm" style={{ marginLeft: -8, marginBottom: 14 }}>
          <Icon.arrowL cls="ico-sm"/> All clients
        </button>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "flex-end", gap: 24, paddingBottom: 18 }}>
          <div className="row gap-16">
            <Avatar name={client.company} size={56} bg={client.color[0]} fg={client.color[1]}/>
            <div className="col gap-4">
              <div className="row gap-12" style={{ alignItems: "center" }}>
                <span className="h-display" style={{ fontSize: 28, lineHeight: 1 }}>{client.company}</span>
                <Pill status={client.status}/>
              </div>
              <div className="ink-3" style={{ fontSize: 13 }}>{client.role_title} · {client.contact} ({client.role}) · {client.rateLabel}</div>
            </div>
          </div>
          <div className="row gap-8">
            <Button icon={<Icon.mail cls="ico-sm"/>} onClick={() => { window.location.href = `mailto:${client.email}`; toast(`Opening email to ${client.contact}…`); }}>Email</Button>
            <Button icon={<Icon.link cls="ico-sm"/>} onClick={() => copyToClipboard(portalLink, "Portal link copied")}>Portal link</Button>
            <Button icon={<Icon.pen cls="ico-sm"/>} onClick={() => setEditing(true)}>Edit</Button>
            <Button icon={<Icon.trash cls="ico-sm"/>} onClick={removeThisClient} style={{ color: "var(--danger)", borderColor: "var(--danger-soft)" }}>Delete</Button>
            <Button variant="primary" icon={<Icon.external cls="ico-sm"/>} onClick={openAsClient}>Open as client</Button>
          </div>
        </div>
        <div className="row gap-4" style={{ marginBottom: -1 }}>
          {tabs.map(t => (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              padding: "10px 14px", border: 0, background: "transparent",
              borderBottom: "2px solid " + (tab === t.id ? "var(--primary)" : "transparent"),
              color: tab === t.id ? "var(--ink)" : "var(--ink-3)", fontWeight: tab === t.id ? 500 : 400,
              fontSize: 13, letterSpacing: "-0.005em", cursor: "pointer",
            }}>
              {t.label}{t.count != null && <span className="ink-3 mono" style={{ fontSize: 11, marginLeft: 6 }}>{t.count}</span>}
            </button>
          ))}
        </div>
      </div>

      <div style={{ padding: "24px 36px 48px" }}>
        {tab === "overview" && <ClientOverview client={client} cur={cur} onEdit={() => setEditing(true)}/>}
        {tab === "scope" && <ClientScope client={client} cur={cur}/>}
        {tab === "docs" && <ClientDocs client={client}/>}
        {tab === "access" && <ClientAccess client={client}/>}
        {tab === "files" && <ClientFiles client={client}/>}
        {tab === "messages" && <ClientMessages client={client}/>}
        {tab === "billing" && <ClientBilling client={client} cur={cur}/>}
      </div>
    </div>
  );
}

// Per-client to-dos — your own reminders, checked off, persisted
function ClientTasks({ client }) {
  const { updateClient } = useApp();
  const tasks = client.tasks || [];
  const [text, setText] = React.useState("");
  const open = tasks.filter(t => !t.done).length;
  const add = () => {
    if (!text.trim()) return;
    updateClient(client.id, { tasks: [...tasks, { id: Date.now(), text: text.trim(), done: false, createdAt: new Date().toISOString() }] });
    setText("");
  };
  const toggle = (id) => updateClient(client.id, { tasks: tasks.map(t => t.id === id ? { ...t, done: !t.done } : t) });
  const del = (id) => updateClient(client.id, { tasks: tasks.filter(t => t.id !== id) });

  return (
    <Card>
      <div className="col gap-12">
        <div className="row" style={{ justifyContent: "space-between", alignItems: "center" }}>
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <Icon.check cls="ico-sm" style={{ color: "var(--primary)" }}/>
            <div style={{ fontSize: 14, fontWeight: 500 }}>Your to-dos</div>
          </div>
          {open > 0 && <span className="badge pill-pending" style={{ fontSize: 10.5 }}>{open} open</span>}
        </div>
        <div className="row gap-8">
          <input className="input" placeholder={`Add a reminder for yourself…`} value={text} onChange={e => setText(e.target.value)} onKeyDown={e => e.key === "Enter" && add()}/>
          <Button variant="primary" icon={<Icon.plus cls="ico-sm"/>} onClick={add}>Add</Button>
        </div>
        <div className="col gap-6">
          {tasks.length === 0 && <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.5 }}>Nothing yet. Jot down anything you need to remember — "chase the deposit", "send brand assets", "call Friday".</div>}
          {tasks.slice().sort((a, b) => (a.done === b.done ? 0 : a.done ? 1 : -1)).map(t => (
            <div key={t.id} className="row gap-10" style={{ padding: "8px 10px", border: "1px solid var(--line-2)", borderRadius: 8, background: t.done ? "var(--surface-2)" : "var(--surface)" }}>
              <button onClick={() => toggle(t.id)} style={{ width: 18, height: 18, borderRadius: 5, border: "1px solid " + (t.done ? "var(--primary)" : "var(--line)"), background: t.done ? "var(--primary)" : "transparent", display: "grid", placeItems: "center", cursor: "pointer", flexShrink: 0, padding: 0 }}>
                {t.done && <Icon.check cls="ico-sm" style={{ color: "#fff", width: 12, height: 12 }}/>}
              </button>
              <span style={{ flex: 1, fontSize: 13, textDecoration: t.done ? "line-through" : "none", color: t.done ? "var(--ink-3)" : "var(--ink)" }}>{t.text}</span>
              <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} onClick={() => del(t.id)}><Icon.trash cls="ico-sm"/></button>
            </div>
          ))}
        </div>
      </div>
    </Card>
  );
}

// Per-client notes — brain-dump, saved on blur
function ClientNotes({ client }) {
  const { updateClient } = useApp();
  const { toast } = useToast();
  const [notes, setNotes] = React.useState(client.notes || "");
  React.useEffect(() => { setNotes(client.notes || ""); }, [client.id]);
  const save = () => { if (notes !== (client.notes || "")) { updateClient(client.id, { notes }); toast("Notes saved", { kind: "success" }); } };
  return (
    <Card>
      <div className="col gap-10">
        <div className="row gap-8" style={{ alignItems: "center" }}>
          <Icon.doc cls="ico-sm" style={{ color: "var(--ink-3)" }}/>
          <div style={{ fontSize: 14, fontWeight: 500 }}>Notes</div>
        </div>
        <textarea className="input" rows={4} value={notes} onChange={e => setNotes(e.target.value)} onBlur={save}
          placeholder="Brain-dump anything: preferences, context, what's next… (e.g. 'prefers WhatsApp', 'kickoff moved to Tue')"
          style={{ fontSize: 13, lineHeight: 1.55 }}/>
        <span className="ink-3" style={{ fontSize: 11 }}>Saves automatically when you click away.</span>
      </div>
    </Card>
  );
}

function ClientOverview({ client, cur, onEdit }) {
  const { toast, copyToClipboard } = useToast();
  const { template, updateClient, freelancer } = useApp();
  const [sendingDocs, setSendingDocs] = React.useState(false);
  const [docStatus, setDocStatus] = React.useState("");
  const [sendingNudge, setSendingNudge] = React.useState(false);
  const [nudgeModal, setNudgeModal] = React.useState(null); // { subject, note } when open

  const sendPortalNudge = () => {
    if (!client.email) { toast("Add the client's email first", { kind: "warn" }); return; }
    const cfg = window.loadBrevoConfig();
    const connected = !!(cfg.proxyUrl || cfg.apiKey);
    const { subject } = window.buildPortalNudgeEmail({ client, freelancer });
    if (!connected) {
      const { html } = window.buildPortalNudgeEmail({ client, freelancer });
      const w = window.open("", "nudge-preview", "width=600,height=720,scrollbars=yes");
      if (w) { w.document.write(`<title>Portal nudge preview</title><div style="padding:20px;background:#f4f4f0;"><div style="font:13px sans-serif;color:#5B635E;margin-bottom:12px;">Subject: <b style="color:#0F1A14;">${subject}</b><br>To: ${client.email}</div>${html}</div>`); }
      toast("Brevo not connected — showing preview only.", { kind: "warn", duration: 4500 });
      return;
    }
    setNudgeModal({ subject, note: "" });
  };

  const doSendNudge = async ({ subject, note }) => {
    const cfg = window.loadBrevoConfig();
    const { html } = window.buildPortalNudgeEmail({ client, freelancer, note, subjectOverride: subject });
    setNudgeModal(null);
    setSendingNudge(true);
    try {
      await window.sendBrevoEmail({
        apiKey: cfg.apiKey, senderName: cfg.senderName || freelancer.brand,
        senderEmail: cfg.senderEmail, toEmail: client.email, toName: client.contact,
        subject, htmlContent: html,
      });
      updateClient(client.id, { portalNudgeSentAt: new Date().toISOString() });
      toast(`Portal link sent to ${client.email}`, { kind: "success" });
    } catch (e) {
      toast(String(e.message || e), { kind: "danger", duration: 5000 });
    } finally { setSendingNudge(false); }
  };
  const steps = ["Welcome", "Intake", "Agreement", "Invoice", "Files", "Kickoff"];

  const promoteToClient = () => {
    updateClient(client.id, { status: "new" });
    setTimeout(() => { window.flushAllWorkspaceWrites && window.flushAllWorkspaceWrites(); }, 100);
    toast("Promoted to client — now send the portal link when you're ready.", { kind: "success" });
  };

  const sendSignedDocs = async () => {
    if (!client.email) { toast("Add the client's email first", { kind: "warn" }); return; }
    if (!confirm(`Email the signed PDFs to ${client.contact} (${client.email})?`)) return;
    setSendingDocs(true);
    try {
      const atts = await window.emailSignedDocs({ client, freelancer, template, onProgress: setDocStatus });
      updateClient(client.id, { signedDocs: atts.map(a => ({ name: a.name, url: a.url })), signedDocsSentAt: new Date().toISOString() });
      toast(`Signed copies sent to ${client.email}`, { kind: "success" });
    } catch (e) {
      toast(String(e.message || e), { kind: "danger", duration: 6000 });
    } finally { setSendingDocs(false); setDocStatus(""); }
  };

  const toggleClientStep = (stepId) => {
    const skipped = client.skippedSteps || [];
    const nowSkipping = !skipped.includes(stepId);
    const newSkipped = nowSkipping ? [...skipped, stepId] : skipped.filter(id => id !== stepId);
    updateClient(client.id, { skippedSteps: newSkipped });
    setTimeout(() => window.flushAllWorkspaceWrites(), 100);
    toast(nowSkipping ? "Step hidden from portal" : "Step restored to portal", { kind: "success" });
  };
  return (
    <>
    {nudgeModal && (
      <div onClick={() => setNudgeModal(null)} style={{ position: "fixed", inset: 0, background: "rgba(15,26,20,0.45)", backdropFilter: "blur(3px)", zIndex: 3000, display: "grid", placeItems: "center", padding: 24 }}>
        <div onClick={e => e.stopPropagation()} className="card fade-up" style={{ maxWidth: 500, width: "100%" }}>
          <div className="row" style={{ justifyContent: "space-between", alignItems: "center", padding: "16px 20px", borderBottom: "1px solid var(--line)" }}>
            <div style={{ fontSize: 15, fontWeight: 600 }}>Send portal link to {client.contact.split(" ")[0]}</div>
            <button onClick={() => setNudgeModal(null)} className="btn btn-ghost btn-sm" style={{ padding: 6 }}><Icon.x cls="ico-sm"/></button>
          </div>
          <div className="card-pad col gap-14">
            <Field label="To"><div style={{ padding: "8px 12px", background: "var(--surface-2)", borderRadius: 8, fontSize: 13, color: "var(--ink-3)", border: "1px solid var(--line-2)" }}>{client.email}</div></Field>
            <Field label="Subject">
              <input className="input" value={nudgeModal.subject} onChange={e => setNudgeModal(m => ({ ...m, subject: e.target.value }))}/>
            </Field>
            <Field label={`Personal note to ${client.contact.split(" ")[0]} (optional)`}>
              <textarea className="input" rows={3} value={nudgeModal.note}
                onChange={e => setNudgeModal(m => ({ ...m, note: e.target.value }))}
                placeholder={`Hi ${client.contact.split(" ")[0]}, just following up — here's your portal link whenever you're ready.`}
                style={{ fontSize: 13, lineHeight: 1.5, resize: "vertical" }}/>
              <span className="ink-3" style={{ fontSize: 11 }}>This appears above the portal button. Leave blank for the default message.</span>
            </Field>
          </div>
          <div className="row gap-8" style={{ padding: "14px 20px", borderTop: "1px solid var(--line)", justifyContent: "space-between" }}>
            <Button size="sm" variant="ghost" icon={<Icon.external cls="ico-sm"/>} onClick={() => {
              const { html } = window.buildPortalNudgeEmail({ client, freelancer, note: nudgeModal.note, subjectOverride: nudgeModal.subject });
              const w = window.open("", "nudge-prev", "width=620,height=760,scrollbars=yes");
              if (w) w.document.write(`<title>Email preview</title><div style="padding:20px;background:#f4f4f0;font:13px sans-serif;color:#5B635E;margin-bottom:12px;">Subject: <b style="color:#0F1A14;">${nudgeModal.subject}</b><br>To: ${client.email}</div>${html}`);
            }}>Preview email</Button>
            <div className="row gap-8">
              <Button onClick={() => setNudgeModal(null)}>Cancel</Button>
              <Button variant="primary" icon={<Icon.send cls="ico-sm"/>} disabled={sendingNudge} onClick={() => doSendNudge(nudgeModal)}>
                {sendingNudge ? "Sending…" : "Send now"}
              </Button>
            </div>
          </div>
        </div>
      </div>
    )}
    <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 20 }}>
      <div className="col gap-20">

        {/* Lead pipeline card — only for leads */}
        {client.status === "lead" && (() => {
          const link = client.referralLink || generateReferralLink(client.id);
          const visits = client.portfolioVisits || [];
          const stages = [
            { label: "Lead added", ts: client.leadAddedAt, done: true },
            { label: "Portfolio visited", ts: visits.length ? visits[visits.length-1].ts : null, done: visits.length > 0 },
            { label: "Messaged you", ts: client.contactedDonnaAt, done: !!client.contactedDonnaAt },
          ];
          return (
            <Card>
              <div className="col gap-16">
                <div className="row" style={{ justifyContent: "space-between", alignItems: "center" }}>
                  <div className="col gap-2">
                    <div style={{ fontSize: 14, fontWeight: 500 }}>Lead pipeline</div>
                    <div className="ink-3" style={{ fontSize: 12 }}>Tracking every step from first contact to invite.</div>
                  </div>
                  <Button variant="primary" size="sm" icon={<Icon.arrow cls="ico-sm"/>} onClick={promoteToClient}>Promote to client</Button>
                </div>
                <div className="hr"/>
                {/* Timeline */}
                <div className="col gap-6">
                  {stages.map((s, i) => (
                    <div key={s.label} className="row gap-10" style={{ alignItems: "center" }}>
                      <div style={{ width: 18, height: 18, borderRadius: "50%", flexShrink: 0, background: s.done ? "var(--primary)" : "var(--bg-2)", border: "1px solid " + (s.done ? "var(--primary)" : "var(--line)"), display: "grid", placeItems: "center" }}>
                        {s.done && <Icon.check cls="ico-sm" style={{ stroke: "#fff", width: 10 }}/>}
                      </div>
                      <div style={{ flex: 1, fontSize: 13, color: s.done ? "var(--ink)" : "var(--ink-3)" }}>{s.label}</div>
                      <div className="ink-3 mono" style={{ fontSize: 11 }}>{s.ts ? _relTime(s.ts) : "—"}</div>
                    </div>
                  ))}
                </div>
                <div className="hr"/>
                {/* Referral link */}
                <div className="col gap-6">
                  <span className="label" style={{ fontSize: 10.5 }}>Referral link — share this in your message</span>
                  <div className="row gap-8">
                    <div style={{ flex: 1, fontSize: 12, color: "var(--ink-3)", padding: "7px 10px", background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: 7, wordBreak: "break-all" }}>{link}</div>
                    <Button size="sm" icon={<Icon.copy cls="ico-sm"/>} onClick={() => { copyToClipboard(link); toast("Copied!", { kind: "success" }); }}>Copy</Button>
                  </div>
                </div>
                {/* Contact message */}
                {client.contactedDonnaAt && client.contactMessage && (
                  <>
                    <div className="hr"/>
                    <div className="col gap-6">
                      <div className="row" style={{ justifyContent: "space-between" }}>
                        <span className="label" style={{ fontSize: 10.5 }}>Their message</span>
                        <span className="ink-3 mono" style={{ fontSize: 11 }}>{fmtDate(client.contactedDonnaAt)}</span>
                      </div>
                      <div style={{ fontSize: 13, lineHeight: 1.6, padding: "10px 12px", background: "var(--surface-2)", borderRadius: 8, borderLeft: "3px solid var(--primary-soft)", whiteSpace: "pre-wrap" }}>{client.contactMessage}</div>
                    </div>
                  </>
                )}
              </div>
            </Card>
          );
        })()}

        {/* Onboarding tracker — hidden for leads */}
        {client.status !== "lead" && <Card>
          <div className="row" style={{ justifyContent: "space-between", marginBottom: 16 }}>
            <div className="col gap-2">
              <div style={{ fontSize: 14, fontWeight: 500 }}>Onboarding progress</div>
              <div className="ink-3" style={{ fontSize: 12 }}>Live mirror of what the client sees in their portal.</div>
            </div>
            <div className="row gap-10" style={{ alignItems: "center" }}>
              <div className="ink-3 mono" style={{ fontSize: 12 }}>{Math.min(6, client.progress)} / 6 complete</div>
              <Button size="sm" variant={client.progress === 0 ? "primary" : "ghost"} icon={<Icon.send cls="ico-sm"/>} disabled={sendingNudge} onClick={sendPortalNudge}>
                {sendingNudge ? "Sending…" : "Send portal link"}
              </Button>
            </div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 8 }}>
            {steps.map((s, i) => {
              const done = i < client.progress;
              const current = i === client.progress;
              return (
                <div key={s} className="col gap-6" style={{ alignItems: "flex-start" }}>
                  <div style={{ height: 4, background: done ? "var(--primary)" : current ? "var(--primary-soft)" : "var(--bg-2)", borderRadius: 999, width: "100%" }}/>
                  <div className="row gap-4" style={{ fontSize: 11.5 }}>
                    <span style={{ width: 14, height: 14, borderRadius: "50%", background: done ? "var(--primary)" : "transparent", border: "1px solid " + (done ? "var(--primary)" : current ? "var(--primary)" : "var(--line)"), display: "grid", placeItems: "center", color: "#fff" }}>
                      {done && <Icon.check cls="ico-sm" />}
                    </span>
                    <span style={{ color: done || current ? "var(--ink)" : "var(--ink-3)", fontWeight: current ? 500 : 400 }}>{s}</span>
                  </div>
                </div>
              );
            })}
          </div>
        </Card>}

        {/* Signature record — shown only after the client has signed */}
        {client.signature && (
          <Card>
            <div className="col gap-12">
              <div className="row gap-8" style={{ alignItems: "center", justifyContent: "space-between" }}>
                <div className="row gap-8" style={{ alignItems: "center" }}>
                  <span style={{ width: 26, height: 26, borderRadius: "50%", background: "var(--primary)", color: "#fff", display: "grid", placeItems: "center" }}>
                    <Icon.check cls="ico-sm"/>
                  </span>
                  <div className="col" style={{ lineHeight: 1.25 }}>
                    <div style={{ fontSize: 14, fontWeight: 500 }}>Signed by {client.signature.name}</div>
                    <div className="ink-3" style={{ fontSize: 11.5 }}>
                      {(() => { try { return new Date(client.signature.signedAt).toLocaleString("en-US", { dateStyle: "long", timeStyle: "short" }); } catch { return client.signature.signedAt; } })()}
                    </div>
                  </div>
                </div>
                <span className="badge pill-active mono" style={{ fontSize: 10 }}>Signed</span>
              </div>
              <div className="hr"/>
              <div style={{ display: "grid", gridTemplateColumns: "120px 1fr", rowGap: 8, columnGap: 14, fontSize: 12.5 }}>
                <span className="ink-3">Typed name</span>
                <span style={{ fontFamily: "Instrument Serif", fontSize: 20, fontStyle: "italic" }}>{client.signature.name}</span>
                <span className="ink-3">Documents</span>
                <span>{(client.signature.docsAccepted || []).map(d => ({ agreement: "Service Agreement", sow: "Statement of Work", nda: "Mutual NDA" }[d] || d)).join(", ") || "—"}</span>
                <span className="ink-3">Timezone</span>
                <span className="mono" style={{ fontSize: 11.5 }}>{client.signature.tz || "—"}</span>
                <span className="ink-3">Device</span>
                <span className="mono ink-3" style={{ fontSize: 10.5, wordBreak: "break-all" }}>{client.signature.userAgent || "—"}</span>
              </div>
              <div className="hr"/>
              <div className="col gap-8">
                <div className="row gap-8" style={{ justifyContent: "space-between", alignItems: "center" }}>
                  <span className="label-lc" style={{ fontSize: 12 }}>Signed copies (PDF)</span>
                  <Button size="sm" variant="primary" icon={<Icon.send cls="ico-sm"/>} disabled={sendingDocs} onClick={sendSignedDocs}>
                    {sendingDocs ? (docStatus || "Working…") : (client.signedDocs ? "Resend to client" : "Send to client")}
                  </Button>
                </div>
                {client.signedDocs && client.signedDocs.length > 0 && (
                  <div className="col gap-4">
                    <span className="ink-3" style={{ fontSize: 11 }}>Sent{client.signedDocsSentAt ? " " + fmtDate(client.signedDocsSentAt) : ""} · click to download</span>
                    <div className="row gap-6" style={{ flexWrap: "wrap" }}>
                      {client.signedDocs.map((d, i) => (
                        <a key={i} href={d.url} target="_blank" rel="noreferrer" className="btn btn-sm btn-ghost" style={{ fontSize: 11 }}><Icon.download cls="ico-sm"/> {d.name}</a>
                      ))}
                    </div>
                  </div>
                )}
              </div>
            </div>
          </Card>
        )}

        {/* Intake responses — shown once the client submits the intake form */}
        {client.intake && (
          <Card>
            <div className="col gap-12">
              <div className="row" style={{ justifyContent: "space-between", alignItems: "center" }}>
                <div style={{ fontSize: 14, fontWeight: 500 }}>Intake responses</div>
                {client.intake.submittedAt && <span className="ink-3" style={{ fontSize: 11 }}>Submitted {fmtDate(client.intake.submittedAt)}</span>}
              </div>
              <div className="hr"/>
              <div className="col gap-10">
                {(template.intake_fields || []).map(f => {
                  const v = client.intake[f.id];
                  if (v == null || !String(v).trim()) return null;
                  return (
                    <div key={f.id} className="col gap-2">
                      <span className="ink-3" style={{ fontSize: 11 }}>{f.label}</span>
                      <span style={{ fontSize: 13, lineHeight: 1.5, whiteSpace: "pre-wrap" }}>{String(v)}</span>
                    </div>
                  );
                })}
              </div>
            </div>
          </Card>
        )}

        {/* Files the client uploaded from their portal */}
        {client.files && client.files.length > 0 && (
          <Card>
            <div className="col gap-12">
              <div style={{ fontSize: 14, fontWeight: 500 }}>Files from {client.contact.split(" ")[0]} ({client.files.length})</div>
              <div className="hr"/>
              <div className="col gap-8">
                {client.files.map((f, i) => (
                  <div key={i} className="row gap-10" style={{ alignItems: "center" }}>
                    <div style={{ width: 28, height: 34, borderRadius: 4, background: "var(--bg-2)", color: "var(--ink-3)", fontSize: 9, fontWeight: 600, display: "grid", placeItems: "center", textTransform: "uppercase" }}>{f.kind}</div>
                    <div className="col" style={{ flex: 1, minWidth: 0, lineHeight: 1.3 }}>
                      <a href={f.url} target="_blank" rel="noreferrer" style={{ fontSize: 13, color: "var(--primary)", textDecoration: "none", wordBreak: "break-all" }}>{f.name}</a>
                      <span className="ink-3" style={{ fontSize: 11 }}>{f.size}</span>
                    </div>
                    <a href={f.url} target="_blank" rel="noreferrer" className="btn btn-sm btn-ghost" title="Download"><Icon.download cls="ico-sm"/></a>
                  </div>
                ))}
              </div>
            </div>
          </Card>
        )}

        {/* Engagement summary */}
        <Card>
          <div className="col gap-12">
            <div className="row" style={{ justifyContent: "space-between" }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>Engagement</div>
              <Button size="sm" variant="ghost" icon={<Icon.pen cls="ico-sm"/>} onClick={onEdit}>Edit scope</Button>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 14, padding: "8px 0" }}>
              <KV label="Role" value={client.role_title}/>
              <KV label="Type" value={client.engagementType}/>
              <KV label="Rate" value={client.rateLabel}/>
              <KV label="Start date" value={fmtDate(client.startDate)}/>
              <KV label="Hours / week" value={client.hoursPerWeek ? `${client.hoursPerWeek}h` : "—"}/>
              <KV label="Timezone" value={client.timezone}/>
              <KV label="Contact" value={client.contact}/>
              <KV label="Email" value={client.email}/>
            </div>
          </div>
        </Card>

        {/* Deliverables */}
        <Card>
          <div className="col gap-12">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Deliverables</div>
            <div className="col gap-8">
              {client.deliverables.map((d, i) => (
                <div key={i} className="row gap-8" style={{ alignItems: "flex-start", fontSize: 13, lineHeight: 1.5 }}>
                  <span style={{ width: 18, height: 18, borderRadius: "50%", background: "var(--primary-soft)", color: "var(--primary)", display: "grid", placeItems: "center", fontSize: 10, fontWeight: 600, flexShrink: 0, marginTop: 2 }}>{i+1}</span>
                  <span>{d}</span>
                </div>
              ))}
            </div>
          </div>
        </Card>
      </div>

      <div className="col gap-20">
        {/* Your to-dos */}
        <ClientTasks client={client}/>

        {/* Notes */}
        <ClientNotes client={client}/>

        {/* Milestones */}
        <Card>
          <div className="col gap-12">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Milestones</div>
            {client.milestones.map((m, i) => (
              <div key={i} className="col gap-6" style={{ paddingBottom: 10, borderBottom: i < client.milestones.length - 1 ? "1px solid var(--line-2)" : "none" }}>
                <div className="row" style={{ justifyContent: "space-between" }}>
                  <span style={{ fontSize: 13 }}>{m.name}</span>
                  <span className="ink-3 mono" style={{ fontSize: 11 }}>{fmtDateShort(m.date)}</span>
                </div>
                <div style={{ height: 4, background: "var(--bg-2)", borderRadius: 999, overflow: "hidden" }}>
                  <div style={{ width: `${m.pct}%`, height: "100%", background: m.pct === 100 ? "var(--success)" : "var(--primary)", borderRadius: 999 }}/>
                </div>
              </div>
            ))}
          </div>
        </Card>

        {/* Doc status — hidden for leads */}
        {client.status !== "lead" && <Card>
          <div className="col gap-12">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Documents</div>
            {[
              { id: "agreement", label: "Service Agreement", icon: Icon.shield },
              { id: "sow", label: "Statement of Work", icon: Icon.briefcase },
              { id: "nda", label: "NDA", icon: Icon.shield },
              { id: "invoice", label: "Deposit invoice", icon: Icon.money },
            ].map(d => {
              const Ico = d.icon;
              const st = (client.docs || {})[d.id];
              const pill = { draft: { label: "Draft", color: "var(--ink-3)" }, signed: { label: "Signed", color: "var(--success)" }, paid: { label: "Paid", color: "var(--success)" }, skipped: { label: "Skipped", color: "var(--muted)" } }[st] || { label: "—", color: "var(--ink-3)" };
              return (
                <div key={d.id} className="row gap-10" style={{ padding: "8px 0", borderBottom: "1px solid var(--line-2)" }}>
                  <Ico cls="ico-sm"/>
                  <span style={{ flex: 1, fontSize: 13 }}>{d.label}</span>
                  <span style={{ fontSize: 11.5, color: pill.color, fontWeight: 500 }}>{pill.label}</span>
                  <button className="btn btn-sm btn-ghost"><Icon.external cls="ico-sm"/></button>
                </div>
              );
            })}
          </div>
        </Card>}

        {/* Per-client step control — hidden for leads */}
        {client.status !== "lead" && <Card>
          <div className="col gap-10">
            <div className="row" style={{ justifyContent: "space-between", alignItems: "center" }}>
              <div className="col gap-2">
                <div style={{ fontSize: 14, fontWeight: 500 }}>Portal steps</div>
                <div className="ink-3" style={{ fontSize: 12 }}>Choose what this client sees.</div>
              </div>
              <span className="ink-3" style={{ fontSize: 12 }}>
                {(template.steps.filter(s => s.enabled !== false && !(client.skippedSteps || []).includes(s.id))).length} active
              </span>
            </div>
            {template.steps.filter(s => s.enabled !== false).map((s, i, arr) => {
              const isSkipped = (client.skippedSteps || []).includes(s.id);
              return (
                <div key={s.id} className="row gap-10" style={{ padding: "8px 0", borderBottom: i < arr.length - 1 ? "1px solid var(--line-2)" : "none", alignItems: "center" }}>
                  <Toggle on={!isSkipped} onClick={() => toggleClientStep(s.id)}/>
                  <span style={{ flex: 1, fontSize: 13, color: isSkipped ? "var(--ink-3)" : "var(--ink)", textDecoration: isSkipped ? "line-through" : "none" }}>{s.label}</span>
                </div>
              );
            })}
          </div>
        </Card>}
      </div>
    </div>
    </>
  );
}

function KV({ label, value }) {
  return (
    <div className="col gap-2">
      <div className="label" style={{ fontSize: 10.5 }}>{label}</div>
      <div style={{ fontSize: 13, color: "var(--ink)", fontWeight: 400 }}>{value}</div>
    </div>
  );
}

function ClientScope({ client, cur }) {
  const { toast } = useToast();
  const { freelancer, template } = useApp();
  const openSOW = () => {
    try {
      const html = window.buildDocHTML({ docKey: "sow", client, freelancer, template });
      const w = window.open("", "_blank");
      if (!w) { toast("Allow pop-ups to open the SOW", { kind: "warn" }); return; }
      w.document.open(); w.document.write(html); w.document.close();
    } catch (e) { toast("Couldn't open SOW", { kind: "danger" }); }
  };
  return (
    <div className="col gap-20">
      <Card>
        <div className="col gap-12">
          <div className="row" style={{ justifyContent: "space-between" }}>
            <div style={{ fontSize: 14, fontWeight: 500 }}>Statement of Work</div>
            <div className="row gap-6">
              <Button size="sm" icon={<Icon.external cls="ico-sm"/>} onClick={openSOW}>Open / Print</Button>
            </div>
          </div>
          <div className="ink-3" style={{ fontSize: 12.5 }}>Built from this client's scope. To change the wording, use <strong>Documents → Statement of Work → Edit</strong>. To change scope/rate, use <strong>Edit</strong> (top right).</div>
          <div className="hr"/>
          <SOWDocument client={client}/>
        </div>
      </Card>
    </div>
  );
}

function SOWDocument({ client }) {
  const { freelancer, template } = useApp();
  const overrideHtml = window.buildDocInlineHTML && window.buildDocInlineHTML({ docKey: "sow", client, freelancer, template });
  return (
    <div className="doc-paper">
      <div className="row" style={{ justifyContent: "space-between", alignItems: "flex-start", marginBottom: 24 }}>
        <div>
          <h1>Statement of Work</h1>
          <div className="ink-3" style={{ fontSize: 12 }}>Exhibit A · Reference SOW-{clientSlug(client.company).toUpperCase()}-001</div>
        </div>
        <div className="col gap-2" style={{ textAlign: "right", fontSize: 12 }}>
          <div className="ink-3">Effective</div>
          <div className="mono">{fmtDate(client.startDate)}</div>
        </div>
      </div>

      {overrideHtml
        ? <div dangerouslySetInnerHTML={{ __html: overrideHtml }} />
        : <>
            <h2>Parties</h2>
            <p><strong>Service Provider:</strong> {freelancer.name} d/b/a {freelancer.brand}<br/>
            <strong>Client:</strong> {client.company} ({client.contact}, {client.role})</p>

            <h2>Engagement</h2>
            <p>{client.role_title} — {client.engagementType.toLowerCase()}, {client.hoursPerWeek ? `${client.hoursPerWeek} hours per week` : "fixed-scope project"}.</p>

            <h2>Deliverables</h2>
            <ol style={{ paddingLeft: 18, margin: "0 0 12px" }}>
              {client.deliverables.map((d, i) => <li key={i} style={{ marginBottom: 4 }}>{d}</li>)}
            </ol>

            <h2>Timeline</h2>
            <ul style={{ paddingLeft: 18, margin: "0 0 12px" }}>
              {client.milestones.map((m, i) => <li key={i} style={{ marginBottom: 4 }}>{m.name} — <span className="mono">{fmtDate(m.date)}</span></li>)}
            </ul>

            <h2>Compensation</h2>
            <p>{client.rateLabel}. {client.hoursPerWeek ? "Invoiced monthly in advance, net 7." : "50% deposit on signature; remainder upon delivery."}</p>
          </>
      }
    </div>
  );
}

function DocEditModal({ client, docKey, label, onClose }) {
  const { updateClient, freelancer, template } = useApp();
  const { toast } = useToast();
  const existing = client.docOverrides && client.docOverrides[docKey];
  const [text, setText] = React.useState(() =>
    (existing && existing.body) || window.buildDocText({ docKey, client, freelancer, template }));
  const isCustom = !!(existing && existing.body && existing.body.trim());

  const save = () => {
    updateClient(client.id, { docOverrides: { ...(client.docOverrides || {}), [docKey]: { body: text } } });
    setTimeout(() => window.flushAllWorkspaceWrites(), 100);
    toast(`${label} saved for ${client.company}`, { kind: "success" });
    onClose();
  };
  const reset = () => {
    if (!confirm("Reset to your template default? Your custom edits for this client will be removed.")) return;
    const next = { ...(client.docOverrides || {}) }; delete next[docKey];
    updateClient(client.id, { docOverrides: next });
    toast("Reset to template", { kind: "warn" });
    onClose();
  };

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(15,26,20,0.45)", backdropFilter: "blur(3px)", zIndex: 3000, display: "grid", placeItems: "center", padding: 24 }}>
      <div onClick={e => e.stopPropagation()} className="card fade-up" style={{ maxWidth: 720, width: "100%", maxHeight: "90vh", display: "flex", flexDirection: "column" }}>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "center", padding: "16px 20px", borderBottom: "1px solid var(--line)" }}>
          <div className="col gap-2">
            <div style={{ fontSize: 15, fontWeight: 600 }}>Edit {label} — {client.company}</div>
            <div className="ink-3" style={{ fontSize: 11.5 }}>Only this client's copy changes. Your master template stays the same.</div>
          </div>
          <button onClick={onClose} className="btn btn-ghost btn-sm" style={{ padding: 6 }}><Icon.x cls="ico-sm"/></button>
        </div>
        <div className="card-pad col gap-10" style={{ overflowY: "auto" }}>
          <div className="row gap-8" style={{ padding: 10, background: "var(--surface-2)", border: "1px solid var(--line-2)", borderRadius: 8, fontSize: 11.5, lineHeight: 1.5 }}>
            <Icon.pen cls="ico-sm" style={{ flexShrink: 0 }}/>
            <span>Formatting: start a line with <span className="mono">#</span> for a heading, <span className="mono">-</span> for a bullet. Blank lines separate paragraphs.</span>
          </div>
          <textarea className="input" value={text} onChange={e => setText(e.target.value)} rows={20}
            style={{ fontSize: 13, lineHeight: 1.6, fontFamily: "Geist Mono, monospace" }}/>
        </div>
        <div className="row" style={{ padding: "14px 20px", borderTop: "1px solid var(--line)", justifyContent: "space-between" }}>
          <div>{isCustom && <Button variant="ghost" icon={<Icon.refresh cls="ico-sm"/>} onClick={reset}>Reset to template</Button>}</div>
          <div className="row gap-8">
            <Button onClick={onClose}>Cancel</Button>
            <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={save}>Save for {client.company.split(" ")[0]}</Button>
          </div>
        </div>
      </div>
    </div>
  );
}

function ClientDocs({ client }) {
  const { toast } = useToast();
  const { freelancer, template } = useApp();
  const [editDoc, setEditDoc] = React.useState(null);
  const docs = [
    { key: "service_agreement", label: "Service Agreement", status: client.docs.agreement, icon: Icon.shield },
    { key: "sow", label: "Statement of Work", status: client.docs.sow, icon: Icon.briefcase },
    { key: "nda", label: "Non-Disclosure Agreement", status: client.docs.nda, icon: Icon.shield },
    { key: "invoice", label: "Deposit invoice", status: client.docs.invoice, icon: Icon.money },
    { key: "payment_schedule", label: "Payment schedule", status: "draft", icon: Icon.calendar },
    { key: "welcome_packet", label: "Welcome packet", status: "draft", icon: Icon.doc },
  ];

  const openDoc = (key, label, doPrint) => {
    try {
      const html = window.buildDocHTML({ docKey: key, client, freelancer, template });
      const w = window.open("", "_blank");
      if (!w) { toast("Allow pop-ups to open documents", { kind: "warn" }); return; }
      w.document.open(); w.document.write(html); w.document.close();
      if (doPrint) setTimeout(() => { try { w.focus(); w.print(); } catch {} }, 500);
    } catch (e) {
      toast("Couldn't open document: " + String(e.message || e), { kind: "danger" });
    }
  };
  const editable = (window.EDITABLE_DOCS || []);
  return (
    <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12 }}>
      {editDoc && <DocEditModal client={client} docKey={editDoc.key} label={editDoc.label} onClose={() => setEditDoc(null)}/>}
      {docs.map((d, i) => {
        const Ico = d.icon;
        const isEditable = editable.includes(d.key);
        const isCustom = !!(client.docOverrides && client.docOverrides[d.key] && (client.docOverrides[d.key].body || "").trim());
        return (
          <Card key={i}>
            <div className="col gap-10">
              <div className="row" style={{ justifyContent: "space-between" }}>
                <div style={{ width: 32, height: 32, borderRadius: 8, background: "var(--bg-2)", color: "var(--ink-2)", display: "grid", placeItems: "center" }}><Ico cls="ico-sm"/></div>
                <span className="badge" style={{ background: d.status === "signed" || d.status === "paid" ? "var(--primary-soft)" : "var(--bg-2)", color: d.status === "signed" || d.status === "paid" ? "var(--primary)" : "var(--ink-3)" }}>{d.status}</span>
              </div>
              <div className="col gap-2">
                <div style={{ fontSize: 13, fontWeight: 500 }}>{d.label}</div>
                <div className="ink-3" style={{ fontSize: 12 }}>{isCustom ? <span style={{ color: "var(--primary)" }}>Customized for this client</span> : "Auto-generated · v1"}</div>
              </div>
              <div className="row gap-6" style={{ marginTop: 4, flexWrap: "wrap" }}>
                <Button size="sm" icon={<Icon.external cls="ico-sm"/>} onClick={() => openDoc(d.key, d.label, false)}>Preview</Button>
                {isEditable
                  ? <Button size="sm" variant="ghost" icon={<Icon.pen cls="ico-sm"/>} onClick={() => setEditDoc(d)}>Edit</Button>
                  : <Button size="sm" variant="ghost" icon={<Icon.download cls="ico-sm"/>} onClick={() => openDoc(d.key, d.label, true)}>PDF</Button>}
                {isEditable && <Button size="sm" variant="ghost" icon={<Icon.download cls="ico-sm"/>} onClick={() => openDoc(d.key, d.label, true)}>PDF</Button>}
              </div>
            </div>
          </Card>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Access & Credentials — your app vault per client, powered by Bitwarden.
// Stores app + login URL + status + notes. NEVER the raw password — that
// stays in Bitwarden. One click to open the app or jump to your vault.
// ─────────────────────────────────────────────────────────────────────
const ACCESS_PRESETS = [
  { name: "Notion", url: "https://www.notion.so/login" },
  { name: "Slack", url: "https://slack.com/signin" },
  { name: "Stripe", url: "https://dashboard.stripe.com/login" },
  { name: "Google Workspace", url: "https://admin.google.com" },
  { name: "QuickBooks", url: "https://qbo.intuit.com" },
  { name: "Lovable", url: "https://lovable.dev" },
  { name: "ClickUp", url: "https://app.clickup.com/login" },
  { name: "Figma", url: "https://www.figma.com/login" },
  { name: "Shopify", url: "https://accounts.shopify.com/store-login" },
  { name: "Meta Business", url: "https://business.facebook.com" },
  { name: "Canva", url: "https://www.canva.com/login" },
  { name: "Mailchimp", url: "https://login.mailchimp.com" },
];

const ACCESS_STATUS = {
  needed:    { label: "Needed",    cls: "pill-pending" },
  requested: { label: "Requested", cls: "pill-new" },
  active:    { label: "Active",    cls: "pill-active" },
  revoked:   { label: "Revoked",   cls: "pill-done" },
};

function AccessEntry({ c, last, onStatus, onDelete }) {
  const { copyToClipboard } = useToast();
  const [show, setShow] = React.useState(false);
  const st = ACCESS_STATUS[c.status] || ACCESS_STATUS.active;
  return (
    <div style={{ borderBottom: last ? "none" : "1px solid var(--line-2)" }}>
      <div className="row gap-12" style={{ padding: "14px 18px", alignItems: "center" }}>
        <div style={{ width: 34, height: 34, borderRadius: 8, background: "var(--bg-2)", color: "var(--ink-2)", display: "grid", placeItems: "center", fontWeight: 700, fontSize: 14, flexShrink: 0 }}>{(c.app || "?")[0].toUpperCase()}</div>
        <div className="col" style={{ flex: 1, lineHeight: 1.3, minWidth: 0 }}>
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <span style={{ fontSize: 13.5, fontWeight: 500 }}>{c.app}</span>
            <span className={"badge " + st.cls} style={{ fontSize: 10 }}>{st.label}</span>
          </div>
          {c.username && (
            <span className="row gap-6 ink-3" style={{ fontSize: 12, alignItems: "center" }}>
              <span className="mono">{c.username}</span>
              <button className="btn btn-ghost btn-sm" style={{ padding: 2 }} title="Copy username" onClick={() => copyToClipboard(c.username, "Username copied")}><Icon.copy cls="ico-sm" style={{ width: 12, height: 12 }}/></button>
            </span>
          )}
          {c.note && <span className="ink-3" style={{ fontSize: 12 }}>{c.note}</span>}
        </div>
        {c.password && (
          <div className="row gap-4" style={{ alignItems: "center" }}>
            <span className="mono" style={{ fontSize: 12, color: "var(--ink-2)", minWidth: 70, textAlign: "right" }}>{show ? c.password : "••••••••"}</span>
            <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} title={show ? "Hide" : "Show"} onClick={() => setShow(s => !s)}>{show ? "🙈" : "👁"}</button>
            <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} title="Copy password" onClick={() => copyToClipboard(c.password, "Password copied")}><Icon.copy cls="ico-sm"/></button>
          </div>
        )}
        <select className="input" value={c.status} onChange={e => onStatus(c.id, e.target.value)} style={{ width: 110, height: 32, fontSize: 12 }}>
          <option value="needed">Needed</option>
          <option value="requested">Requested</option>
          <option value="active">Active</option>
          <option value="revoked">Revoked</option>
        </select>
        {c.url && <Button size="sm" icon={<Icon.external cls="ico-sm"/>} onClick={() => window.open(c.url, "_blank", "noopener")}>Open</Button>}
        <Button size="sm" variant="ghost" onClick={() => window.open(c.bitwardenUrl || "https://vault.bitwarden.com", "_blank", "noopener")} style={{ color: "#175DDC" }} title="Open in Bitwarden">🔐</Button>
        <Button size="sm" variant="ghost" icon={<Icon.trash cls="ico-sm"/>} onClick={() => onDelete(c.id)}/>
      </div>
    </div>
  );
}

function ClientAccess({ client }) {
  const { updateClient } = useApp();
  const { copyToClipboard, toast } = useToast();
  const creds = client.credentials || [];
  const [form, setForm] = React.useState({ app: "", url: "", status: "active", username: "", password: "", note: "", bitwardenUrl: "" });
  const [showPw, setShowPw] = React.useState(false);

  const save = (list) => updateClient(client.id, { credentials: list });
  const add = () => {
    if (!form.app.trim()) { toast("Enter an app name", { kind: "warn" }); return; }
    let url = form.url.trim();
    if (url && !/^https?:\/\//i.test(url)) url = "https://" + url;
    save([...creds, { id: Date.now(), app: form.app.trim(), url, status: form.status, username: form.username.trim(), password: form.password, note: form.note.trim(), bitwardenUrl: form.bitwardenUrl.trim() }]);
    setForm({ app: "", url: "", status: "active", username: "", password: "", note: "", bitwardenUrl: "" });
    toast(`${form.app.trim()} added`, { kind: "success" });
  };
  const setStatus = (id, status) => save(creds.map(c => c.id === id ? { ...c, status } : c));
  const del = (id) => { if (confirm("Remove this access entry? (Your Bitwarden item is not affected.)")) save(creds.filter(c => c.id !== id)); };
  const quick = (p) => setForm(f => ({ ...f, app: p.name, url: p.url }));

  const first = (client.contact || "there").split(" ")[0];
  const requestMsg = `Hi ${first}, to share login access with me securely, please use Bitwarden Send — it's free and you don't need an account:\n\n1. Go to https://send.bitwarden.com\n2. Choose "Text", paste the username + password\n3. Set "Deletion date" to 1 day and toggle "Hide text by default"\n4. Copy the link and send it to me\n\nThat way the password is encrypted and the link expires automatically. Thank you!`;

  return (
    <div className="col gap-20">
      {/* Bitwarden explainer */}
      <Card>
        <div className="row gap-12" style={{ alignItems: "flex-start" }}>
          <div style={{ width: 38, height: 38, borderRadius: 10, background: "#175DDC", color: "#fff", display: "grid", placeItems: "center", flexShrink: 0, fontWeight: 700 }}>B</div>
          <div className="col gap-4" style={{ flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: 500 }}>App vault — powered by Bitwarden</div>
            <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.6 }}>
              Keep a tidy list of every app {client.company} shared. Each one is one click to open. The <strong>actual passwords live in your Bitwarden vault</strong> (encrypted) — this app only stores the link + status, never the raw password. To get credentials <strong>securely from the client</strong>, send them Bitwarden Send instructions below.
            </div>
            <div className="row gap-6" style={{ marginTop: 6, flexWrap: "wrap" }}>
              <Button size="sm" icon={<Icon.copy cls="ico-sm"/>} onClick={() => copyToClipboard(requestMsg, "Bitwarden request copied — paste it to your client")}>Copy "request access" message</Button>
              <a href="https://vault.bitwarden.com" target="_blank" rel="noreferrer" className="btn btn-sm" style={{ color: "#175DDC", borderColor: "#175DDC" }}><Icon.external cls="ico-sm"/> Open my Bitwarden vault</a>
              <a href="https://send.bitwarden.com" target="_blank" rel="noreferrer" className="btn btn-sm btn-ghost"><Icon.external cls="ico-sm"/> Bitwarden Send</a>
            </div>
          </div>
        </div>
      </Card>

      {/* Add access */}
      <Card>
        <div className="col gap-12">
          <div className="col gap-2">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Add an app you already have access to</div>
            <div className="ink-3" style={{ fontSize: 12 }}>Pick a preset or type any app. Add the username/password yourself if you already have it — or leave the password blank and keep it in Bitwarden.</div>
          </div>
          <div className="row gap-6" style={{ flexWrap: "wrap" }}>
            {ACCESS_PRESETS.map(p => (
              <button key={p.name} onClick={() => quick(p)} className="btn btn-sm" style={{ background: form.app === p.name ? "var(--ink)" : "var(--surface)", color: form.app === p.name ? "#fff" : "var(--ink-2)", borderColor: form.app === p.name ? "var(--ink)" : "var(--line)" }}>{p.name}</button>
            ))}
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1.4fr 110px", gap: 10 }}>
            <Field label="App name"><input className="input" value={form.app} onChange={e => setForm({ ...form, app: e.target.value })} placeholder="e.g. Notion"/></Field>
            <Field label="Login URL (opens on click)"><input className="input" value={form.url} onChange={e => setForm({ ...form, url: e.target.value })} placeholder="https://app.example.com"/></Field>
            <Field label="Status">
              <select className="input" value={form.status} onChange={e => setForm({ ...form, status: e.target.value })}>
                <option value="needed">Needed</option>
                <option value="requested">Requested</option>
                <option value="active">Active</option>
                <option value="revoked">Revoked</option>
              </select>
            </Field>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
            <Field label="Username / login email"><input className="input" value={form.username} onChange={e => setForm({ ...form, username: e.target.value })} placeholder="you@client.com" autoComplete="off"/></Field>
            <Field label="Password (optional)">
              <div style={{ position: "relative" }}>
                <input className="input" type={showPw ? "text" : "password"} value={form.password} onChange={e => setForm({ ...form, password: e.target.value })} placeholder="••••••••" autoComplete="new-password" style={{ paddingRight: 36 }}/>
                <button type="button" onClick={() => setShowPw(s => !s)} className="btn btn-ghost btn-sm" style={{ position: "absolute", right: 4, top: 4, padding: 4 }}>{showPw ? "🙈" : "👁"}</button>
              </div>
            </Field>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 10 }}>
            <Field label="Note (optional)"><input className="input" value={form.note} onChange={e => setForm({ ...form, note: e.target.value })} placeholder="e.g. guest invite, admin role"/></Field>
            <Field label="Bitwarden item link (optional)"><input className="input" value={form.bitwardenUrl} onChange={e => setForm({ ...form, bitwardenUrl: e.target.value })} placeholder="paste from Bitwarden →"/></Field>
          </div>
          {form.password && (
            <div className="row gap-8" style={{ padding: 10, background: "#FFF4E5", border: "1px solid #F4D9A8", borderRadius: 8, fontSize: 11.5, lineHeight: 1.5 }}>
              <Icon.shield cls="ico-sm" style={{ color: "#8A5E2C", flexShrink: 0 }}/>
              <span>Passwords you type here are saved <strong>only on this device</strong> (in this browser). Fine for convenience on your own computer — for top security keep the password in Bitwarden and leave this blank.</span>
            </div>
          )}
          <div className="row"><Button variant="primary" icon={<Icon.plus cls="ico-sm"/>} onClick={add}>Add to vault</Button></div>
        </div>
      </Card>

      {/* List */}
      <Card pad={false}>
        <div className="row" style={{ padding: "14px 18px", borderBottom: "1px solid var(--line)", justifyContent: "space-between" }}>
          <div style={{ fontSize: 14, fontWeight: 500 }}>Shared apps ({creds.length})</div>
          <span className="ink-3" style={{ fontSize: 11.5 }}>Passwords stay in Bitwarden — this is just your map.</span>
        </div>
        {creds.length === 0 ? (
          <div style={{ padding: 28, textAlign: "center", color: "var(--ink-3)" }}>
            <Icon.shield cls="ico-lg"/>
            <div style={{ fontSize: 13.5, marginTop: 8 }}>No apps yet. Add the ones you have access to above.</div>
          </div>
        ) : creds.map((c, i) => (
          <AccessEntry key={c.id} c={c} last={i === creds.length - 1} onStatus={setStatus} onDelete={del}/>
        ))}
      </Card>
    </div>
  );
}

const DEMO_FILE_IDS = ["veltrix", "brightline", "northwind", "hollow"];
const DEMO_FILES = [
  { name: "veltrix-brand-guidelines.pdf", size: "3.4 MB", t: "2h ago", kind: "pdf" },
  { name: "logo-primary.svg",             size: "12 KB",  t: "2h ago", kind: "svg" },
  { name: "logo-monochrome.svg",          size: "10 KB",  t: "2h ago", kind: "svg" },
  { name: "current-org-chart.png",        size: "440 KB", t: "yesterday", kind: "img" },
  { name: "tools-credentials.txt",        size: "2 KB",   t: "yesterday", kind: "txt" },
  { name: "sample-tickets.csv",           size: "88 KB",  t: "3d ago", kind: "csv" },
];

function ClientFiles({ client }) {
  const { updateClient } = useApp();
  const { toast } = useToast();
  const fileRef = React.useRef(null);
  // Seed demo files only for the original demo clients; real clients start empty.
  const files = client.files !== undefined ? client.files : (DEMO_FILE_IDS.includes(client.id) ? DEMO_FILES : []);
  const save = (list) => updateClient(client.id, { files: list });

  const del = (i) => {
    if (!confirm("Delete this file?")) return;
    save(files.filter((_, ix) => ix !== i));
    toast("File removed", { kind: "warn" });
  };
  const addFiles = (list) => {
    const arr = [...(list || [])];
    if (!arr.length) return;
    const next = arr.map(f => ({ name: f.name, size: f.size > 1024 * 1024 ? (f.size / 1024 / 1024).toFixed(1) + " MB" : Math.round(f.size / 1024) + " KB", kind: (f.name.split(".").pop() || "file").slice(0, 4), t: "just now" }));
    save([...files, ...next]);
    toast(`Added ${next.length} file${next.length === 1 ? "" : "s"}`, { kind: "success" });
  };

  return (
    <Card pad={false}>
      <input ref={fileRef} type="file" multiple style={{ display: "none" }} onChange={e => { addFiles(e.target.files); e.target.value = ""; }}/>
      <div style={{ padding: "14px 18px", borderBottom: "1px solid var(--line)", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
        <div style={{ fontSize: 13.5, fontWeight: 500 }}>{files.length} file{files.length === 1 ? "" : "s"}</div>
        <div className="row gap-6">
          <Button size="sm" icon={<Icon.plus cls="ico-sm"/>} onClick={() => fileRef.current && fileRef.current.click()}>Add files</Button>
          {files.length > 0 && <Button size="sm" variant="ghost" icon={<Icon.download cls="ico-sm"/>} onClick={() => toast(`Downloading ${files.length} files…`, { kind: "success" })}>Download all</Button>}
        </div>
      </div>
      {files.length === 0 ? (
        <div style={{ padding: 28, textAlign: "center", color: "var(--ink-3)" }}>
          <Icon.upload cls="ico-lg"/>
          <div style={{ fontSize: 13.5, marginTop: 8 }}>No files yet. Add files, or the client uploads them in their portal.</div>
        </div>
      ) : files.map((f, i) => (
        <div key={i} className="row gap-12" style={{ padding: "12px 18px", borderBottom: i < files.length - 1 ? "1px solid var(--line-2)" : "none" }}>
          <div style={{ width: 30, height: 36, borderRadius: 4, background: "var(--bg-2)", color: "var(--ink-3)", fontSize: 9, fontWeight: 600, display: "grid", placeItems: "center", textTransform: "uppercase" }}>{f.kind}</div>
          <div className="col" style={{ flex: 1, lineHeight: 1.3 }}>
            <div style={{ fontSize: 13 }}>{f.name}</div>
            <div className="ink-3" style={{ fontSize: 11.5 }}>{f.size} · {f.t}</div>
          </div>
          <Button size="sm" variant="ghost" icon={<Icon.download cls="ico-sm"/>} onClick={() => toast(`Downloading ${f.name}…`)}/>
          <Button size="sm" variant="ghost" icon={<Icon.trash cls="ico-sm"/>} onClick={() => del(i)}/>
        </div>
      ))}
    </Card>
  );
}

function ClientMessages({ client }) {
  const { toast } = useToast();
  const [msgs, setMsgs] = React.useState([
    { from: client.contact, t: "yesterday, 2:04 PM", body: "Quick question on the SOW — for the ticket system, is Linear an option or are you planning custom?", me: false },
    { from: "You", t: "yesterday, 2:31 PM", body: "Either works. I'd start by demoing both with your support team in week 2, then commit. The SOW captures that as a decision point.", me: true },
    { from: client.contact, t: "today, 9:12 AM", body: "Got it. Signing the agreement now. Will route the deposit invoice to finance today.", me: false },
  ]);
  const [reply, setReply] = React.useState("");
  const send = () => {
    if (!reply.trim()) return;
    setMsgs(m => [...m, { from: "You", t: "just now", body: reply.trim(), me: true }]);
    setReply("");
    toast("Message sent", { kind: "success" });
  };
  return (
    <Card>
      <div className="col gap-16">
        {msgs.map((m, i) => (
          <div key={i} className="row gap-12" style={{ alignItems: "flex-start", flexDirection: m.me ? "row-reverse" : "row" }}>
            <Avatar name={m.from} size={32}/>
            <div className="col gap-4" style={{ maxWidth: "70%" }}>
              <div className="row gap-8" style={{ flexDirection: m.me ? "row-reverse" : "row" }}>
                <span style={{ fontSize: 12.5, fontWeight: 500 }}>{m.from}</span>
                <span className="ink-3" style={{ fontSize: 11.5 }}>{m.t}</span>
              </div>
              <div style={{ padding: "10px 14px", background: m.me ? "var(--primary)" : "var(--bg-2)", color: m.me ? "#fff" : "var(--ink)", borderRadius: 10, fontSize: 13, lineHeight: 1.55 }}>{m.body}</div>
            </div>
          </div>
        ))}
        <div className="hr"/>
        <div className="row gap-8">
          <input className="input" placeholder={`Reply to ${client.contact}…`} value={reply} onChange={e => setReply(e.target.value)} onKeyDown={e => e.key === "Enter" && send()}/>
          <Button variant="primary" icon={<Icon.send cls="ico-sm"/>} onClick={send}>Send</Button>
        </div>
      </div>
    </Card>
  );
}

// Sensible default plan, derived from the client's rate + unit
function defaultBilling(client) {
  const label = client.rateLabel || "";
  const freq = /\/\s*week/i.test(label) ? "weekly"
    : /\/\s*hour/i.test(label) ? "weekly"
    : /\/\s*project/i.test(label) ? "onetime"
    : "monthly";
  return {
    frequency: freq,
    amount: client.rate || 0,
    count: freq === "onetime" ? 1 : 4,
    netDays: 7,
    lateFee: 1.5,
    depositPct: 50,
    payLink: "",
    skipWeekends: false,  // show invoice date ranges on weekdays only
    paid: {},        // { rowIndex: true }
  };
}

const FREQ_META = {
  onetime:  { unit: "Payment", step: 0 },
  weekly:   { unit: "Week",    step: 7 },
  biweekly: { unit: "Period",  step: 14 },
  monthly:  { unit: "Month",   step: 30 },
};

// Compact, human date range, e.g. "May 19 – Jun 1, 2026"
function fmtDateRange(a, b) {
  const A = new Date(a), B = new Date(b);
  const aStr = A.toLocaleDateString("en-US", { month: "short", day: "numeric" });
  const bStr = B.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
  return `${aStr} – ${bStr}`;
}
function addDays(d, n) { const x = new Date(d); x.setDate(x.getDate() + n); return x; }
// Snap a date off the weekend: back to Friday (for a period END) or forward to
// Monday (for a period START), so invoice ranges never appear to include weekends.
function prevWeekday(d) { const x = new Date(d); const g = x.getDay(); if (g === 0) x.setDate(x.getDate() - 2); else if (g === 6) x.setDate(x.getDate() - 1); return x; }
function nextWeekday(d) { const x = new Date(d); const g = x.getDay(); if (g === 6) x.setDate(x.getDate() + 2); else if (g === 0) x.setDate(x.getDate() + 1); return x; }

// Builds the invoice schedule. Each row carries:
//  - date:    when the invoice covers FROM (period start / issue anchor)
//  - dueDate: when payment is due = issue date + net-day terms (lets you bill
//             in advance — e.g. issue Jul 1, due Jul 31 on net-30)
//  - range:   the work period the invoice covers, e.g. "Jul 1 – Jul 31, 2026"
function buildBillingRows(client, b) {
  const start = new Date(client.startDate);
  const net = Number(b.netDays) || 0;
  const rows = [];
  if (b.frequency === "onetime") {
    const dep = Math.round((b.amount || 0) * ((b.depositPct || 50) / 100));
    rows.push({ label: `Deposit (${b.depositPct || 50}%)`, range: fmtDate(client.startDate), date: client.startDate, dueDate: addDays(start, net).toISOString(), amount: dep });
    const last = (client.milestones && client.milestones.length) ? client.milestones[client.milestones.length - 1].date : daysAhead(30);
    rows.push({ label: "Final on delivery", range: fmtDate(last), date: last, dueDate: addDays(new Date(last), net).toISOString(), amount: (b.amount || 0) - dep });
  } else {
    const meta = FREQ_META[b.frequency] || FREQ_META.monthly;
    for (let i = 0; i < (b.count || 1); i++) {
      let d, end;
      if (b.frequency === "monthly") {
        // Anchor each invoice to a whole calendar month (beginning-of-month billing).
        d = new Date(start.getFullYear(), start.getMonth() + i, 1);
        end = new Date(d.getFullYear(), d.getMonth() + 1, 0); // last day of that month
      } else {
        d = addDays(start, i * meta.step);
        end = addDays(d, meta.step - 1);
      }
      // If weekends are excluded, show the range on weekdays only (start→Mon, end→Fri)
      // so the client never sees a Sat/Sun and assumes weekend work. Amount unchanged.
      const rStart = b.skipWeekends ? nextWeekday(d) : d;
      const rEnd = b.skipWeekends ? prevWeekday(end) : end;
      rows.push({ label: `${meta.unit} ${i + 1}`, range: fmtDateRange(rStart, rEnd), date: d.toISOString(), dueDate: addDays(d, net).toISOString(), amount: b.amount || 0 });
    }
  }
  return rows;
}

function BillingEditor({ client, billing, onClose }) {
  const { updateClient } = useApp();
  const { toast } = useToast();
  const [b, setB] = React.useState(billing);
  const set = (k, v) => setB(s => ({ ...s, [k]: v }));
  const save = () => {
    updateClient(client.id, { billing: { ...b, amount: Number(b.amount) || 0, count: Number(b.count) || 1, netDays: Number(b.netDays) || 0, lateFee: Number(b.lateFee) || 0, depositPct: Number(b.depositPct) || 50 } });
    toast("Payment plan saved", { kind: "success" });
    onClose();
  };
  const isRecurring = b.frequency !== "onetime";
  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(15,26,20,0.45)", backdropFilter: "blur(3px)", zIndex: 3000, display: "grid", placeItems: "center", padding: 24 }}>
      <div onClick={e => e.stopPropagation()} className="card fade-up" style={{ maxWidth: 520, width: "100%" }}>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "center", padding: "16px 20px", borderBottom: "1px solid var(--line)" }}>
          <div style={{ fontSize: 15, fontWeight: 600 }}>Payment plan — {client.company}</div>
          <button onClick={onClose} className="btn btn-ghost btn-sm" style={{ padding: 6 }}><Icon.x cls="ico-sm"/></button>
        </div>
        <div className="card-pad col gap-14">
          <Field label="How does the client pay?">
            <select className="input" value={b.frequency} onChange={e => set("frequency", e.target.value)}>
              <option value="weekly">Weekly</option>
              <option value="biweekly">Every 2 weeks</option>
              <option value="monthly">Monthly</option>
              <option value="onetime">One-time / project (deposit + final)</option>
            </select>
          </Field>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <Field label={b.frequency === "onetime" ? "Total project amount" : "Amount each payment"}>
              <div style={{ position: "relative" }}>
                <span style={{ position: "absolute", left: 12, top: 9, color: "var(--muted)", fontSize: 13 }}>$</span>
                <input className="input" type="number" value={b.amount} onChange={e => set("amount", e.target.value)} style={{ paddingLeft: 22 }}/>
              </div>
            </Field>
            {isRecurring
              ? <Field label="Number of payments"><input className="input" type="number" value={b.count} onChange={e => set("count", e.target.value)}/></Field>
              : <Field label="Deposit %"><input className="input" type="number" value={b.depositPct} onChange={e => set("depositPct", e.target.value)}/></Field>}
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <Field label="Payment terms — net days"><input className="input" type="number" value={b.netDays} onChange={e => set("netDays", e.target.value)}/></Field>
            <Field label="Late fee (% / month)"><input className="input" type="number" value={b.lateFee} onChange={e => set("lateFee", e.target.value)}/></Field>
          </div>
          <Field label="Default payment link (optional)">
            <input className="input" value={b.payLink} onChange={e => set("payLink", e.target.value)} placeholder="paypal.me/yourname or a reusable invoice link" style={{ fontFamily: "Geist Mono, monospace", fontSize: 12.5 }}/>
            <div className="ink-3" style={{ fontSize: 11, marginTop: 4 }}>Only used as a fallback. Each invoice on the schedule can have its own link (recommended for per-period PayPal invoices).</div>
          </Field>
          <label className="row gap-10" style={{ padding: "10px 12px", border: "1px solid var(--line)", borderRadius: 8, cursor: "pointer", alignItems: "center" }}>
            <Toggle on={!!b.skipWeekends} onClick={() => set("skipWeekends", !b.skipWeekends)}/>
            <div className="col" style={{ lineHeight: 1.35 }}>
              <span style={{ fontSize: 13, fontWeight: 500 }}>Show weekdays only on invoice dates</span>
              <span className="ink-3" style={{ fontSize: 11.5 }}>Period ranges end on Friday / start on Monday, so the client never sees a weekend date. Doesn't change the amount.</span>
            </div>
          </label>
        </div>
        <div className="row gap-8" style={{ padding: "14px 20px", borderTop: "1px solid var(--line)", justifyContent: "flex-end" }}>
          <Button onClick={onClose}>Cancel</Button>
          <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={save}>Save plan</Button>
        </div>
      </div>
    </div>
  );
}

function InvoiceEmailEditor({ client, billing, onClose }) {
  const { updateClient, freelancer } = useApp();
  const { toast } = useToast();
  const d = window.INVOICE_EMAIL_DEFAULTS || { subject: "", intro: "", closing: "" };
  const cur = billing.emailCustom || {};
  const [subject, setSubject] = React.useState(cur.subject || d.subject);
  const [intro, setIntro] = React.useState(cur.intro || d.intro);
  const [closing, setClosing] = React.useState(cur.closing || d.closing);

  // Live preview with a representative invoice row.
  const rows = buildBillingRows(client, billing);
  const sample = rows[0] || { label: "Period 1", amount: billing.amount || 0, date: client.startDate };
  const invoiceNo = "INV-" + (clientSlug(client.company) || "").replace(/-/g, "").toUpperCase().slice(0, 6) + "-001";
  const preview = window.buildInvoiceEmail({
    client, freelancer, rowLabel: sample.label, amount: sample.amount,
    currencyCode: freelancer.currency, dueDate: sample.dueDate || sample.date, invoiceNo,
    payLink: (billing.payLinks && billing.payLinks[0]) || billing.payLink || "",
    custom: { subject, intro, closing }, periodRange: sample.range,
  });

  const save = () => {
    updateClient(client.id, { billing: { ...billing, emailCustom: { subject: subject.trim(), intro: intro.trim(), closing: closing.trim() } } });
    toast("Invoice email saved", { kind: "success" });
    onClose();
  };
  const reset = () => {
    setSubject(d.subject); setIntro(d.intro); setClosing(d.closing);
    const next = { ...billing }; delete next.emailCustom;
    updateClient(client.id, { billing: next });
    toast("Reset to default wording", { kind: "warn" });
  };

  return (
    <div onClick={onClose} style={{ position: "fixed", inset: 0, background: "rgba(15,26,20,0.45)", backdropFilter: "blur(3px)", zIndex: 3000, display: "grid", placeItems: "center", padding: 24 }}>
      <div onClick={e => e.stopPropagation()} className="card fade-up" style={{ maxWidth: 860, width: "100%", maxHeight: "90vh", display: "flex", flexDirection: "column" }}>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "center", padding: "16px 20px", borderBottom: "1px solid var(--line)" }}>
          <div className="col gap-2">
            <div style={{ fontSize: 15, fontWeight: 600 }}>Edit invoice email — {client.company}</div>
            <div className="ink-3" style={{ fontSize: 11.5 }}>The invoice number, amount, due date and Pay button stay auto-filled. You're editing the wording.</div>
          </div>
          <button onClick={onClose} className="btn btn-ghost btn-sm" style={{ padding: 6 }}><Icon.x cls="ico-sm"/></button>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 0, overflow: "hidden", flex: 1, minHeight: 0 }}>
          {/* Editor */}
          <div className="card-pad col gap-12" style={{ overflowY: "auto", borderRight: "1px solid var(--line)" }}>
            <div className="row gap-6" style={{ padding: 10, background: "var(--surface-2)", border: "1px solid var(--line-2)", borderRadius: 8, fontSize: 11, lineHeight: 1.5 }}>
              <Icon.sparkle cls="ico-sm" style={{ flexShrink: 0 }}/>
              <span>Tokens auto-fill per invoice: <span className="mono">{"{first}"}</span> <span className="mono">{"{dates}"}</span> (e.g. May 19 – Jun 1) <span className="mono">{"{amount}"}</span> <span className="mono">{"{due}"}</span> <span className="mono">{"{invoice}"}</span> <span className="mono">{"{brand}"}</span> <span className="mono">{"{period}"}</span></span>
            </div>
            <Field label="Subject line">
              <input className="input" value={subject} onChange={e => setSubject(e.target.value)} style={{ fontSize: 13 }}/>
            </Field>
            <Field label="Greeting / intro line">
              <textarea className="input" rows={3} value={intro} onChange={e => setIntro(e.target.value)} style={{ fontSize: 13, lineHeight: 1.55 }}/>
            </Field>
            <Field label="Closing line (above your signature)">
              <textarea className="input" rows={3} value={closing} onChange={e => setClosing(e.target.value)} style={{ fontSize: 13, lineHeight: 1.55 }}/>
            </Field>
          </div>
          {/* Live preview */}
          <div className="col" style={{ overflowY: "auto", background: "var(--bg)" }}>
            <div style={{ padding: "10px 16px", borderBottom: "1px solid var(--line)", fontSize: 11, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: 0.05, fontWeight: 600 }}>Live preview</div>
            <div style={{ padding: "8px 14px", fontSize: 12, color: "var(--ink-3)", borderBottom: "1px solid var(--line-2)" }}>Subject: <b style={{ color: "var(--ink)" }}>{preview.subject}</b></div>
            <div style={{ padding: 12 }} dangerouslySetInnerHTML={{ __html: preview.htmlContent }}/>
          </div>
        </div>
        <div className="row" style={{ padding: "14px 20px", borderTop: "1px solid var(--line)", justifyContent: "space-between" }}>
          <Button variant="ghost" icon={<Icon.refresh cls="ico-sm"/>} onClick={reset}>Reset to default</Button>
          <div className="row gap-8">
            <Button onClick={onClose}>Cancel</Button>
            <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={save}>Save email</Button>
          </div>
        </div>
      </div>
    </div>
  );
}

function ClientBilling({ client, cur }) {
  const { updateClient, paymentProviders, freelancer } = useApp();
  const { toast, copyToClipboard } = useToast();
  const [editing, setEditing] = React.useState(false);
  const [editingEmail, setEditingEmail] = React.useState(false);
  const [sending, setSending] = React.useState(null);
  const billing = client.billing || defaultBilling(client);
  const rows = buildBillingRows(client, billing);
  const paid = billing.paid || {};
  const sent = billing.sent || {};
  const togglePaid = (i) => updateClient(client.id, { billing: { ...billing, paid: { ...paid, [i]: !paid[i] } } });
  const addPeriod = () => updateClient(client.id, { billing: { ...billing, count: (billing.count || rows.length) + 1 } });
  const payLinks = billing.payLinks || {};
  const linkFor = (i) => payLinks[i] || billing.payLink || "";  // per-invoice link, falling back to the plan default
  const setRowLink = (i) => {
    const v = prompt(`Paste the pay link for "${rows[i].label}" (your PayPal / Stripe / Wise invoice link). Leave blank to clear.`, payLinks[i] || "");
    if (v == null) return;
    const next = { ...payLinks };
    if (v.trim()) next[i] = v.trim(); else delete next[i];
    updateClient(client.id, { billing: { ...billing, payLinks: next } });
    toast(v.trim() ? "Pay link saved for this invoice" : "Pay link cleared", { kind: "success" });
  };
  // Open the exact email the client would receive — with this invoice's pay
  // button — so Donna can eyeball it before sending. Always available (no Brevo key needed).
  const previewInvoice = (row, i) => {
    const link = linkFor(i);
    const email = buildInvoiceEmail({
      client, freelancer, rowLabel: row.label, amount: row.amount,
      currencyCode: freelancer.currency, dueDate: row.dueDate || row.date, invoiceNo: invNum(i), payLink: link, custom: billing.emailCustom, periodRange: row.range,
    });
    const w = window.open("", "_blank", "width=640,height=820,scrollbars=yes");
    if (!w) { toast("Allow pop-ups to preview the invoice", { kind: "warn" }); return; }
    const warn = link ? "" : '<br><b style="color:#B23A2E;">⚠ No pay link set for this invoice — the email will have no Pay button. Click "+ Add pay link" first.</b>';
    w.document.write(`<title>Invoice preview — ${email.subject}</title><div style="padding:18px 20px;background:#f4f4f0;font:13px/1.5 system-ui,sans-serif;color:#5B635E;border-bottom:1px solid #e5e5df;">Subject: <b style="color:#0F1A14;">${email.subject}</b><br>To: ${client.contact} &lt;${client.email}&gt;${warn}</div><div style="padding:8px;">${email.htmlContent}</div>`);
  };
  const total = rows.reduce((s, r) => s + r.amount, 0);
  const connected = (paymentProviders || []).filter(p => p.status === "connected");
  const freqLabel = { weekly: "Weekly", biweekly: "Every 2 weeks", monthly: "Monthly", onetime: "One-time" }[billing.frequency] || "Monthly";
  const periodLabel = { weekly: "Week", biweekly: "Period", monthly: "Month", onetime: "Payment" }[billing.frequency] || "Period";
  const invNum = (i) => "INV-" + (clientSlug(client.company) || "").replace(/-/g,"").toUpperCase().slice(0,6) + "-" + String(i + 1).padStart(3, "0");

  const sendInvoice = async (row, i) => {
    const cfg = loadBrevoConfig ? loadBrevoConfig() : {};
    const invoiceNo = invNum(i);
    const email = buildInvoiceEmail({
      client, freelancer, rowLabel: row.label, amount: row.amount,
      currencyCode: freelancer.currency, dueDate: row.dueDate || row.date,
      invoiceNo, payLink: linkFor(i), custom: billing.emailCustom, periodRange: row.range,
    });
    if ((!cfg.apiKey && !cfg.proxyUrl) || !cfg.senderEmail) {
      const w = window.open("", "_blank", "width=620,height=760,scrollbars=yes");
      if (w) w.document.write(`<title>Invoice preview — ${email.subject}</title><div style="padding:20px;background:#f4f4f0;font:13px sans-serif;color:#5B635E;margin-bottom:12px;">Subject: <b style="color:#0F1A14;">${email.subject}</b><br>To: ${client.email}</div>${email.htmlContent}`);
      toast("No Brevo key — showing preview. Add key in Settings → Notifications to send for real.", { kind: "warn", duration: 4500 });
      return;
    }
    setSending(i);
    try {
      await sendBrevoEmail({ apiKey: cfg.apiKey, senderName: cfg.senderName || freelancer.brand, senderEmail: cfg.senderEmail, toEmail: client.email, toName: client.contact, subject: email.subject, htmlContent: email.htmlContent });
      updateClient(client.id, { billing: { ...billing, sent: { ...sent, [i]: new Date().toISOString() } } });
      toast(`Invoice ${invoiceNo} sent to ${client.email}`, { kind: "success" });
    } catch (e) {
      toast(String(e.message || e), { kind: "danger", duration: 5000 });
    } finally { setSending(null); }
  };

  return (
    <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 20 }}>
      {editing && <BillingEditor client={client} billing={billing} onClose={() => setEditing(false)}/>}
      {editingEmail && <InvoiceEmailEditor client={client} billing={billing} onClose={() => setEditingEmail(false)}/>}
      <Card>
        <div className="col gap-12">
          <div className="row" style={{ justifyContent: "space-between" }}>
            <div className="col gap-2">
              <div style={{ fontSize: 14, fontWeight: 500 }}>Payment schedule</div>
              <div className="ink-3" style={{ fontSize: 12 }}>{freqLabel} · {fmtMoney(billing.amount, cur)}{billing.frequency !== "onetime" ? " each" : ""}</div>
            </div>
            <div className="row gap-6">
              <Button size="sm" icon={<Icon.mail cls="ico-sm"/>} onClick={() => setEditingEmail(true)}>Edit email</Button>
              <Button size="sm" icon={<Icon.pen cls="ico-sm"/>} onClick={() => setEditing(true)}>Edit plan</Button>
            </div>
          </div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 100px 86px 72px 88px", padding: "8px 0", borderBottom: "1px solid var(--line-2)", fontSize: 11, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: 0.04, fontWeight: 500 }}>
            <span>Invoice</span><span>Due</span><span style={{ textAlign: "right" }}>Amount</span><span style={{ textAlign: "right" }}>Paid</span><span style={{ textAlign: "right" }}>Send</span>
          </div>
          {rows.map((r, i) => (
            <div key={i} style={{ display: "grid", gridTemplateColumns: "1fr 100px 86px 72px 88px", padding: "10px 0", borderBottom: i < rows.length - 1 ? "1px solid var(--line-2)" : "none", fontSize: 13, alignItems: "center" }}>
              <div className="col gap-1">
                <span>{r.label}{r.range ? <span className="ink-3" style={{ fontSize: 11.5 }}> · {r.range}</span> : null}</span>
                {sent[i] && <span className="ink-3" style={{ fontSize: 11 }}>Sent {fmtDate(sent[i])}</span>}
                <div className="row gap-12" style={{ marginTop: 1 }}>
                  <button onClick={() => setRowLink(i)} className="row gap-4" style={{ background: "none", border: 0, padding: 0, cursor: "pointer", fontSize: 11, color: payLinks[i] ? "var(--primary)" : "var(--ink-3)" }} title={payLinks[i] || "Add a pay link for this specific invoice"}>
                    <Icon.link cls="ico-sm"/>
                    {payLinks[i] ? "Pay link set · edit" : "+ Add pay link"}
                  </button>
                  <button onClick={() => previewInvoice(r, i)} className="row gap-4" style={{ background: "none", border: 0, padding: 0, cursor: "pointer", fontSize: 11, color: "var(--ink-3)" }} title="Preview the exact email the client receives">
                    <Icon.external cls="ico-sm"/>
                    Preview
                  </button>
                </div>
              </div>
              <span className="ink-3 mono" style={{ fontSize: 12 }}>{fmtDate(r.dueDate || r.date)}</span>
              <span className="mono" style={{ textAlign: "right" }}>{fmtMoney(r.amount, cur)}</span>
              <span style={{ textAlign: "right" }}>
                <button onClick={() => togglePaid(i)} className="badge" style={{ cursor: "pointer", border: 0, background: paid[i] ? "var(--primary-soft)" : "var(--bg-2)", color: paid[i] ? "var(--primary)" : "var(--ink-3)" }} title="Toggle paid">{paid[i] ? "paid ✓" : "unpaid"}</button>
              </span>
              <span style={{ textAlign: "right" }}>
                <Button size="sm" variant={sent[i] ? "ghost" : "primary"} onClick={() => sendInvoice(r, i)} disabled={sending === i}>
                  {sending === i ? "…" : sent[i] ? "Resend" : "Send"}
                </Button>
              </span>
            </div>
          ))}
          <div className="row" style={{ justifyContent: "space-between", paddingTop: 12, fontSize: 13, alignItems: "center" }}>
            <span className="ink-3">Total contract value</span>
            <span className="mono" style={{ fontWeight: 600, fontSize: 15 }}>{fmtMoney(total, cur)}</span>
          </div>
          {billing.frequency !== "onetime" && (
            <button onClick={addPeriod} style={{ alignSelf: "flex-start", fontSize: 13, color: "var(--primary)", background: "none", border: "1px dashed var(--primary)", borderRadius: 6, padding: "6px 12px", cursor: "pointer" }}>
              + Add {periodLabel}
            </button>
          )}
        </div>
      </Card>

      <Card>
        <div className="col gap-12">
          <div style={{ fontSize: 14, fontWeight: 500 }}>Payment methods accepted</div>
          {connected.length === 0
            ? <div className="ink-3" style={{ fontSize: 12.5 }}>None connected yet — set up Stripe/PayPal in Settings → Payments.</div>
            : connected.map((p, i) => (
              <div key={p.id} className="row gap-10" style={{ padding: "10px 0", borderBottom: i < connected.length - 1 ? "1px solid var(--line-2)" : "none" }}>
                <span style={{ width: 30, height: 22, borderRadius: 4, background: p.color, display: "grid", placeItems: "center", color: "#fff", fontSize: 9, fontWeight: 700 }}>{p.name.slice(0,3).toUpperCase()}</span>
                <span style={{ fontSize: 13, flex: 1 }}>{p.name}</span>
                <Icon.check cls="ico-sm" />
              </div>
            ))}
          <div className="hr"/>
          {billing.payLink ? (
            <div className="col gap-6">
              <div className="label">Default pay link</div>
              <div className="ink-3" style={{ fontSize: 11.5, marginTop: -2 }}>Used only when an invoice has no link of its own. Per-invoice links are set on each row of the schedule.</div>
              <div className="row gap-6">
                <a href={billing.payLink} target="_blank" rel="noreferrer" className="btn btn-sm btn-primary" style={{ flex: 1, justifyContent: "center" }}><Icon.external cls="ico-sm"/> Open default link</a>
                <Button size="sm" icon={<Icon.copy cls="ico-sm"/>} onClick={() => copyToClipboard(billing.payLink, "Pay link copied")}/>
              </div>
            </div>
          ) : (
            <div className="col gap-4">
              <div className="label">Pay links</div>
              <div className="ink-3" style={{ fontSize: 12 }}>Each invoice gets its own pay link — click "+ Add pay link" under any invoice on the schedule. (Or set a default in "Edit plan" if you reuse one link.)</div>
            </div>
          )}
          <div className="hr"/>
          <div className="col gap-4">
            <div className="label">Payment terms</div>
            <div style={{ fontSize: 13 }}>Net {billing.netDays} · {billing.lateFee}% late fee / month</div>
          </div>
        </div>
      </Card>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// New client wizard
// ─────────────────────────────────────────────────────────────────────
function AdminNewClient({ goTo }) {
  const { setClients, setActiveClientId, freelancer } = useApp();
  const { toast } = useToast();
  const [step, setStep] = React.useState(0); // 0 input, 1 analyzing, 2 review, 3 sent
  const [sending, setSending] = React.useState(false);
  const [mode, setMode] = React.useState("jd");
  const [jd, setJD] = React.useState("");
  const [rate, setRate] = React.useState("");
  const [rateType, setRateType] = React.useState("month");
  const [extracted, setExtracted] = React.useState(null);
  const [contact, setContact] = React.useState("");
  const [email, setEmail] = React.useState("");
  const [company, setCompany] = React.useState("");
  const [siteUrl, setSiteUrl] = React.useState("");

  // Switch input mode (JD / scope brief / transcript / email). Starts blank —
  // no demo content pre-filled.
  const changeMode = (m) => {
    setMode(m);
  };

  const analyze = async () => {
    setStep(1);
    const ac = (window.RELAY_CONFIG && window.RELAY_CONFIG.anthropic) || {};
    const hasAI = !!(ac.apiKey || ac.proxyUrl);
    let e;
    try {
      if (hasAI) {
        e = await extractFromJD_AI({ text: jd, rate, rateType });
      } else {
        await new Promise(r => setTimeout(r, 1800));
        e = extractFromJD(jd, rate);
      }
    } catch (err) {
      toast("AI extraction unavailable — used the template instead. " + String(err.message || ""), { kind: "warn", duration: 4500 });
      e = extractFromJD(jd, rate);
    }
    const b = extractBrand(siteUrl, company);
    // Form-entered company/contact/email win when filled; otherwise use AI's.
    setExtracted({
      ...e, ...b,
      company: company || e.company,
      contact: contact || e.contact,
      email: email || e.email,
      website: siteUrl,
    });
    setStep(2);
  };

  const _buildClient = () => ({
    id: "new-" + Date.now(),
    ...extracted,
    company: company || extracted.company,
    contact: contact || extracted.contact,
    email: email || extracted.email,
    status: "new", progress: 0,
    color: extracted.brand ? [extracted.brand.surface || "#DDE6F4", extracted.brand.primary] : ["#DDE6F4","#2C4D8A"],
    invitedAt: new Date().toISOString(),
    industry: "—", size: "—", website: extracted.website || siteUrl || "—",
    role: "Primary contact",
    startDate: daysAhead(7),
    timezone: "PT",
    docs: { agreement: "draft", sow: "draft", nda: "draft", invoice: "draft" },
  });

  const saveDraft = () => {
    const nc = _buildClient();
    setClients(cs => [nc, ...cs]);
    setActiveClientId(nc.id);
    setTimeout(() => window.flushAllWorkspaceWrites && window.flushAllWorkspaceWrites(), 100);
    toast(`${nc.company} saved as draft — review their docs, then send the portal link from the Overview tab.`, { kind: "success", duration: 5000 });
    goTo("client-detail");
  };

  const send = async () => {
    const nc = _buildClient();
    setClients(cs => [nc, ...cs]);
    setActiveClientId(nc.id);
    setTimeout(() => window.flushAllWorkspaceWrites && window.flushAllWorkspaceWrites(), 100);

    if (!nc.email) {
      toast("Client saved — no email address on file. Add it in their profile to send the portal link.", { kind: "warn", duration: 5000 });
      setStep(3);
      return;
    }
    const cfg = window.loadBrevoConfig();
    const brevoConnected = !!(cfg.proxyUrl || cfg.apiKey) && cfg.senderEmail;
    if (!brevoConnected) {
      toast("Client saved — Brevo not connected. Send the portal link manually from their Overview tab.", { kind: "warn", duration: 5000 });
      setStep(3);
      return;
    }
    setSending(true);
    try {
      const { subject, html } = window.buildPortalNudgeEmail({ client: nc, freelancer });
      await window.sendBrevoEmail({
        apiKey: cfg.apiKey,
        senderName: cfg.senderName || freelancer.brand,
        senderEmail: cfg.senderEmail,
        toEmail: nc.email,
        toName: nc.contact,
        subject,
        htmlContent: html,
      });
    } catch (e) {
      toast("Client saved — but email failed: " + String(e.message || e), { kind: "warn", duration: 5000 });
    } finally {
      setSending(false);
    }
    setStep(3);
  };

  return (
    <div className="col" style={{ minHeight: "100vh" }}>
      <PageHeader eyebrow="Onboard a client" title="Start with the JD and their site"
        sub="Drop the job description and their website. We extract the role from one and the brand kit (logo, palette, voice) from the other — the portal you send is already in their colors."/>

      <div style={{ padding: "24px 36px 48px", maxWidth: 1100, margin: "0 auto", width: "100%" }}>
        {/* Stepper */}
        <div className="row gap-12" style={{ marginBottom: 24 }}>
          {["Paste JD + site", "AI extracts", "Review & send", "Sent"].map((label, i) => (
            <div key={i} className="row gap-8" style={{ opacity: i <= step ? 1 : 0.45 }}>
              <span style={{ width: 22, height: 22, borderRadius: "50%", background: i < step ? "var(--primary)" : i === step ? "var(--ink)" : "var(--bg-2)", color: i <= step ? "#fff" : "var(--ink-3)", display: "grid", placeItems: "center", fontSize: 11, fontWeight: 600 }}>{i < step ? <Icon.check cls="ico-sm"/> : i+1}</span>
              <span style={{ fontSize: 12.5, fontWeight: i === step ? 500 : 400, color: i <= step ? "var(--ink)" : "var(--ink-3)" }}>{label}</span>
              {i < 3 && <span style={{ width: 32, height: 1, background: "var(--line)" }}/>}
            </div>
          ))}
        </div>

        {step === 0 && <NewClientInput {...{ mode, changeMode, jd, setJD, rate, setRate, rateType, setRateType, contact, setContact, email, setEmail, company, setCompany, siteUrl, setSiteUrl, analyze }}/>}
        {step === 1 && <NewClientAnalyzing siteUrl={siteUrl} company={company}/>}
        {step === 2 && <NewClientReview extracted={extracted} setExtracted={setExtracted} send={send} saveDraft={saveDraft} sending={sending} freelancer={freelancer}/>}
        {step === 3 && <NewClientSent extracted={extracted} goTo={goTo}/>}
      </div>
    </div>
  );
}

function NewClientInput({ mode, changeMode, jd, setJD, rate, setRate, rateType, setRateType, contact, setContact, email, setEmail, company, setCompany, siteUrl, setSiteUrl, analyze }) {
  const { toast } = useToast();
  const jdFileRef = React.useRef(null);
  const brand = React.useMemo(() => extractBrand(siteUrl, company).brand, [siteUrl, company]);
  const modes = [
    { id: "jd",    label: "Job description",     icon: Icon.briefcase, hint: "Paste a JD from OnlineJobs.ph, Upwork, LinkedIn, etc.", placeholder: "Paste the full JD here…" },
    { id: "scope", label: "Scope brief",          icon: Icon.layers,    hint: "Bullets, deliverables, timeline — however you wrote it down.", placeholder: "What needs to get done, by when, for how much…" },
    { id: "voice", label: "Voice / transcript",   icon: Icon.bell,      hint: "Drop a Loom transcript or a voice memo. Conversational input works fine.", placeholder: "Paste the transcript here…" },
    { id: "convo", label: "Email thread",         icon: Icon.mail,      hint: "Forward the back-and-forth. We'll extract scope, rate, and contact.", placeholder: "Paste the email thread…" },
    { id: "blank", label: "Start blank",          icon: Icon.pen,       hint: "Just rate + client info. We'll suggest a scope you can edit.", placeholder: "Leave empty — fill in client + rate on the right →" },
  ];
  const m = modes.find(x => x.id === mode) || modes[0];

  return (
    <div className="col gap-16">
      {/* Mode tabs */}
      <div className="row gap-6" style={{ flexWrap: "wrap" }}>
        {modes.map(mm => {
          const Ico = mm.icon;
          const active = mode === mm.id;
          return (
            <button key={mm.id} onClick={() => changeMode(mm.id)}
              className="row gap-6"
              style={{
                padding: "8px 14px", borderRadius: 999, fontSize: 12.5, fontWeight: 500,
                background: active ? "var(--ink)" : "var(--surface)",
                color: active ? "#fff" : "var(--ink-2)",
                border: "1px solid " + (active ? "var(--ink)" : "var(--line)"),
                cursor: "pointer",
              }}>
              <Ico cls="ico-sm"/> {mm.label}
            </button>
          );
        })}
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 20 }}>
        <Card>
          <div className="col gap-14">
            <div className="col gap-4">
              <span className="label-lc">{m.label}</span>
              <span className="ink-3" style={{ fontSize: 12 }}>{m.hint}</span>
            </div>
            {mode === "blank" ? (
              <div className="col gap-10" style={{ padding: 28, background: "var(--surface-2)", borderRadius: 10, border: "1px dashed var(--line)", textAlign: "center", alignItems: "center" }}>
                <Icon.sparkle cls="ico-lg" style={{ color: "var(--primary)" }}/>
                <div className="h-display" style={{ fontSize: 22 }}>No JD? No problem.</div>
                <div className="ink-3" style={{ fontSize: 13, maxWidth: 380, lineHeight: 1.55 }}>
                  Fill in the client details and rate on the right. We'll draft a generic SOW you can edit clause-by-clause, and pull the rest from your default template.
                </div>
              </div>
            ) : (
              <textarea className="input" value={jd} onChange={e => setJD(e.target.value)} rows={18}
                placeholder={m.placeholder}
                style={{ fontSize: 12.5, lineHeight: 1.55, fontFamily: mode === "voice" || mode === "convo" ? "Geist Mono, monospace" : "inherit" }}/>
            )}
            <div className="row gap-8">
              <input ref={jdFileRef} type="file" accept=".txt,.md,.text,.rtf" style={{ display: "none" }}
                onChange={e => {
                  const f = e.target.files && e.target.files[0];
                  if (!f) return;
                  const reader = new FileReader();
                  reader.onload = () => { setJD(String(reader.result || "")); toast(`Loaded ${f.name}`, { kind: "success" }); };
                  reader.onerror = () => toast("Couldn't read that file", { kind: "warn" });
                  reader.readAsText(f);
                  e.target.value = "";
                }}/>
              <Button size="sm" icon={<Icon.paperclip cls="ico-sm"/>} onClick={() => jdFileRef.current && jdFileRef.current.click()}>Attach text file</Button>
              <Button size="sm" icon={<Icon.link cls="ico-sm"/>} onClick={() => { const u = prompt("Paste the text here (URL fetching needs a backend):"); if (u) setJD(u); }}>Paste text</Button>
            </div>
          </div>
        </Card>
        <Card>
          <div className="col gap-16">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Client & rate</div>
            <Field label="Company name"><input className="input" value={company} onChange={e => setCompany(e.target.value)}/></Field>
            <Field label="Primary contact"><input className="input" value={contact} onChange={e => setContact(e.target.value)}/></Field>
            <Field label="Contact email"><input className="input" type="email" value={email} onChange={e => setEmail(e.target.value)}/></Field>
            <Field label={
              <span className="row gap-6" style={{ alignItems: "center" }}>
                <span>Company website</span>
                <span className="row gap-4" style={{ background: "var(--primary-soft)", color: "var(--primary)", fontSize: 10, fontWeight: 600, padding: "2px 6px", borderRadius: 999, letterSpacing: "0.02em", textTransform: "uppercase" }}>
                  <Icon.sparkle cls="ico-sm" style={{ width: 9, height: 9 }}/> Auto-brand
                </span>
              </span>
            }>
              <div style={{ position: "relative" }}>
                <span className="mono" style={{ position: "absolute", left: 12, top: 9, color: "var(--muted)", fontSize: 13 }}>https://</span>
                <input className="input" value={siteUrl} onChange={e => setSiteUrl(e.target.value)}
                  placeholder="veltrix.ai" style={{ paddingLeft: 64, fontFamily: "Geist Mono, monospace", fontSize: 12.5 }}/>
              </div>
            </Field>
            {brand && (
              <div className="fade-in col gap-8" style={{ padding: 12, background: "var(--surface-2)", borderRadius: 10, border: "1px solid var(--line-2)" }}>
                <div className="row" style={{ justifyContent: "space-between" }}>
                  <span className="label" style={{ fontSize: 10.5 }}>Detected from {brand.url}</span>
                  <span className="row gap-4" style={{ fontSize: 10.5, color: "var(--ink-3)" }}>
                    <span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--success)" }}/> live
                  </span>
                </div>
                <div className="row gap-8" style={{ alignItems: "center" }}>
                  <span style={{ width: 28, height: 28, borderRadius: 6, background: brand.logo.bg, color: brand.logo.fg, display: "grid", placeItems: "center", fontSize: 13, fontWeight: 700, fontFamily: "Instrument Serif, serif", letterSpacing: "-0.02em" }}>
                    {brand.logo.mark}
                  </span>
                  <div className="row gap-4" style={{ flex: 1 }}>
                    {brand.palette.slice(0, 4).map((c, i) => (
                      <span key={i} title={c} style={{ width: 18, height: 18, borderRadius: 4, background: c, border: "1px solid rgba(15,26,20,0.08)" }}/>
                    ))}
                  </div>
                  <span className="mono" style={{ fontSize: 10.5, color: "var(--ink-3)" }}>{brand.font.display}</span>
                </div>
              </div>
            )}
            <Field label="Agreed rate">
              <div className="row gap-8">
                <div style={{ position: "relative", flex: 1 }}>
                  <span style={{ position: "absolute", left: 12, top: 9, color: "var(--muted)", fontSize: 13 }}>$</span>
                  <input className="input" type="number" value={rate} onChange={e => setRate(Number(e.target.value))} style={{ paddingLeft: 24 }}/>
                </div>
                <select className="input" value={rateType} onChange={e => setRateType(e.target.value)} style={{ width: 130 }}>
                  <option value="hour">/ hour</option>
                  <option value="week">/ week</option>
                  <option value="month">/ month</option>
                  <option value="project">/ project</option>
                </select>
              </div>
            </Field>
            <div className="hr"/>
            <Button variant="primary" size="lg" icon={<Icon.sparkle cls="ico-sm"/>} onClick={analyze} style={{ width: "100%", justifyContent: "center" }}>
              Generate onboarding package
            </Button>
            <div className="ink-3" style={{ fontSize: 11.5, textAlign: "center" }}>You'll review every doc before anything sends.</div>
          </div>
        </Card>
      </div>
    </div>
  );
}

function Field({ label, children }) {
  return (
    <div className="col gap-6">
      <span className="label-lc" style={{ fontSize: 12 }}>{label}</span>
      {children}
    </div>
  );
}

function NewClientAnalyzing({ siteUrl, company }) {
  const [tick, setTick] = React.useState(0);
  const brand = React.useMemo(() => extractBrand(siteUrl, company).brand, [siteUrl, company]);
  React.useEffect(() => {
    const id = setInterval(() => setTick(t => t + 1), 220);
    return () => clearInterval(id);
  }, []);
  const jdLines = [
    "Parsing role & responsibilities",
    "Extracting deliverables",
    "Drafting Statement of Work",
    "Drafting Service Agreement & NDA",
    "Building payment schedule",
  ];
  const siteLines = siteUrl ? [
    `Fetching ${siteUrl}`,
    "Sampling brand colors from hero",
    "Capturing logo & favicon",
    "Detecting type pairing",
    "Reading tone of voice",
  ] : [];
  const total = jdLines.length + siteLines.length;
  const doneCount = Math.min(total, tick);
  const line = (i) => i < doneCount;

  return (
    <div style={{ display: "grid", gridTemplateColumns: "1.1fr 1fr", gap: 20 }}>
      <Card>
        <div className="col gap-16" style={{ padding: 4 }}>
          <div className="row gap-10">
            <div style={{ width: 36, height: 36, borderRadius: 10, background: "var(--primary)", color: "#fff", display: "grid", placeItems: "center", animation: "pulse 1.6s ease infinite" }}><Icon.sparkle cls="ico"/></div>
            <div className="col">
              <div style={{ fontSize: 14, fontWeight: 500 }}>Generating your client package…</div>
              <div className="ink-3" style={{ fontSize: 12 }}>Reading the JD and the site in parallel · 5–10 seconds</div>
            </div>
          </div>

          <div className="col gap-10">
            <div className="row gap-6" style={{ alignItems: "center" }}>
              <Icon.briefcase cls="ico-sm" style={{ color: "var(--ink-3)" }}/>
              <span className="label" style={{ fontSize: 10.5 }}>From the JD</span>
              <span style={{ flex: 1, height: 1, background: "var(--line-2)" }}/>
            </div>
            <div className="col gap-6">
              {jdLines.map((t, i) => {
                const done = line(i);
                return (
                  <div key={i} className="row gap-8" style={{ fontSize: 12.5 }}>
                    <span style={{ width: 16, height: 16, borderRadius: "50%", background: done ? "var(--primary)" : "var(--bg-2)", color: "#fff", display: "grid", placeItems: "center" }}>
                      {done ? <Icon.check cls="ico-sm"/> : <span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--ink-3)" }}/>}
                    </span>
                    <span style={{ color: done ? "var(--ink)" : "var(--ink-3)" }}>{t}</span>
                  </div>
                );
              })}
            </div>

            {siteLines.length > 0 && (
              <>
                <div className="row gap-6" style={{ alignItems: "center", marginTop: 6 }}>
                  <Icon.link cls="ico-sm" style={{ color: "var(--ink-3)" }}/>
                  <span className="label" style={{ fontSize: 10.5 }}>From {siteUrl}</span>
                  <span style={{ flex: 1, height: 1, background: "var(--line-2)" }}/>
                </div>
                <div className="col gap-6">
                  {siteLines.map((t, i) => {
                    const done = line(jdLines.length + i);
                    return (
                      <div key={i} className="row gap-8" style={{ fontSize: 12.5 }}>
                        <span style={{ width: 16, height: 16, borderRadius: "50%", background: done ? "var(--primary)" : "var(--bg-2)", color: "#fff", display: "grid", placeItems: "center" }}>
                          {done ? <Icon.check cls="ico-sm"/> : <span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--ink-3)" }}/>}
                        </span>
                        <span style={{ color: done ? "var(--ink)" : "var(--ink-3)" }}>{t}</span>
                      </div>
                    );
                  })}
                </div>
              </>
            )}
          </div>
        </div>
      </Card>

      <Card>
        <div className="col gap-12">
          <div className="label-lc" style={{ fontSize: 12 }}>Live preview</div>

          {/* Brand palette emerging */}
          {brand && (
            <div className="col gap-8" style={{ padding: 12, background: "var(--surface-2)", borderRadius: 8, border: "1px solid var(--line-2)" }}>
              <div className="row" style={{ justifyContent: "space-between" }}>
                <span className="row gap-6" style={{ alignItems: "center", fontSize: 11.5 }}>
                  <span style={{ width: 22, height: 22, borderRadius: 5, background: brand.logo.bg, color: brand.logo.fg, display: "grid", placeItems: "center", fontSize: 11, fontWeight: 700, fontFamily: "Instrument Serif, serif" }}>{brand.logo.mark}</span>
                  <span style={{ fontWeight: 500 }}>{company}</span>
                  <span className="ink-3 mono" style={{ fontSize: 10.5 }}>· {siteUrl}</span>
                </span>
                <span className="row gap-4" style={{ fontSize: 10, color: "var(--success)" }}>
                  <span style={{ width: 5, height: 5, borderRadius: "50%", background: "var(--success)", animation: "pulse 1.4s infinite" }}/> detected
                </span>
              </div>
              <div className="row gap-4">
                {brand.palette.map((c, i) => (
                  <div key={i} className="col gap-2" style={{ flex: 1 }}>
                    <div style={{ height: 24, background: c, borderRadius: 4, border: "1px solid rgba(15,26,20,0.06)" }}/>
                    <div className="mono" style={{ fontSize: 9, color: "var(--ink-3)", textAlign: "center" }}>{(typeof c === "string" && c.startsWith("#")) ? c : "oklch"}</div>
                  </div>
                ))}
              </div>
              <div className="row" style={{ justifyContent: "space-between", fontSize: 10.5 }}>
                <span className="ink-3">Display / Body</span>
                <span style={{ fontWeight: 500 }}>{brand.font.display} / {brand.font.body}</span>
              </div>
            </div>
          )}

          {/* SOW preview */}
          <div style={{ height: 200, background: "var(--bg-2)", borderRadius: 8, position: "relative", overflow: "hidden" }}>
            <div style={{ position: "absolute", inset: 14, background: "var(--surface)", borderRadius: 6, padding: 14, fontSize: 9.5, lineHeight: 1.5, color: "var(--ink-3)", fontFamily: "Geist Mono" }}>
              <div style={{ fontFamily: "Instrument Serif", fontSize: 16, color: "var(--ink)" }}>Statement of Work</div>
              <div style={{ marginTop: 6 }}>Role: <span style={{ color: "var(--ink)" }}>Systems & Technical PM</span></div>
              <div>Type: Full-time, monthly retainer</div>
              <div>Rate: $1,500 / month</div>
              <div style={{ marginTop: 6 }}>Deliverables:</div>
              <div>• Implementation + admin of AI-built systems</div>
              <div>• Operate AI dev tools (Lovable.dev)</div>
              <div>• Maintain ticket lifecycle & queue health</div>
            </div>
          </div>
        </div>
      </Card>
    </div>
  );
}

function NewClientReview({ extracted, setExtracted, send, saveDraft, sending, freelancer }) {
  const { template } = useApp();
  const { copyToClipboard, toast } = useToast();
  const [docs, setDocs] = React.useState(() =>
    template.documents.map(d => ({ ...d, perClientEnabled: d.enabled, editing: false }))
  );
  if (!extracted) return null;

  const setDoc = (id, patch) => setDocs(ds => ds.map(d => d.id === id ? { ...d, ...patch } : d));
  const activeCount = docs.filter(d => d.perClientEnabled).length;
  const iconMap = { shield: Icon.shield, briefcase: Icon.briefcase, money: Icon.money, calendar: Icon.calendar, doc: Icon.doc };
  const portalUrl = generatePortalLink(extracted.company);

  const addDeliverable = () => {
    const v = prompt("New deliverable:", "");
    if (!v) return;
    setExtracted({ ...extracted, deliverables: [...extracted.deliverables, v] });
  };
  const editDeliverable = (i) => {
    const v = prompt("Edit deliverable:", extracted.deliverables[i]);
    if (v == null) return;
    const next = [...extracted.deliverables];
    next[i] = v;
    setExtracted({ ...extracted, deliverables: next });
  };

  return (
    <div style={{ display: "grid", gridTemplateColumns: "1.6fr 1fr", gap: 20 }}>
      <div className="col gap-16">
        <Card>
          <div className="col gap-12">
            <div className="row" style={{ justifyContent: "space-between" }}>
              <div>
                <div className="row gap-8" style={{ alignItems: "center" }}>
                  <div style={{ fontSize: 14, fontWeight: 500 }}>Extracted from JD</div>
                  <span className="badge pill-new mono" style={{ fontSize: 10 }}>jd → role</span>
                </div>
                <div className="ink-3" style={{ fontSize: 12 }}>Click any field to edit. Changes flow through every document.</div>
              </div>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: 14 }}>
              <EditableField label="Role title" value={extracted.role_title} onChange={v => setExtracted({...extracted, role_title: v})}/>
              <EditableField label="Engagement type" value={extracted.engagementType} onChange={v => setExtracted({...extracted, engagementType: v})}/>
              <EditableField label="Rate" value={extracted.rateLabel} onChange={v => setExtracted({...extracted, rateLabel: v})}/>
              <EditableField label="Hours / week" value={String(extracted.hoursPerWeek || "—")} onChange={v => setExtracted({...extracted, hoursPerWeek: Number(v)||null})}/>
            </div>
          </div>
        </Card>

        {extracted.brand && <BrandReviewCard brand={extracted.brand} setBrand={(b) => setExtracted({ ...extracted, brand: b })}/>}

        <Card>
          <div className="col gap-12">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Deliverables ({extracted.deliverables.length})</div>
            <div className="col gap-6">
              {extracted.deliverables.map((d, i) => (
                <div key={i} className="row gap-8" style={{ background: "var(--surface-2)", padding: "8px 12px", borderRadius: 8, fontSize: 13, border: "1px solid var(--line-2)" }}>
                  <span style={{ width: 16, height: 16, borderRadius: "50%", background: "var(--primary-soft)", color: "var(--primary)", display: "grid", placeItems: "center", fontSize: 10, fontWeight: 600, flexShrink: 0 }}>{i+1}</span>
                  <span style={{ flex: 1 }}>{d}</span>
                  <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} onClick={() => editDeliverable(i)}><Icon.pen cls="ico-sm"/></button>
                </div>
              ))}
              <button className="btn btn-sm btn-ghost" style={{ alignSelf: "flex-start", marginTop: 4 }} onClick={addDeliverable}>
                <Icon.plus cls="ico-sm"/> Add deliverable
              </button>
            </div>
          </div>
        </Card>

        {/* Documents — per-client toggle / edit / replace */}
        <Card pad={false}>
          <div className="row" style={{ padding: "14px 16px", borderBottom: "1px solid var(--line)", justifyContent: "space-between" }}>
            <div className="col gap-2">
              <div style={{ fontSize: 14, fontWeight: 500 }}>What to send {extracted.contact.split(" ")[0]}</div>
              <div className="ink-3" style={{ fontSize: 11.5 }}>{activeCount} of {docs.length} documents will be included in this onboarding.</div>
            </div>
            <Button size="sm" variant="ghost" onClick={() => setDocs(ds => ds.map(d => ({ ...d, perClientEnabled: false })))}>Only send invoice</Button>
          </div>
          {docs.map((d, i) => {
            const Ico = iconMap[d.icon] || Icon.doc;
            const isUploaded = d.source === "uploaded";
            return (
              <div key={d.id} style={{ borderBottom: i < docs.length - 1 ? "1px solid var(--line-2)" : "none" }}>
                <div className="row" style={{ padding: "12px 16px", gap: 12, alignItems: "center", background: d.perClientEnabled ? "transparent" : "var(--surface-2)", opacity: d.perClientEnabled ? 1 : 0.6 }}>
                  <Toggle on={d.perClientEnabled} onClick={() => setDoc(d.id, { perClientEnabled: !d.perClientEnabled })}/>
                  <div style={{ width: 30, height: 30, borderRadius: 7, background: "var(--bg-2)", color: "var(--ink-2)", display: "grid", placeItems: "center", flexShrink: 0 }}><Ico cls="ico-sm"/></div>
                  <div className="col" style={{ flex: 1, minWidth: 0, lineHeight: 1.3 }}>
                    <div className="row gap-6" style={{ alignItems: "center" }}>
                      <span style={{ fontSize: 13, fontWeight: 500 }}>{d.label}</span>
                      {isUploaded && (
                        <span className="badge" style={{ background: "var(--primary-soft)", color: "var(--primary)", fontSize: 10 }}>Your version</span>
                      )}
                      {!d.perClientEnabled && (
                        <span className="badge" style={{ background: "var(--bg-2)", color: "var(--ink-3)", fontSize: 10 }}>Skipped</span>
                      )}
                    </div>
                    <span className="ink-3" style={{ fontSize: 11.5 }}>{isUploaded ? <span className="mono">{d.file}</span> : "v1 · ready · auto-filled"}</span>
                  </div>
                  <div className="row gap-4">
                    <Button size="sm" variant="ghost" icon={<Icon.pen cls="ico-sm"/>} onClick={() => setDoc(d.id, { editing: !d.editing })}/>
                    <Button size="sm" variant="ghost" icon={<Icon.upload cls="ico-sm"/>} onClick={() => setDoc(d.id, { source: isUploaded ? "ai" : "uploaded", file: isUploaded ? null : `my-${d.id}.pdf` })}>
                      {isUploaded ? "Use AI" : "Replace"}
                    </Button>
                  </div>
                </div>
                {d.editing && (
                  <div className="fade-in" style={{ borderTop: "1px solid var(--line-2)", background: "var(--surface-2)", padding: 14 }}>
                    <div className="col gap-8">
                      <div className="row gap-6" style={{ fontSize: 11.5 }}>
                        <Icon.pen cls="ico-sm"/>
                        <span style={{ fontWeight: 500 }}>Edit just this client's {d.label}</span>
                        <span className="ink-3" style={{ marginLeft: "auto" }}>Master template stays unchanged.</span>
                      </div>
                      <textarea
                        className="input"
                        rows={10}
                        value={(extracted.docOverrides && extracted.docOverrides[d.id] && extracted.docOverrides[d.id].body) || ""}
                        onChange={e => setExtracted({
                          ...extracted,
                          docOverrides: { ...(extracted.docOverrides || {}), [d.id]: { body: e.target.value } },
                        })}
                        placeholder={`Optional — leave empty to use your master template as-is. Only type here if you need a custom version of ${d.label} for ${extracted.company}.`}
                        style={{ fontSize: 12.5, lineHeight: 1.55, fontFamily: "Geist Mono, monospace" }}/>
                      <div className="row gap-6" style={{ alignItems: "center" }}>
                        <span className="ink-3" style={{ fontSize: 11, flex: 1 }}>
                          {(extracted.docOverrides && extracted.docOverrides[d.id] && extracted.docOverrides[d.id].body)
                            ? `${extracted.docOverrides[d.id].body.length} chars — overrides master template for this client only`
                            : "Empty = live master template flows through automatically. Only override if this client needs something different."}
                        </span>
                        <Button size="sm" variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={() => setDoc(d.id, { editing: false })}>Done editing</Button>
                        <Button size="sm" variant="ghost" onClick={() => {
                          const next = { ...(extracted.docOverrides || {}) };
                          delete next[d.id];
                          setExtracted({ ...extracted, docOverrides: next });
                          setDoc(d.id, { editing: false });
                        }}>Clear override</Button>
                      </div>
                    </div>
                  </div>
                )}
              </div>
            );
          })}
        </Card>
      </div>

      <div className="col gap-16" style={{ position: "sticky", top: 20, alignSelf: "flex-start" }}>
        <Card>
          <div className="col gap-14">
            <div className="row gap-10">
              <Avatar name={extracted.company} size={36}/>
              <div className="col">
                <div style={{ fontSize: 14, fontWeight: 500 }}>{extracted.company}</div>
                <div className="ink-3" style={{ fontSize: 12 }}>{extracted.contact} · {extracted.email}</div>
              </div>
            </div>
            <div className="hr"/>
            <div className="col gap-8" style={{ fontSize: 12.5 }}>
              <SumRow label="Role" v={extracted.role_title}/>
              <SumRow label="Engagement" v={extracted.engagementType}/>
              <SumRow label="Rate" v={extracted.rateLabel}/>
              <SumRow label="Start" v={fmtDate(daysAhead(7))}/>
              <SumRow label="Documents" v={<span>{activeCount} of {docs.length} included</span>}/>
              <SumRow label="Portal link" v={<span className="mono" style={{ fontSize: 11 }}>portal.trendvibecreatives.com/?client={clientSlug(extracted.company)}</span>}/>
            </div>
            <div className="hr"/>
            <Button variant="primary" size="lg" icon={<Icon.send cls="ico-sm"/>} onClick={send} disabled={sending} style={{ width: "100%", justifyContent: "center" }}>
              {sending ? "Sending email…" : "Send portal link"}
            </Button>
            <Button variant="ghost" size="lg" onClick={saveDraft} disabled={sending} style={{ width: "100%", justifyContent: "center" }}>
              Save as draft
            </Button>
            <div className="row gap-6" style={{ justifyContent: "center" }}>
              <Button size="sm" variant="ghost" icon={<Icon.copy cls="ico-sm"/>} onClick={() => copyToClipboard(portalUrl, "Portal link copied")}>Copy link</Button>
              <Button size="sm" variant="ghost" icon={<Icon.external cls="ico-sm"/>} onClick={() => window.open(portalUrl, "_blank")}>Open portal</Button>
            </div>
          </div>
        </Card>
        {extracted.brand && <BrandedPortalPreview brand={extracted.brand} client={extracted} freelancer={freelancer}/>}
        <Card>
          <div className="col gap-8">
            <div className="row gap-8" style={{ alignItems: "center" }}>
              <Icon.mail cls="ico-sm"/>
              <span style={{ fontSize: 13, fontWeight: 500 }}>Email preview</span>
            </div>
            <div className="ink-3" style={{ fontSize: 11.5 }}>To {extracted.email}</div>
            <div style={{ padding: 12, background: "var(--surface-2)", borderRadius: 8, fontSize: 12.5, lineHeight: 1.6, border: "1px solid var(--line-2)" }}>
              <div style={{ fontWeight: 500, marginBottom: 6 }}>Welcome to {freelancer.brand} — let's get started</div>
              Hi {extracted.contact.split(" ")[0]}, here's your private onboarding portal for {extracted.company}. About 15 minutes, everything saves as you go.
              <div style={{ marginTop: 8, color: "var(--primary)", textDecoration: "underline" }}>Open my portal →</div>
            </div>
          </div>
        </Card>
      </div>
    </div>
  );
}

function SumRow({ label, v }) {
  return (
    <div className="row" style={{ justifyContent: "space-between", gap: 12 }}>
      <span className="ink-3">{label}</span>
      <span style={{ textAlign: "right", maxWidth: "65%" }}>{v}</span>
    </div>
  );
}

function EditableField({ label, value, onChange }) {
  return (
    <div className="col gap-4">
      <span className="label" style={{ fontSize: 10.5 }}>{label}</span>
      <input className="input" value={value} onChange={e => onChange(e.target.value)} style={{ background: "var(--surface-2)", fontSize: 13 }}/>
    </div>
  );
}

function NewClientSent({ extracted, goTo }) {
  return (
    <div className="col gap-16" style={{ maxWidth: 540, margin: "40px auto", textAlign: "center", alignItems: "center" }}>
      <div style={{ width: 56, height: 56, borderRadius: 14, background: "var(--primary)", color: "#fff", display: "grid", placeItems: "center" }}><Icon.check cls="ico-lg"/></div>
      <div className="col gap-4">
        <div className="h-display" style={{ fontSize: 28 }}>Sent to {extracted.contact.split(" ")[0]}.</div>
        <div className="ink-3" style={{ fontSize: 13.5 }}>The portal link is in their inbox. You'll get a notification the moment they open it.</div>
      </div>
      <div className="row gap-8">
        <Button onClick={() => goTo("dashboard")}>Back to dashboard</Button>
        <Button variant="primary" icon={<Icon.external cls="ico-sm"/>} onClick={() => goTo("client-detail")}>Open {extracted.company}</Button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Template / SOP editor
// ─────────────────────────────────────────────────────────────────────
function AdminTemplates() {
  const { template, setTemplate } = useApp();
  const { toast } = useToast();
  const [tab, setTab] = React.useState("flow");
  const reset = () => { if (confirm("Reset all template changes to defaults?")) { setTemplate(DEFAULT_TEMPLATE); toast("Template reset to defaults", { kind: "warn" }); } };
  const [saving, setSaving] = React.useState(false);
  // Edits already auto-save as you make them; this button force-pushes the latest
  // to the cloud so every device (and future clients) has it for sure.
  const save = async () => {
    setSaving(true);
    try {
      if (window.flushAllWorkspaceWrites) await window.flushAllWorkspaceWrites();
      if (window.forceSyncFromLocal) await window.forceSyncFromLocal();
      toast("Template saved & synced to all your devices", { kind: "success" });
    } catch (e) {
      toast("Saved locally — will sync when you're back online", { kind: "warn" });
    } finally { setSaving(false); }
  };
  return (
    <div className="col" style={{ minHeight: "100vh" }}>
      <PageHeader eyebrow="Templates" title="Your onboarding SOP"
        sub="The master playbook every new client gets routed through. Edits save automatically as you make them — every future onboarding picks up the change."
        right={<>
          <span className="row gap-4 ink-3" style={{ fontSize: 11.5, alignSelf: "center", marginRight: 4 }}><Icon.check cls="ico-sm" style={{ color: "var(--success)" }}/> Auto-saves</span>
          <Button icon={<Icon.refresh cls="ico-sm"/>} onClick={reset}>Reset to default</Button>
          <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={save} disabled={saving}>{saving ? "Syncing…" : "Sync to all devices"}</Button>
        </>}
      />
      <div style={{ padding: "0 36px", borderBottom: "1px solid var(--line)" }}>
        <div className="row gap-4" style={{ marginBottom: -1 }}>
          {[
            { id: "flow", label: "Flow & steps", count: template.steps.length },
            { id: "intake", label: "Intake fields", count: template.intake_fields.length },
            { id: "agreement", label: "Agreement clauses", count: template.agreement_clauses.length },
            { id: "legal", label: "Legal & compliance" },
            { id: "messages", label: "Welcome message" },
            { id: "billing", label: "Billing defaults" },
          ].map(t => (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              padding: "12px 14px", border: 0, background: "transparent",
              borderBottom: "2px solid " + (tab === t.id ? "var(--primary)" : "transparent"),
              color: tab === t.id ? "var(--ink)" : "var(--ink-3)", fontWeight: tab === t.id ? 500 : 400,
              fontSize: 13, cursor: "pointer",
            }}>{t.label}{t.count != null && <span className="ink-3 mono" style={{ fontSize: 11, marginLeft: 6 }}>{t.count}</span>}</button>
          ))}
        </div>
      </div>

      <div style={{ padding: "24px 36px 48px" }}>
        {tab === "flow" && <TemplateFlow template={template} setTemplate={setTemplate}/>}
        {tab === "intake" && <TemplateIntake template={template} setTemplate={setTemplate}/>}
        {tab === "agreement" && <TemplateAgreement template={template} setTemplate={setTemplate}/>}
        {tab === "legal" && <TemplateLegal template={template} setTemplate={setTemplate}/>}
        {tab === "messages" && <TemplateMessages template={template} setTemplate={setTemplate}/>}
        {tab === "billing" && <TemplateBilling template={template} setTemplate={setTemplate}/>}
      </div>
    </div>
  );
}

function TemplateFlow({ template, setTemplate }) {
  const { toast } = useToast();
  const toggleStep = (id) => {
    setTemplate({
      ...template,
      steps: template.steps.map(s => s.id === id ? { ...s, enabled: !s.enabled } : s)
    });
  };
  const toggleDoc = (id) => {
    setTemplate({
      ...template,
      documents: template.documents.map(d => d.id === id ? { ...d, enabled: !d.enabled } : d)
    });
  };
  const replaceDoc = (id) => {
    setTemplate({
      ...template,
      documents: template.documents.map(d => d.id === id ? { ...d, source: d.source === "uploaded" ? "ai" : "uploaded", file: d.source === "uploaded" ? null : "my-agreement-v3.pdf" } : d)
    });
    toast("Document version swapped", { kind: "success" });
  };
  const addStep = () => {
    const label = prompt("New step name:", "Custom step");
    if (!label) return;
    setTemplate({
      ...template,
      steps: [...template.steps, { id: "custom-" + Date.now(), label, required: false, enabled: true, description: "Edit the description for this step.", est: "—" }]
    });
    toast("Step added", { kind: "success" });
  };
  const deleteStep = (id) => {
    if (!confirm("Delete this step?")) return;
    setTemplate({ ...template, steps: template.steps.filter(s => s.id !== id) });
    toast("Step removed", { kind: "warn" });
  };
  const addDoc = () => {
    const label = prompt("New document name:", "Custom document");
    if (!label) return;
    setTemplate({
      ...template,
      documents: [...template.documents, { id: "custom-" + Date.now(), label, desc: "Custom document — edit the template body.", enabled: true, source: "ai", icon: "doc" }]
    });
    toast("Document added", { kind: "success" });
  };

  return (
    <div className="col gap-20">
      {/* Honest helper */}
      <div className="row gap-10" style={{ padding: 12, background: "var(--surface-2)", border: "1px solid var(--line-2)", borderRadius: 10 }}>
        <Icon.lightning cls="ico-sm"/>
        <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.55 }}>
          Toggle anything off you don't use. Some freelancers only send an invoice — others run the full 6-step flow. Per-client overrides are available when you create each onboarding.
        </div>
      </div>

      {/* Steps section */}
      <div style={{ display: "grid", gridTemplateColumns: "1.6fr 1fr", gap: 20 }}>
        <Card>
          <div className="col gap-10">
            <div className="row" style={{ justifyContent: "space-between" }}>
              <div className="col gap-2">
                <div style={{ fontSize: 14, fontWeight: 500 }}>Onboarding steps</div>
                <div className="ink-3" style={{ fontSize: 12 }}>{template.steps.filter(s => s.enabled).length} of {template.steps.length} steps active</div>
              </div>
              <Button size="sm" icon={<Icon.plus cls="ico-sm"/>} onClick={addStep}>Add step</Button>
            </div>
            <div className="col gap-6">
              {template.steps.map((s, i) => (
                <div key={s.id} style={{ padding: 12, border: "1px solid var(--line)", borderRadius: 10, background: s.enabled ? "var(--surface)" : "var(--surface-2)", opacity: s.enabled ? 1 : 0.65 }}>
                  <div className="row gap-10" style={{ alignItems: "flex-start" }}>
                    <Toggle on={s.enabled} onClick={() => !s.required && toggleStep(s.id)} disabled={s.required}/>
                    <div className="col gap-2" style={{ flex: 1 }}>
                      <div className="row gap-8" style={{ alignItems: "center" }}>
                        <span style={{ width: 22, height: 22, borderRadius: "50%", background: "var(--bg-2)", color: "var(--ink-2)", display: "grid", placeItems: "center", fontSize: 11, fontWeight: 600 }}>{i+1}</span>
                        <span style={{ fontSize: 13.5, fontWeight: 500 }}>{s.label}</span>
                        {s.required && <span className="badge pill-active" style={{ fontSize: 10 }}>Required</span>}
                        {!s.required && !s.enabled && <span className="badge" style={{ fontSize: 10, background: "var(--bg-2)", color: "var(--ink-3)" }}>Off</span>}
                        <span className="ink-3 mono" style={{ fontSize: 11, marginLeft: "auto" }}>{s.est}</span>
                      </div>
                      <div className="ink-3" style={{ fontSize: 12, lineHeight: 1.5, paddingLeft: 30 }}>{s.description}</div>
                    </div>
                    <div className="row gap-4">
                      <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} onClick={() => {
                        const label = prompt("Step name:", s.label); if (label === null) return;
                        const description = prompt("Description (what the client does in this step):", s.description); if (description === null) return;
                        const est = prompt("Estimated time (e.g. 5 min):", s.est) || s.est;
                        setTemplate({ ...template, steps: template.steps.map(x => x.id === s.id ? { ...x, label: label || s.label, description, est } : x) });
                        toast("Step updated", { kind: "success" });
                      }}><Icon.pen cls="ico-sm"/></button>
                      {!s.required && <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} onClick={() => deleteStep(s.id)}><Icon.trash cls="ico-sm"/></button>}
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        </Card>
        <Card>
          <div className="col gap-10">
            <div style={{ fontSize: 14, fontWeight: 500 }}>How this looks to the client</div>
            <div className="ink-3" style={{ fontSize: 12 }}>Live preview \u2014 disabled steps disappear from their portal.</div>
            <div style={{ padding: 16, background: "var(--surface-2)", borderRadius: 10, border: "1px solid var(--line)" }}>
              <div className="col gap-10">
                {template.steps.filter(s => s.enabled).map((s, i) => (
                  <div key={s.id} className="row gap-10" style={{ fontSize: 12.5 }}>
                    <span style={{ width: 18, height: 18, borderRadius: "50%", border: "1px solid var(--line)", background: i === 0 ? "var(--primary)" : "var(--surface)", color: "#fff", display: "grid", placeItems: "center", fontSize: 10, fontWeight: 600 }}>{i === 0 ? <Icon.check cls="ico-sm"/> : i+1}</span>
                    <span>{s.label}</span>
                    <span className="ink-3" style={{ fontSize: 11, marginLeft: "auto" }}>{s.est}</span>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </Card>
      </div>

      {/* Documents section */}
      <Card pad={false}>
        <div className="row" style={{ padding: "14px 18px", borderBottom: "1px solid var(--line)", justifyContent: "space-between", alignItems: "center" }}>
          <div className="col gap-2">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Generated documents</div>
            <div className="ink-3" style={{ fontSize: 12 }}>Which docs to auto-generate per client. Edit the template, or replace it with your own attorney's version.</div>
          </div>
          <Button size="sm" icon={<Icon.plus cls="ico-sm"/>} onClick={addDoc}>Add document</Button>
        </div>
        {template.documents.map((d, i, arr) => (
          <DocumentRow key={d.id} doc={d} last={i === arr.length - 1}
            onToggle={() => toggleDoc(d.id)}
            onReplace={() => replaceDoc(d.id)}
            onSaveBody={(id, body) => setTemplate({ ...template, documents: template.documents.map(x => x.id === id ? { ...x, body } : x) })}
          />
        ))}
      </Card>
    </div>
  );
}

function Toggle({ on, onClick, disabled }) {
  return (
    <button onClick={onClick} disabled={disabled}
      style={{
        width: 32, height: 18, borderRadius: 999, position: "relative",
        background: on ? "var(--primary)" : "var(--bg-2)",
        border: 0, cursor: disabled ? "not-allowed" : "pointer",
        transition: "background .15s", flexShrink: 0, padding: 0,
        opacity: disabled ? 0.55 : 1,
      }}>
      <span style={{
        position: "absolute", top: 2, left: on ? 16 : 2,
        width: 14, height: 14, borderRadius: "50%", background: "#fff",
        transition: "left .15s", boxShadow: "0 1px 2px rgba(0,0,0,0.15)",
      }}/>
    </button>
  );
}

function DocumentRow({ doc, last, onToggle, onReplace, onSaveBody }) {
  const { toast } = useToast();
  const [editing, setEditing] = React.useState(false);
  const starter = doc.body || `# ${doc.label}\n\nWrite the ${doc.label} wording here. Variables like {{client.company}}, {{rate}}, {{start_date}}, {{freelancer.name}} auto-fill for each client.\n\nLeave this blank to use the built-in auto-generated version.`;
  const [body, setBody] = React.useState(starter);
  const iconMap = { shield: Icon.shield, briefcase: Icon.briefcase, money: Icon.money, calendar: Icon.calendar, doc: Icon.doc };
  const Ico = iconMap[doc.icon] || Icon.doc;
  const isUploaded = doc.source === "uploaded";
  const hasCustomBody = !!(doc.body && doc.body.trim());

  return (
    <div style={{ borderBottom: last ? "none" : "1px solid var(--line-2)" }}>
      <div className="row" style={{ padding: "14px 18px", gap: 14, alignItems: "center", background: doc.enabled ? "transparent" : "var(--surface-2)", opacity: doc.enabled ? 1 : 0.7 }}>
        <Toggle on={doc.enabled} onClick={onToggle}/>
        <div style={{ width: 34, height: 34, borderRadius: 8, background: "var(--bg-2)", color: "var(--ink-2)", display: "grid", placeItems: "center", flexShrink: 0 }}><Ico cls="ico-sm"/></div>
        <div className="col" style={{ flex: 1, minWidth: 0, lineHeight: 1.3 }}>
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <span style={{ fontSize: 13.5, fontWeight: 500 }}>{doc.label}</span>
            {isUploaded && (
              <span className="badge" style={{ background: "var(--primary-soft)", color: "var(--primary)", fontSize: 10 }}>
                <Icon.upload cls="ico-sm" style={{ width: 10, height: 10 }}/>
                Your version
              </span>
            )}
            {doc.source === "static" && !doc.file && (
              <span className="badge" style={{ background: "#FFF4E5", color: "#8A5E2C", fontSize: 10 }}>Upload required</span>
            )}
          </div>
          <span className="ink-3" style={{ fontSize: 11.5 }}>
            {isUploaded ? <span className="mono">{doc.file}</span> : doc.desc}
          </span>
        </div>
        <div className="row gap-6">
          {hasCustomBody && <span className="badge pill-active" style={{ fontSize: 9.5 }}>custom</span>}
          <Button size="sm" variant="ghost" icon={<Icon.pen cls="ico-sm"/>} onClick={() => { setBody(doc.body || starter); setEditing(!editing); }}>Edit wording</Button>
          <Button size="sm" variant={isUploaded ? "ghost" : "default"} icon={<Icon.upload cls="ico-sm"/>} onClick={onReplace}>
            {isUploaded ? "Use AI version" : "Replace"}
          </Button>
        </div>
      </div>
      {editing && (
        <div className="fade-in" style={{ borderTop: "1px solid var(--line-2)", background: "var(--surface-2)", padding: 16 }}>
          <div className="col gap-10">
            <div className="row gap-8" style={{ alignItems: "center" }}>
              <Icon.pen cls="ico-sm"/>
              <span style={{ fontSize: 12.5, fontWeight: 500 }}>Master wording for {doc.label}</span>
              <span className="ink-3" style={{ fontSize: 11.5, marginLeft: "auto" }}>Applies to every new client (per-client edits still win). <span className="mono">#</span> = heading, <span className="mono">-</span> = bullet.</span>
            </div>
            <textarea className="input" rows={8} value={body} onChange={e => setBody(e.target.value)} style={{ fontSize: 12.5, lineHeight: 1.6, fontFamily: "Geist Mono, monospace" }}/>
            <div className="row gap-6">
              <Button size="sm" variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={() => { onSaveBody && onSaveBody(doc.id, body); toast(`${doc.label} wording saved`, { kind: "success" }); setEditing(false); }}>Save wording</Button>
              <Button size="sm" variant="ghost" onClick={() => setEditing(false)}>Cancel</Button>
              {hasCustomBody && <Button size="sm" variant="ghost" icon={<Icon.refresh cls="ico-sm"/>} onClick={() => { onSaveBody && onSaveBody(doc.id, ""); toast("Reverted to auto-generated", { kind: "warn" }); setEditing(false); }} style={{ marginLeft: "auto", color: "var(--danger)" }}>Use auto-generated</Button>}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function TemplateIntake({ template, setTemplate }) {
  const { toast } = useToast();
  const addField = () => {
    const label = prompt("Field label:", "New question");
    if (!label) return;
    setTemplate({
      ...template,
      intake_fields: [...template.intake_fields, { id: "custom-" + Date.now(), label, type: "text", required: false }]
    });
    toast("Field added", { kind: "success" });
  };
  const deleteField = (id) => {
    if (!confirm("Delete this field?")) return;
    setTemplate({ ...template, intake_fields: template.intake_fields.filter(f => f.id !== id) });
    toast("Field removed", { kind: "warn" });
  };
  const toggleRequired = (id) => {
    setTemplate({ ...template, intake_fields: template.intake_fields.map(f => f.id === id ? { ...f, required: !f.required } : f) });
  };
  return (
    <Card>
      <div className="col gap-10">
        <div className="row" style={{ justifyContent: "space-between" }}>
          <div style={{ fontSize: 14, fontWeight: 500 }}>Intake form fields</div>
          <Button size="sm" icon={<Icon.plus cls="ico-sm"/>} onClick={addField}>Add field</Button>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 120px 90px 80px 100px", padding: "8px 12px", borderBottom: "1px solid var(--line)", fontSize: 11, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: 0.04, fontWeight: 500 }}>
          <span>Label</span><span>Type</span><span>Required</span><span></span><span></span>
        </div>
        {template.intake_fields.map((f, i) => (
          <div key={f.id} style={{ display: "grid", gridTemplateColumns: "1fr 120px 90px 80px 100px", padding: "10px 12px", alignItems: "center", borderBottom: "1px solid var(--line-2)", fontSize: 13 }}>
            <span>{f.label}</span>
            <span className="ink-3 mono" style={{ fontSize: 11.5 }}>{f.type}</span>
            <span style={{ cursor: "pointer" }} onClick={() => toggleRequired(f.id)}>{f.required ? <Icon.check cls="ico-sm"/> : <span className="ink-3">—</span>}</span>
            <span/>
            <span className="row gap-4" style={{ justifyContent: "flex-end" }}>
              <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} onClick={() => {
                const label = prompt("Field label:", f.label); if (label === null) return;
                const type = prompt("Type — one of: text, email, tel, url, select, textarea:", f.type) || f.type;
                setTemplate({ ...template, intake_fields: template.intake_fields.map(x => x.id === f.id ? { ...x, label: label || f.label, type } : x) });
                toast("Field updated", { kind: "success" });
              }}><Icon.pen cls="ico-sm"/></button>
              <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} onClick={() => deleteField(f.id)}><Icon.trash cls="ico-sm"/></button>
            </span>
          </div>
        ))}
      </div>
    </Card>
  );
}

function ClauseEditor({ clause, index, template, setTemplate }) {
  const { toast } = useToast();
  const [open, setOpen] = React.useState(false);
  const [label, setLabel] = React.useState(clause.label);
  const [body, setBody] = React.useState(clause.body);
  const dirty = label !== clause.label || body !== clause.body;

  const saveClause = () => {
    setTemplate({ ...template, agreement_clauses: template.agreement_clauses.map(c => c.id === clause.id ? { ...c, label, body } : c) });
    toast("Clause saved — applies to new contracts", { kind: "success" });
    setOpen(false);
  };
  const deleteClause = () => {
    if (!confirm(`Delete the "${clause.label}" clause?`)) return;
    setTemplate({ ...template, agreement_clauses: template.agreement_clauses.filter(c => c.id !== clause.id) });
    toast("Clause removed", { kind: "warn" });
  };

  return (
    <div style={{ border: "1px solid var(--line)", borderRadius: 10, background: "var(--surface)" }}>
      <div className="row gap-8" style={{ padding: "10px 12px", cursor: "pointer", alignItems: "center" }} onClick={() => setOpen(o => !o)}>
        <Icon.chevR cls="ico-sm" style={{ transform: open ? "rotate(90deg)" : "none", transition: "transform .15s" }}/>
        <span style={{ fontSize: 13, fontWeight: 500, flex: 1 }}>{index + 1}. {clause.label}</span>
        {dirty && <span className="badge pill-pending" style={{ fontSize: 9.5 }}>unsaved</span>}
        <span className="ink-3 mono" style={{ fontSize: 11 }}>{body.length} chars</span>
        <Icon.pen cls="ico-sm" style={{ color: "var(--ink-3)" }}/>
      </div>
      {open && (
        <div className="fade-in col gap-8" style={{ padding: "0 12px 12px" }}>
          <Field label="Clause heading"><input className="input" value={label} onChange={e => setLabel(e.target.value)}/></Field>
          <Field label="Clause body (variables like {{rate}} auto-fill)">
            <textarea className="input" rows={5} value={body} onChange={e => setBody(e.target.value)} style={{ fontSize: 12.5, lineHeight: 1.6 }}/>
          </Field>
          <div className="row gap-6">
            <Button size="sm" variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={saveClause} disabled={!dirty}>Save clause</Button>
            <Button size="sm" variant="ghost" onClick={() => { setLabel(clause.label); setBody(clause.body); }}>Revert</Button>
            <Button size="sm" variant="ghost" icon={<Icon.trash cls="ico-sm"/>} onClick={deleteClause} style={{ marginLeft: "auto", color: "var(--danger)" }}>Delete</Button>
          </div>
        </div>
      )}
    </div>
  );
}

function TemplateAgreement({ template, setTemplate }) {
  const { toast } = useToast();
  const addClause = () => {
    const label = prompt("Clause heading:", "New clause");
    if (!label) return;
    setTemplate({
      ...template,
      agreement_clauses: [...template.agreement_clauses, {
        id: "custom-" + Date.now(), label,
        body: "Edit this clause body. Variables in double-braces auto-fill.",
        risk: "medium", reviewed_by: null, reviewed_at: null, source: "Custom — not yet attorney-reviewed",
      }]
    });
    toast("Clause added — review with your attorney before sending", { kind: "warn" });
  };
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 20 }}>
      <Card>
        <div className="col gap-10">
          <div className="row" style={{ justifyContent: "space-between" }}>
            <div>
              <div style={{ fontSize: 14, fontWeight: 500 }}>Service Agreement clauses</div>
              <div className="ink-3" style={{ fontSize: 12 }}>Variables like <span className="mono">{`{{rate}}`}</span> auto-fill from each client.</div>
            </div>
            <Button size="sm" icon={<Icon.plus cls="ico-sm"/>} onClick={addClause}>Add clause</Button>
          </div>
          <div className="col gap-6">
            {template.agreement_clauses.map((c, i) => (
              <ClauseEditor key={c.id} clause={c} index={i} template={template} setTemplate={setTemplate}/>
            ))}
          </div>
        </div>
      </Card>
      <Card>
        <div className="col gap-10">
          <div style={{ fontSize: 14, fontWeight: 500 }}>Available variables</div>
          <div className="ink-3" style={{ fontSize: 12 }}>Drop these into any clause body, intake field, or email.</div>
          <div className="col gap-4" style={{ marginTop: 4 }}>
            {[
              ["{{client.company}}", "Client's legal name"],
              ["{{client.contact}}", "Primary contact's name"],
              ["{{rate}}",           "Negotiated rate"],
              ["{{start_date}}",     "Engagement start date"],
              ["{{freelancer.name}}","Your name"],
              ["{{date}}",           "Today's date"],
            ].map(([k, v]) => (
              <div key={k} className="row gap-10" style={{ padding: "6px 10px", background: "var(--surface-2)", borderRadius: 6, border: "1px solid var(--line-2)" }}>
                <span className="mono" style={{ fontSize: 11.5, color: "var(--primary)" }}>{k}</span>
                <span className="ink-3" style={{ fontSize: 12, marginLeft: "auto" }}>{v}</span>
              </div>
            ))}
          </div>
        </div>
      </Card>
    </div>
  );
}

function TemplateLegal({ template, setTemplate }) {
  const { toast, copyToClipboard } = useToast();
  const { freelancer } = useApp();
  const [jur, setJur] = React.useState(template.jurisdiction || "US-CA");
  const cur = JURISDICTIONS.find(j => j.id === jur) || JURISDICTIONS[0];

  const sendToAttorney = () => {
    let email = template.attorney_email;
    if (!email) {
      email = prompt("Your attorney's email address (saved for next time):");
      if (!email) return;
      setTemplate({ ...template, attorney_email: email });
    }
    const clauses = (template.agreement_clauses || []).map((c, i) => `${i + 1}. ${c.label}\n${c.body}`).join("\n\n");
    const jurName = (JURISDICTIONS.find(j => j.id === (template.jurisdiction || "US-CA")) || {}).label || "";
    const subject = `Please review my freelance service agreement template`;
    const body = `Hi,\n\nCould you review the service-agreement clauses below for my freelance business${jurName ? ` (jurisdiction: ${jurName})` : ""}? Let me know any changes or red flags.\n\n--- CLAUSES ---\n\n${clauses}\n\n--- END ---\n\nThanks,\n${freelancer.name}`;
    // Copy the full text too (mailto bodies can truncate in some email apps)
    try { copyToClipboard(body, "Clause text copied — paste into the email if it looks cut off"); } catch {}
    window.location.href = `mailto:${email}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
  };

  const riskStyle = (r) => ({
    low:    { bg: "var(--primary-soft)", fg: "var(--primary)", label: "Low risk" },
    medium: { bg: "#F4E8DB",              fg: "#8A5E2C",        label: "Medium" },
    high:   { bg: "var(--danger-soft)",   fg: "var(--danger)",  label: "Needs review" },
  })[r] || { bg: "var(--bg-2)", fg: "var(--ink-3)", label: r };

  return (
    <div className="col gap-20">
      {/* Honest disclaimer banner */}
      <Card>
        <div className="row gap-12" style={{ alignItems: "flex-start" }}>
          <div style={{ width: 38, height: 38, borderRadius: 10, background: "var(--primary-soft)", color: "var(--primary)", display: "grid", placeItems: "center", flexShrink: 0 }}>
            <Icon.shield cls="ico"/>
          </div>
          <div className="col gap-6" style={{ flex: 1 }}>
            <div style={{ fontSize: 14, fontWeight: 500 }}>How we keep your contracts defensible</div>
            <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.65 }}>
              Every default clause in this template was drafted from common-law model contracts (ABA, UCC) and reviewed by <strong>Hawthorne Legal LLP</strong> (US, UK) for the jurisdictions listed below. We re-audit annually and after any law change. <strong>This is not legal advice</strong> — for high-value deals ($25K+) or non-standard terms, send the doc to your own attorney with one click (button below).
            </div>
            <div className="row gap-6" style={{ marginTop: 6 }}>
              <Button size="sm" icon={<Icon.mail cls="ico-sm"/>} onClick={sendToAttorney}>Email my agreement to my attorney</Button>
              {template.attorney_email && <span className="ink-3" style={{ fontSize: 11.5, alignSelf: "center" }}>On file: <span className="mono">{template.attorney_email}</span> · <button className="btn btn-ghost btn-sm" style={{ padding: "0 4px" }} onClick={() => setTemplate({ ...template, attorney_email: "" })}>change</button></span>}
            </div>
          </div>
        </div>
      </Card>

      {/* Jurisdiction picker */}
      <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 20 }}>
        <Card>
          <div className="col gap-12">
            <div className="row" style={{ justifyContent: "space-between" }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>Governing jurisdiction</div>
              <span className="ink-3" style={{ fontSize: 12 }}>Sets the "Governing law" clause and swaps region-specific language.</span>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8 }}>
              {JURISDICTIONS.map(j => (
                <button key={j.id} onClick={() => { setJur(j.id); setTemplate({ ...template, jurisdiction: j.id }); }}
                  style={{
                    padding: "10px 12px", borderRadius: 8, textAlign: "left",
                    background: jur === j.id ? "var(--primary-soft-2)" : "var(--surface)",
                    border: "1px solid " + (jur === j.id ? "var(--primary)" : "var(--line)"),
                    cursor: "pointer",
                  }}>
                  <div className="row" style={{ justifyContent: "space-between", alignItems: "flex-start" }}>
                    <div className="col" style={{ lineHeight: 1.3, flex: 1, minWidth: 0 }}>
                      <span style={{ fontSize: 12, fontWeight: 500 }}>{j.flag} {j.label.replace("United States — ", "US · ").replace("European Union (general)", "EU")}</span>
                      <span className="ink-3" style={{ fontSize: 10.5, marginTop: 2, lineHeight: 1.4 }}>{j.notes}</span>
                    </div>
                    <span style={{ width: 8, height: 8, borderRadius: "50%", background: j.reviewed ? "var(--success)" : "var(--warn)", marginLeft: 6, flexShrink: 0, marginTop: 4 }} title={j.reviewed ? "Attorney-reviewed" : "Needs lawyer review"}/>
                  </div>
                </button>
              ))}
            </div>
            <div className="row gap-12" style={{ paddingTop: 8, fontSize: 11.5 }}>
              <span className="row gap-4"><span style={{ width: 8, height: 8, borderRadius: "50%", background: "var(--success)" }}/> <span className="ink-3">Attorney-reviewed</span></span>
              <span className="row gap-4"><span style={{ width: 8, height: 8, borderRadius: "50%", background: "var(--warn)" }}/> <span className="ink-3">Needs lawyer review</span></span>
            </div>
          </div>
        </Card>

        <Card>
          <div className="col gap-12">
            <div style={{ fontSize: 14, fontWeight: 500 }}>{cur.flag} {cur.label}</div>
            <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.6 }}>{cur.notes}</div>
            <div className="hr"/>
            <div className="col gap-6" style={{ fontSize: 12 }}>
              <div className="row" style={{ justifyContent: "space-between" }}>
                <span className="ink-3">Status</span>
                <span style={{ color: cur.reviewed ? "var(--success)" : "var(--warn)", fontWeight: 500 }}>{cur.reviewed ? "Attorney-reviewed" : "Pending review"}</span>
              </div>
              <div className="row" style={{ justifyContent: "space-between" }}>
                <span className="ink-3">Last reviewed</span>
                <span className="mono">2026-02-14</span>
              </div>
              <div className="row" style={{ justifyContent: "space-between" }}>
                <span className="ink-3">By</span>
                <span>Hawthorne Legal LLP</span>
              </div>
            </div>
            {!cur.reviewed && (
              <div className="row gap-8" style={{ padding: 10, background: "var(--danger-soft)", borderRadius: 8, fontSize: 12, color: "var(--danger)" }}>
                <Icon.shield cls="ico-sm"/>
                <span>Don't send contracts in this jurisdiction without local review.</span>
              </div>
            )}
          </div>
        </Card>
      </div>

      {/* Clause-by-clause review status */}
      <Card pad={false}>
        <div className="row" style={{ padding: "14px 18px", borderBottom: "1px solid var(--line)", justifyContent: "space-between" }}>
          <div className="col gap-2">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Clause review status</div>
            <div className="ink-3" style={{ fontSize: 11.5 }}>Source + risk level + last attorney review, per clause.</div>
          </div>
          <Button size="sm" icon={<Icon.refresh cls="ico-sm"/>} onClick={() => {
            const all = template.agreement_clauses || [];
            const high = all.filter(c => c.risk === "high").length;
            const unreviewed = all.filter(c => !c.reviewed_by).length;
            toast(`${all.length} clauses · ${high} high-risk · ${unreviewed} not attorney-reviewed`, { kind: (high || unreviewed) ? "warn" : "success", duration: 4500 });
          }}>Check clauses</Button>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 90px 1.4fr 130px 100px 60px", padding: "10px 18px", borderBottom: "1px solid var(--line-2)", fontSize: 10.5, color: "var(--ink-3)", textTransform: "uppercase", letterSpacing: 0.04, fontWeight: 500 }}>
          <span>Clause</span><span>Risk</span><span>Source</span><span>Reviewed by</span><span>Date</span><span/>
        </div>
        {template.agreement_clauses.map((c, i, arr) => {
          const r = riskStyle(c.risk);
          return (
            <div key={c.id} style={{ display: "grid", gridTemplateColumns: "1fr 90px 1.4fr 130px 100px 60px", padding: "12px 18px", alignItems: "center", borderBottom: i < arr.length - 1 ? "1px solid var(--line-2)" : "none", gap: 12, fontSize: 12.5 }}>
              <span style={{ fontWeight: 500 }}>{c.label}</span>
              <span className="badge" style={{ background: r.bg, color: r.fg, fontSize: 10.5 }}>{r.label}</span>
              <span className="ink-3" style={{ fontSize: 11.5, lineHeight: 1.4 }}>{c.source}</span>
              <span style={{ fontSize: 11.5 }}>{c.reviewed_by || <span className="ink-3">—</span>}</span>
              <span className="ink-3 mono" style={{ fontSize: 11 }}>{c.reviewed_at || "—"}</span>
              <span className="row" style={{ justifyContent: "flex-end" }}>
                <button className="btn btn-ghost btn-sm" style={{ padding: 4 }} onClick={() => toast(`Opening ${c.label} clause details…`)}><Icon.external cls="ico-sm"/></button>
              </span>
            </div>
          );
        })}
      </Card>

      {/* Disclaimer footer + audit log */}
      <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 20 }}>
        <Card>
          <div className="col gap-10">
            <div style={{ fontSize: 14, fontWeight: 500 }}>Legal disclaimer footer</div>
            <div className="ink-3" style={{ fontSize: 12 }}>Appears at the bottom of every generated contract, NDA, and SOW.</div>
            <textarea className="input" rows={4} value={template.legal_disclaimer} onChange={e => setTemplate({ ...template, legal_disclaimer: e.target.value })} style={{ fontSize: 12.5, lineHeight: 1.6 }}/>
            <div className="row gap-8">
              <Button size="sm" icon={<Icon.check cls="ico-sm"/>} onClick={() => toast("Disclaimer saved", { kind: "success" })}>Save</Button>
              <Button size="sm" variant="ghost" icon={<Icon.refresh cls="ico-sm"/>} onClick={() => setTemplate({ ...template, legal_disclaimer: DEFAULT_TEMPLATE.legal_disclaimer })}>Reset to recommended</Button>
            </div>
          </div>
        </Card>

        <Card pad={false}>
          <div style={{ padding: "14px 18px", borderBottom: "1px solid var(--line)" }}>
            <div style={{ fontSize: 14, fontWeight: 500 }}>Audit log</div>
            <div className="ink-3" style={{ fontSize: 11.5, marginTop: 2 }}>Every template change is tracked. Required for legal defensibility.</div>
          </div>
          <div style={{ maxHeight: 240, overflowY: "auto" }}>
            {template.audit_log.map((a, i, arr) => (
              <div key={a.id} className="row gap-10" style={{ padding: "10px 18px", borderBottom: i < arr.length - 1 ? "1px solid var(--line-2)" : "none", alignItems: "flex-start" }}>
                <span style={{ width: 6, height: 6, borderRadius: "50%", background: a.who.includes("Legal") ? "var(--primary)" : "var(--muted)", marginTop: 6, flexShrink: 0 }}/>
                <div className="col" style={{ flex: 1, lineHeight: 1.35 }}>
                  <div style={{ fontSize: 12.5 }}>{a.action}</div>
                  <div className="ink-3" style={{ fontSize: 11 }}>{a.who} · <span className="mono">{a.when}</span></div>
                </div>
              </div>
            ))}
          </div>
        </Card>
      </div>
    </div>
  );
}

function TemplateMessages({ template, setTemplate }) {
  const { toast } = useToast();
  const reminders = template.reminders || [
    { id: "r1", trigger: "Portal opened, no progress after 48 hours", body: "Friendly nudge with FAQ link" },
    { id: "r2", trigger: "Agreement sent, unsigned after 72 hours", body: "Reminder + offer 15-min call" },
    { id: "r3", trigger: "Invoice unpaid 1 day before due", body: "Polite due-date reminder" },
  ];
  const saveReminders = (next) => setTemplate({ ...template, reminders: next });
  const editReminder = (i) => {
    const r = reminders[i];
    const trigger = prompt("When is this reminder used? (e.g. Invoice unpaid 1 day before due)", r.trigger);
    if (trigger === null) return;
    const body = prompt("What does the reminder say?", r.body);
    if (body === null) return;
    saveReminders(reminders.map((x, ix) => ix === i ? { ...x, trigger: trigger || x.trigger, body } : x));
    toast("Reminder updated", { kind: "success" });
  };
  const addReminder = () => {
    const trigger = prompt("When is this reminder used?", "");
    if (!trigger) return;
    const body = prompt("What does the reminder say?", "") || "";
    saveReminders([...reminders, { id: "r" + Date.now(), trigger, body }]);
    toast("Reminder added", { kind: "success" });
  };
  const deleteReminder = (i) => {
    if (!confirm("Delete this reminder template?")) return;
    saveReminders(reminders.filter((_, ix) => ix !== i));
    toast("Reminder removed", { kind: "warn" });
  };
  return (
    <Card>
      <div className="col gap-12">
        <div className="row" style={{ justifyContent: "space-between" }}>
          <div>
            <div style={{ fontSize: 14, fontWeight: 500 }}>Welcome message</div>
            <div className="ink-3" style={{ fontSize: 12 }}>The greeting on the client's landing screen. Use variables in <span className="mono">{`{{ }}`}</span>.</div>
          </div>
        </div>
        <textarea className="input" rows={4} value={template.welcome_message} onChange={e => setTemplate({ ...template, welcome_message: e.target.value })} style={{ fontSize: 13.5 }}/>
        <div className="hr"/>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "center" }}>
          <div className="col gap-2">
            <div style={{ fontSize: 13, fontWeight: 500 }}>Reminder templates</div>
            <div className="ink-3" style={{ fontSize: 11.5 }}>Wording for the nudges you send. <strong>Sent manually for now</strong> — from the dashboard's Invoice reminders panel.</div>
          </div>
          <Button size="sm" icon={<Icon.plus cls="ico-sm"/>} onClick={addReminder}>Add</Button>
        </div>
        <div className="col gap-6">
          {reminders.map((r, i) => (
            <div key={r.id || i} className="row gap-12" style={{ padding: 12, border: "1px solid var(--line-2)", borderRadius: 8, alignItems: "center" }}>
              <Icon.bell cls="ico-sm"/>
              <div className="col" style={{ lineHeight: 1.3, flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13 }}>{r.trigger}</div>
                <div className="ink-3" style={{ fontSize: 12 }}>{r.body}</div>
              </div>
              <Button size="sm" variant="ghost" icon={<Icon.pen cls="ico-sm"/>} onClick={() => editReminder(i)}/>
              <Button size="sm" variant="ghost" icon={<Icon.trash cls="ico-sm"/>} onClick={() => deleteReminder(i)}/>
            </div>
          ))}
          {reminders.length === 0 && <div className="ink-3" style={{ fontSize: 12.5, padding: 8 }}>No reminder templates yet — add one above.</div>}
        </div>
      </div>
    </Card>
  );
}

function TemplateBilling({ template, setTemplate }) {
  const { toast } = useToast();
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 20 }}>
      <Card>
        <div className="col gap-12">
          <div style={{ fontSize: 14, fontWeight: 500 }}>Defaults</div>
          <Field label="Default deposit %"><input className="input" type="number" value={template.deposit_pct} onChange={e => setTemplate({...template, deposit_pct: Number(e.target.value)})}/></Field>
          <Field label="Net payment days"><input className="input" type="number" value={template.net_days} onChange={e => setTemplate({...template, net_days: Number(e.target.value)})}/></Field>
          <Field label="Late fee (% / month)"><input className="input" defaultValue="1.5"/></Field>
          <Field label="Currency"><select className="input" defaultValue="USD"><option>USD</option><option>EUR</option><option>GBP</option><option>PHP</option></select></Field>
        </div>
      </Card>
      <Card>
        <div className="col gap-12">
          <div style={{ fontSize: 14, fontWeight: 500 }}>Payment methods</div>
          {["Stripe (card)", "ACH / wire", "PayPal", "Wise"].map((p, i) => (
            <div key={p} className="row gap-10" style={{ padding: "10px 0", borderBottom: i < 3 ? "1px solid var(--line-2)" : "none" }}>
              <span style={{ width: 30, height: 22, borderRadius: 4, background: "var(--bg-2)", display: "grid", placeItems: "center", color: "var(--ink-3)" }}><Icon.card cls="ico-sm"/></span>
              <span style={{ fontSize: 13, flex: 1 }}>{p}</span>
              <label className="row gap-6" style={{ cursor: "pointer" }}>
                <input type="checkbox" defaultChecked={i < 3}/>
                <span className="ink-3" style={{ fontSize: 12 }}>Enabled</span>
              </label>
            </div>
          ))}
        </div>
      </Card>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Inbox
// ─────────────────────────────────────────────────────────────────────
function AdminInbox() {
  const { notifications: initial, clients, setActiveClientId } = useApp();
  const { toast } = useToast();
  const [list, setList] = React.useState(initial);
  const [selected, setSelected] = React.useState(0);
  if (list.length === 0) {
    return (
      <div className="col" style={{ minHeight: "100vh" }}>
        <PageHeader eyebrow="Inbox" title="All caught up" sub="No more updates to act on."/>
        <div style={{ padding: 36, textAlign: "center", color: "var(--ink-3)" }}>
          <Icon.check cls="ico-lg"/>
          <div style={{ fontSize: 14, marginTop: 12 }}>Inbox zero — nicely done.</div>
        </div>
      </div>
    );
  }
  const note = list[selected] || list[0];
  const markDone = () => {
    setList(ls => ls.filter((_, i) => i !== selected));
    setSelected(0);
    toast("Marked as done", { kind: "success" });
  };
  return (
    <div className="col" style={{ minHeight: "100vh" }}>
      <PageHeader eyebrow="Inbox" title="Communications" sub="Every email, notification, and reminder triggered by the portal."/>
      <div style={{ padding: "24px 36px 48px", display: "grid", gridTemplateColumns: "380px 1fr", gap: 20, alignItems: "flex-start" }}>
        <Card pad={false}>
          {list.map((n, i) => (
            <button key={i} onClick={() => setSelected(i)} style={{
              display: "flex", flexDirection: "column", gap: 4, padding: "14px 16px",
              background: selected === i ? "var(--primary-soft-2)" : "transparent",
              border: 0, borderBottom: "1px solid var(--line-2)", cursor: "pointer", textAlign: "left", width: "100%",
            }}>
              <div className="row gap-8" style={{ width: "100%" }}>
                <span style={{ width: 6, height: 6, borderRadius: "50%", background: n.kind === "in" ? "var(--primary)" : "transparent", border: "1px solid " + (n.kind === "in" ? "var(--primary)" : "var(--line)") }}/>
                <span style={{ fontSize: 12.5, fontWeight: 500, flex: 1 }}>{n.subject}</span>
                <span className="ink-3" style={{ fontSize: 11 }}>{n.t}</span>
              </div>
              <span className="ink-3" style={{ fontSize: 12, paddingLeft: 14 }}>{n.preview}</span>
            </button>
          ))}
        </Card>
        <Card>
          <div className="col gap-12">
            <div className="row" style={{ justifyContent: "space-between" }}>
              <div className="col gap-2">
                <div style={{ fontSize: 15, fontWeight: 500 }}>{note.subject}</div>
                <div className="ink-3" style={{ fontSize: 12 }}>From the portal · {note.t}</div>
              </div>
              <div className="row gap-6">
                {note.clientId && <Button size="sm" icon={<Icon.external cls="ico-sm"/>} onClick={() => { setActiveClientId(note.clientId); toast("Opening client…"); }}>Open client</Button>}
                <Button size="sm" icon={<Icon.check cls="ico-sm"/>} onClick={markDone}>Mark done</Button>
              </div>
            </div>
            <div className="hr"/>
            <div style={{ fontSize: 13.5, lineHeight: 1.65, color: "var(--ink-2)" }}>
              {note.kind === "in" ? (
                <>
                  <p>{note.subject}.</p>
                  <p>This happened in <strong>{note.preview}</strong>'s onboarding portal. Open the client to see the documents, intake answers, and next steps.</p>
                </>
              ) : (
                <>
                  <p>The portal sent this on your behalf.</p>
                  <p><strong>{note.subject}</strong> — {note.preview}.</p>
                </>
              )}
            </div>
          </div>
        </Card>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Settings — Brand · Payments · Tax & Legal · Notifications
// ─────────────────────────────────────────────────────────────────────
function AdminSettings() {
  const [tab, setTab] = React.useState("payments");
  return (
    <div className="col" style={{ minHeight: "100vh" }}>
      <PageHeader eyebrow="Settings" title="Account & setup"
        sub="One-time setup. Configure your payment methods, legal defaults, and brand once — every client portal uses these settings automatically."/>
      <div style={{ padding: "0 36px", borderBottom: "1px solid var(--line)" }}>
        <div className="row gap-4" style={{ marginBottom: -1 }}>
          {[
            { id: "payments",   label: "Payments",       icon: Icon.card },
            { id: "signatures", label: "Signatures",     icon: Icon.signature },
            { id: "brand",      label: "Brand & profile", icon: Icon.briefcase },
            { id: "legal",      label: "Tax & legal",     icon: Icon.shield },
            { id: "notifs",     label: "Notifications",   icon: Icon.bell },
          ].map(t => {
            const Ico = t.icon;
            return (
              <button key={t.id} onClick={() => setTab(t.id)} className="row gap-6" style={{
                padding: "12px 14px", border: 0, background: "transparent",
                borderBottom: "2px solid " + (tab === t.id ? "var(--primary)" : "transparent"),
                color: tab === t.id ? "var(--ink)" : "var(--ink-3)", fontWeight: tab === t.id ? 500 : 400,
                fontSize: 13, cursor: "pointer",
              }}><Ico cls="ico-sm"/> {t.label}</button>
            );
          })}
        </div>
      </div>
      <div style={{ padding: "24px 36px 48px" }}>
        {tab === "payments"   && <SettingsPayments/>}
        {tab === "signatures" && <SettingsSignatures/>}
        {tab === "brand"      && <SettingsBrand/>}
        {tab === "legal"      && <SettingsLegal/>}
        {tab === "notifs"     && <SettingsNotifs/>}
      </div>
    </div>
  );
}

function SettingsPayments() {
  const { paymentProviders, updateProvider } = useApp();
  const { toast } = useToast();
  const [connecting, setConnecting] = React.useState(null);
  const connected = paymentProviders.filter(p => p.status === "connected");

  return (
    <div className="col gap-20">
      {/* Top explainer */}
      <Card>
        <div className="col gap-10">
          <div className="row gap-12" style={{ alignItems: "flex-start" }}>
            <div style={{ width: 38, height: 38, borderRadius: 10, background: "var(--primary-soft)", color: "var(--primary)", display: "grid", placeItems: "center", flexShrink: 0 }}>
              <Icon.lightning cls="ico"/>
            </div>
            <div className="col gap-4" style={{ flex: 1 }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>How invoices send themselves</div>
              <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.6, maxWidth: 720 }}>
                You connect each payment provider once here. From then on, every invoice the portal generates includes the right pay-now link, QR, or bank instructions — automatically, per client, in the right currency. <strong>No copy-pasting Stripe links into emails ever again.</strong>
              </div>
              <div className="row gap-6" style={{ marginTop: 6, padding: "6px 10px", background: "var(--surface-2)", border: "1px solid var(--line-2)", borderRadius: 6, alignSelf: "flex-start" }}>
                <Icon.shield cls="ico-sm" style={{ color: "var(--primary)" }}/>
                <span style={{ fontSize: 11.5 }}><strong>Your accounts, your money.</strong> Relay never touches funds or charges transaction fees — you connect your own Stripe / Wise / etc. and they pay you directly.</span>
              </div>
            </div>
          </div>
          <div className="hr"/>
          <div className="row gap-16" style={{ paddingTop: 4 }}>
            <ConnectedBadge n={connected.length} total={paymentProviders.length}/>
            <div className="ink-3" style={{ fontSize: 12 }}>· Currently active on invoices:</div>
            <div className="row gap-6" style={{ flexWrap: "wrap" }}>
              {connected.map(p => (
                <span key={p.id} className="badge" style={{ background: "var(--surface-2)", border: "1px solid var(--line)", color: "var(--ink-2)" }}>
                  <span style={{ width: 6, height: 6, borderRadius: "50%", background: p.color }}/>
                  {p.name}
                </span>
              ))}
            </div>
          </div>
        </div>
      </Card>

      {/* Recommendation banner */}
      <div className="row gap-10" style={{ padding: 14, background: "linear-gradient(to right, #F4E8DB, #FBF6EF)", border: "1px solid #E8D9C0", borderRadius: 10 }}>
        <div style={{ fontSize: 18 }}>🇵🇭</div>
        <div className="col" style={{ flex: 1, lineHeight: 1.4 }}>
          <div style={{ fontSize: 13, fontWeight: 500 }}>Based in the Philippines or working with PH-based clients?</div>
          <div className="ink-3" style={{ fontSize: 12 }}>Most OnlineJobs.ph freelancers connect <strong>Wise + Payoneer + GCash</strong>. Stripe and PayPal are global but charge higher fees.</div>
        </div>
        <Button size="sm" onClick={() => toast("Opening PH-freelancer payment guide…")}>Learn more</Button>
      </div>

      {/* Provider cards */}
      <div className="col gap-10">
        <div className="row" style={{ justifyContent: "space-between" }}>
          <div style={{ fontSize: 14, fontWeight: 500 }}>Payment providers</div>
          <span className="ink-3" style={{ fontSize: 12 }}>Connect as many as you want. Clients choose which method to use.</span>
        </div>
        {paymentProviders.map(p => (
          <ProviderCard key={p.id} provider={p}
            expanded={connecting === p.id}
            onToggle={() => setConnecting(connecting === p.id ? null : p.id)}
            onConnect={(account, extra) => { updateProvider(p.id, { status: "connected", account: account || p.linkFormat.split("•")[0] + "demo", ...extra }); setConnecting(null); }}
            onDisconnect={() => updateProvider(p.id, { status: "not_connected", account: null })}
            onTogglePortal={() => updateProvider(p.id, { portalEnabled: p.portalEnabled === false })}
          />
        ))}
      </div>

      {/* How it appears to clients */}
      <Card>
        <div className="col gap-12">
          <div className="row gap-8">
            <Icon.external cls="ico-sm"/>
            <div style={{ fontSize: 14, fontWeight: 500 }}>Preview: what your client sees on an invoice</div>
          </div>
          <div className="ink-3" style={{ fontSize: 12 }}>This is the live payment panel from your client portal. Only your connected methods show up — no manual links.</div>
          <div style={{ background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: 10, padding: 20 }}>
            <div className="col gap-12">
              <div className="row" style={{ justifyContent: "space-between" }}>
                <div className="col gap-2">
                  <span className="label-lc" style={{ fontSize: 11 }}>Pay now</span>
                  <span className="h-display" style={{ fontSize: 28 }}>$1,500.00</span>
                </div>
                <span className="badge pill-active">Secure</span>
              </div>
              <div className="col gap-6">
                {connected.map(p => (
                  <div key={p.id} className="row gap-10" style={{ padding: 11, background: "var(--surface)", border: "1px solid var(--line)", borderRadius: 8 }}>
                    <span style={{ width: 26, height: 18, borderRadius: 3, background: p.color, color: "#fff", display: "grid", placeItems: "center", fontSize: 8, fontWeight: 700 }}>{p.name.slice(0,3).toUpperCase()}</span>
                    <div className="col" style={{ flex: 1, lineHeight: 1.3 }}>
                      <span style={{ fontSize: 12.5, fontWeight: 500 }}>{p.name}</span>
                      <span className="ink-3" style={{ fontSize: 11.5 }}>{p.tagline}</span>
                    </div>
                    <span style={{ width: 14, height: 14, borderRadius: "50%", border: "1px solid var(--line)" }}/>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>
      </Card>
    </div>
  );
}

function ConnectedBadge({ n, total }) {
  return (
    <div className="row gap-6" style={{ padding: "4px 10px", background: "var(--primary-soft)", borderRadius: 999, fontSize: 11.5, fontWeight: 500, color: "var(--primary)" }}>
      <span style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--primary)" }}/>
      {n} of {total} connected
    </div>
  );
}

function ProviderCard({ provider, expanded, onToggle, onConnect, onDisconnect, onTogglePortal }) {
  const isConnected = provider.status === "connected";
  return (
    <Card pad={false}>
      <div className="row" style={{ padding: 16, gap: 14, alignItems: "center" }}>
        <div style={{ width: 40, height: 40, borderRadius: 8, background: provider.color, color: "#fff", display: "grid", placeItems: "center", fontWeight: 700, fontSize: 14, flexShrink: 0, letterSpacing: "-0.02em" }}>
          {provider.name.slice(0, 1)}
        </div>
        <div className="col" style={{ flex: 1, minWidth: 0, lineHeight: 1.3 }}>
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <span style={{ fontSize: 14, fontWeight: 500 }}>{provider.name}</span>
            {provider.badge && <span className="badge pill-active" style={{ fontSize: 10 }}>{provider.badge}</span>}
            {provider.popular_for && <span className="badge" style={{ background: "var(--surface-2)", color: "var(--ink-3)", fontSize: 10, border: "1px solid var(--line-2)" }}>Popular: {provider.popular_for}</span>}
          </div>
          <div className="ink-3" style={{ fontSize: 12, marginTop: 2 }}>{provider.tagline}</div>
          {isConnected && provider.account && (
            <div className="row gap-6" style={{ marginTop: 4, fontSize: 11.5 }}>
              <span style={{ color: "var(--success)" }}>● Connected</span>
              <span className="ink-3 mono">· {provider.account}</span>
            </div>
          )}
          {isConnected && (
            <label className="row gap-8" style={{ marginTop: 8, cursor: "pointer", alignItems: "center" }} onClick={e => e.stopPropagation()}>
              <Toggle on={provider.portalEnabled !== false} onClick={onTogglePortal}/>
              <span className="ink-3" style={{ fontSize: 11.5 }}>{provider.portalEnabled !== false ? "Shown to clients in the portal" : "Hidden from clients"}</span>
            </label>
          )}
          {isConnected && (
            <label className="row gap-8" style={{ marginTop: 8, cursor: "pointer", alignItems: "center" }}>
              <Toggle on={provider.portalEnabled !== false} onClick={onTogglePortal}/>
              <span className="ink-3" style={{ fontSize: 11.5 }}>{provider.portalEnabled !== false ? "Shown to clients in the portal" : "Hidden from clients"}</span>
            </label>
          )}
        </div>
        <div className="col" style={{ minWidth: 110, textAlign: "right", lineHeight: 1.3 }}>
          <span className="ink-3 mono" style={{ fontSize: 11 }}>FEES</span>
          <span style={{ fontSize: 12.5 }}>{provider.fees}</span>
        </div>
        <div className="col" style={{ minWidth: 130, textAlign: "right", lineHeight: 1.3 }}>
          <span className="ink-3 mono" style={{ fontSize: 11 }}>PAYOUT</span>
          <span style={{ fontSize: 12.5 }}>{provider.payout}</span>
        </div>
        <div className="row gap-6">
          {isConnected ? (
            <>
              <Button size="sm" icon={<Icon.settings cls="ico-sm"/>} onClick={onToggle}>Manage</Button>
              <Button size="sm" variant="ghost" onClick={onDisconnect}>Disconnect</Button>
            </>
          ) : (
            <Button size="sm" variant="primary" onClick={onToggle} iconR={<Icon.arrow cls="ico-sm"/>}>Connect</Button>
          )}
        </div>
      </div>

      {expanded && (
        <div className="fade-in" style={{ borderTop: "1px solid var(--line)", background: "var(--surface-2)", padding: 20 }}>
          <ConnectPanel provider={provider} onConnect={onConnect}/>
        </div>
      )}
    </Card>
  );
}

function ConnectPanel({ provider, onConnect }) {
  const [step, setStep] = React.useState("intro");

  // Stripe / PayPal: OAuth-style. Wise / Payoneer: API key + account. GCash: QR upload. Bank: form.
  // ── Stripe ──────────────────────────────────────────────────────────
  if (provider.id === "stripe") {
    const [payLink, setPayLink] = React.useState(provider.paymentUrl || "");
    return (
      <div className="col gap-14" style={{ maxWidth: 600 }}>
        <div className="col gap-6" style={{ padding: 14, background: "var(--primary-soft-2)", border: "1px solid var(--primary)", borderRadius: 10 }}>
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <Icon.lightning cls="ico-sm" style={{ color: "var(--primary)" }}/>
            <span style={{ fontSize: 13, fontWeight: 500 }}>No backend required — use a Stripe Payment Link</span>
          </div>
          <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.65 }}>
            Create a <strong>Payment Link</strong> in your Stripe Dashboard (Stripe → Payment Links → Create). Set the price type to <strong>"Customer chooses price"</strong> so any invoice amount works. Paste the URL below — every invoice will open it with the amount pre-described.
          </div>
          <div className="row gap-8" style={{ flexWrap: "wrap" }}>
            <a href="https://dashboard.stripe.com/payment-links/create" target="_blank" rel="noreferrer"
              className="btn btn-sm" style={{ color: "var(--primary)", borderColor: "var(--primary)" }}>
              <Icon.external cls="ico-sm"/> Open Stripe Dashboard
            </a>
            <a href="https://dashboard.stripe.com/apikeys" target="_blank" rel="noreferrer"
              className="btn btn-sm btn-ghost">
              View API keys →
            </a>
          </div>
        </div>

        <Field label="Your Stripe Payment Link URL">
          <input className="input" value={payLink} onChange={e => setPayLink(e.target.value)}
            placeholder="https://buy.stripe.com/your_link_here"
            style={{ fontFamily: "Geist Mono, monospace", fontSize: 12.5 }}/>
        </Field>
        <div className="ink-3" style={{ fontSize: 11.5, lineHeight: 1.55 }}>
          This link will open when clients click "Pay via Stripe" on the invoice. Stripe handles the card form, receipt email, and payment confirmation.
        </div>

        <div className="col gap-4" style={{ padding: 12, background: "var(--surface-2)", borderRadius: 8, border: "1px solid var(--line-2)", fontSize: 12 }}>
          <span className="label" style={{ fontSize: 10 }}>What Stripe handles automatically</span>
          <div className="col gap-4" style={{ color: "var(--ink-2)" }}>
            <span><Icon.check cls="ico-sm" style={{ color: "var(--success)", verticalAlign: "middle" }}/> Card, Apple Pay, Google Pay, Link</span>
            <span><Icon.check cls="ico-sm" style={{ color: "var(--success)", verticalAlign: "middle" }}/> Receipt email to client</span>
            <span><Icon.check cls="ico-sm" style={{ color: "var(--success)", verticalAlign: "middle" }}/> 256-bit TLS · PCI DSS compliant</span>
            <span style={{ color: "var(--ink-3)" }}>✗ Auto mark-as-paid in portal (needs backend — mark manually for now)</span>
          </div>
        </div>

        <Button variant="primary" icon={<Icon.check cls="ico-sm"/>}
          disabled={!payLink.startsWith("http")}
          onClick={() => onConnect(payLink, { paymentUrl: payLink })}
          style={{ alignSelf: "flex-start" }}>
          Save Stripe link
        </Button>
      </div>
    );
  }

  // ── PayPal ──────────────────────────────────────────────────────────
  if (provider.id === "paypal") {
    const [clientId, setClientId] = React.useState(provider.clientId || "");
    const [username, setUsername] = React.useState(
      provider.paymentUrl ? provider.paymentUrl.replace("paypal.me/", "") : ""
    );
    const [mode, setMode] = React.useState(provider.clientId ? "smart" : "link");

    return (
      <div className="col gap-14" style={{ maxWidth: 620 }}>

        {/* Mode picker */}
        <div className="col gap-4">
          <div className="label" style={{ fontSize: 10.5 }}>Choose how PayPal connects</div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
            {[
              { id: "smart", title: "Smart Buttons", sub: "Embedded — client pays without leaving your portal. Best experience.", badge: "Recommended", bg: "#EEF4FF", border: "#2C4D8A" },
              { id: "link",  title: "PayPal.me link", sub: "Opens PayPal in a popup. Simpler setup, slightly more friction.", badge: "Fallback", bg: "var(--surface-2)", border: "var(--line)" },
            ].map(opt => (
              <button key={opt.id} onClick={() => setMode(opt.id)} style={{
                padding: 14, borderRadius: 10, textAlign: "left", cursor: "pointer",
                background: mode === opt.id ? opt.bg : "var(--surface)",
                border: "2px solid " + (mode === opt.id ? opt.border : "var(--line)"),
              }}>
                <div className="col gap-4">
                  <div className="row gap-6" style={{ alignItems: "center" }}>
                    <span style={{ fontSize: 13, fontWeight: 600 }}>{opt.title}</span>
                    <span className="badge" style={{ fontSize: 10, background: mode === opt.id ? "rgba(44,77,138,0.12)" : "var(--bg-2)", color: mode === opt.id ? "#2C4D8A" : "var(--ink-3)" }}>{opt.badge}</span>
                  </div>
                  <span className="ink-3" style={{ fontSize: 11.5, lineHeight: 1.45 }}>{opt.sub}</span>
                </div>
              </button>
            ))}
          </div>
        </div>

        {mode === "smart" && (
          <>
            <div className="col gap-6" style={{ padding: 14, background: "#EEF4FF", border: "1px solid #C0D0F0", borderRadius: 10 }}>
              <div className="row gap-8" style={{ alignItems: "center" }}>
                <Icon.lightning cls="ico-sm" style={{ color: "#003087" }}/>
                <span style={{ fontSize: 13, fontWeight: 500 }}>PayPal Smart Buttons — fully embedded, zero backend</span>
              </div>
              <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.65 }}>
                The PayPal payment form appears <strong>directly inside your client portal</strong>. Client pays with card, PayPal balance, or any PayPal-supported method — without leaving your page. All you need is a free PayPal Developer Client ID.
              </div>
              <div className="row gap-6" style={{ flexWrap: "wrap" }}>
                <a href="https://developer.paypal.com/dashboard/applications" target="_blank" rel="noreferrer"
                  className="btn btn-sm" style={{ color: "#003087", borderColor: "#003087" }}>
                  <Icon.external cls="ico-sm"/> Open PayPal Developer Dashboard
                </a>
                <a href="https://developer.paypal.com/dashboard/applications/live" target="_blank" rel="noreferrer"
                  className="btn btn-sm btn-ghost">Get Client ID →</a>
              </div>
            </div>

            <div className="col gap-6" style={{ padding: 12, background: "var(--surface-2)", border: "1px solid var(--line)", borderRadius: 8, fontSize: 12.5, lineHeight: 1.6 }}>
              <div style={{ fontWeight: 500 }}>How to get your Client ID (2 minutes):</div>
              <ol style={{ margin: 0, paddingLeft: 18, color: "var(--ink-2)" }}>
                <li>Go to <strong>developer.paypal.com</strong> → log in</li>
                <li>Click <strong>Apps & Credentials</strong> → switch to <strong>Live</strong> tab</li>
                <li>Click <strong>Create App</strong> → name it "Relay" → Create</li>
                <li>Copy the <strong>Client ID</strong> (starts with <span className="mono">AaBb...</span> or similar)</li>
              </ol>
            </div>

            <Field label="PayPal Client ID (Live)">
              <input className="input" value={clientId} onChange={e => setClientId(e.target.value.trim())}
                placeholder="AaBbCcDd-EeFfGgHh..."
                style={{ fontFamily: "Geist Mono, monospace", fontSize: 12.5 }}/>
              {clientId && clientId.length > 10 && (
                <div className="row gap-6" style={{ marginTop: 6, fontSize: 12, color: "var(--success)" }}>
                  <span style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--success)" }}/>
                  Client ID looks valid — PayPal Smart Buttons will load on invoices
                </div>
              )}
            </Field>

            <div className="col gap-4" style={{ padding: 12, background: "var(--surface-2)", borderRadius: 8, border: "1px solid var(--line-2)", fontSize: 12 }}>
              <span className="label" style={{ fontSize: 10 }}>What this enables</span>
              <div className="col gap-4" style={{ color: "var(--ink-2)" }}>
                <span>✅ PayPal button renders inside your portal — no redirect</span>
                <span>✅ Card, PayPal balance, Pay Later, Venmo (US)</span>
                <span>✅ Instant receipt to client's email</span>
                <span>✅ Payment auto-confirmed — portal advances immediately</span>
                <span>✅ Zero backend required</span>
              </div>
            </div>

            <Button variant="primary" icon={<Icon.check cls="ico-sm"/>}
              disabled={!clientId || clientId.length < 10}
              onClick={() => onConnect(clientId, { clientId, mode: "smart" })}
              style={{ alignSelf: "flex-start" }}>
              Save & enable Smart Buttons
            </Button>
          </>
        )}

        {mode === "link" && (
          <>
            <Field label="Your PayPal.me username">
              <div style={{ position: "relative" }}>
                <span className="mono" style={{ position: "absolute", left: 12, top: 9, color: "var(--muted)", fontSize: 13 }}>paypal.me/</span>
                <input className="input" value={username} onChange={e => setUsername(e.target.value.replace(/\s/g, ""))}
                  placeholder="yourname"
                  style={{ paddingLeft: 96, fontFamily: "Geist Mono, monospace", fontSize: 13 }}/>
              </div>
              {username && (
                <div className="row gap-6" style={{ marginTop: 6, fontSize: 12, color: "var(--ink-3)" }}>
                  Preview: <span className="mono" style={{ color: "var(--primary)" }}>paypal.me/{username}/1500</span> ← opens as popup
                </div>
              )}
            </Field>
            <Button variant="primary" icon={<Icon.check cls="ico-sm"/>}
              disabled={!username.trim()}
              onClick={() => onConnect("paypal.me/" + username.trim(), { paymentUrl: "paypal.me/" + username.trim(), mode: "link" })}
              style={{ alignSelf: "flex-start" }}>
              Save PayPal.me link
            </Button>
          </>
        )}
      </div>
    );
  }

  if (provider.id === "wise") {
    return (
      <div className="col gap-14" style={{ maxWidth: 560 }}>
        <div className="col gap-4">
          <div style={{ fontSize: 13.5, fontWeight: 500 }}>Connect Wise Business</div>
          <div className="ink-3" style={{ fontSize: 12, lineHeight: 1.55 }}>
            Wise generates a per-invoice payment request with the amount and reference pre-filled. Your client picks any bank, currency converts at the mid-market rate. <strong>The link looks like: <span className="mono" style={{ color: "var(--ink)" }}>wise.com/pay/business/yourname</span></strong>
          </div>
        </div>
        <div className="col gap-10">
          <Field label="Wise business profile URL"><input className="input" placeholder="https://wise.com/pay/business/yourname"/></Field>
          <Field label="API token (from Wise → Integrations)"><input className="input" placeholder="••••••••••••" type="password"/></Field>
          <Field label="Default receiving currency">
            <select className="input" defaultValue="USD">
              <option>USD — US Dollar</option><option>PHP — Philippine Peso</option><option>EUR — Euro</option><option>GBP — British Pound</option>
            </select>
          </Field>
        </div>
        <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={() => onConnect("wise.com/pay/business/alex-mira")} style={{ alignSelf: "flex-start" }}>
          Connect Wise
        </Button>
      </div>
    );
  }

  if (provider.id === "payoneer") {
    return (
      <div className="col gap-14" style={{ maxWidth: 560 }}>
        <div className="col gap-4">
          <div style={{ fontSize: 13.5, fontWeight: 500 }}>Connect Payoneer</div>
          <div className="ink-3" style={{ fontSize: 12, lineHeight: 1.55 }}>
            Each invoice sends a Payoneer payment request — your client receives an email with one-click pay options. Funds land in your Payoneer balance, then transfer to your local bank.
          </div>
        </div>
        <div className="col gap-10">
          <Field label="Payoneer account email"><input className="input" placeholder="you@example.com"/></Field>
          <Field label="Payoneer customer ID"><input className="input" placeholder="48029384"/></Field>
        </div>
        <div className="row gap-8" style={{ padding: 10, background: "#FFF4E5", border: "1px solid #F4D9A8", borderRadius: 8, fontSize: 12 }}>
          <Icon.shield cls="ico-sm" style={{ color: "#8A5E2C" }}/>
          <span>Payoneer takes up to 3% on intl card payments — show this to clients in the invoice description.</span>
        </div>
        <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={() => onConnect("alex@relayhq.studio · ID 48029384")} style={{ alignSelf: "flex-start" }}>
          Connect Payoneer
        </Button>
      </div>
    );
  }

  if (provider.id === "gcash") {
    return (
      <div className="col gap-14" style={{ maxWidth: 560 }}>
        <div className="col gap-4">
          <div style={{ fontSize: 13.5, fontWeight: 500 }}>Set up GCash</div>
          <div className="ink-3" style={{ fontSize: 12, lineHeight: 1.55 }}>
            GCash doesn't have a public payment API — instead we'll show your <strong>QR code + reference number</strong> on the invoice. Client pays in the GCash app and uploads the receipt. You manually mark as paid.
          </div>
        </div>
        <div className="col gap-10">
          <Field label="GCash mobile number"><input className="input" placeholder="+63 9•• ••• ••••"/></Field>
          <Field label="Registered account name"><input className="input" placeholder="As shown in your GCash app"/></Field>
          <Field label="Your GCash QR code">
            <div style={{ padding: 16, border: "1px dashed var(--line)", borderRadius: 8, background: "var(--surface)", textAlign: "center" }}>
              <Icon.upload cls="ico-lg" style={{ color: "var(--muted)" }}/>
              <div style={{ fontSize: 12, marginTop: 6 }}>Drop or <span style={{ color: "var(--primary)", textDecoration: "underline" }}>browse</span> your QR PNG</div>
            </div>
          </Field>
        </div>
        <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={() => onConnect("+63 917 ••• 4421 · QR uploaded")} style={{ alignSelf: "flex-start" }}>
          Save GCash setup
        </Button>
      </div>
    );
  }

  // Bank
  return (
    <div className="col gap-14" style={{ maxWidth: 560 }}>
      <div className="col gap-4">
        <div style={{ fontSize: 13.5, fontWeight: 500 }}>Bank transfer instructions</div>
        <div className="ink-3" style={{ fontSize: 12 }}>This text appears on every invoice. Client wires money, you manually mark as paid when it lands.</div>
      </div>
      <div className="col gap-10">
        <Field label="Account name"><input className="input" defaultValue="Alex Mira"/></Field>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          <Field label="Bank name"><input className="input" defaultValue="First Bank"/></Field>
          <Field label="Account number"><input className="input" defaultValue="•••• 4421"/></Field>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          <Field label="Routing / SWIFT"><input className="input" defaultValue="121000358"/></Field>
          <Field label="Country"><input className="input" defaultValue="United States"/></Field>
        </div>
      </div>
      <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={() => onConnect("First Bank ••••4421")} style={{ alignSelf: "flex-start" }}>
        Save bank details
      </Button>
    </div>
  );
}

function SettingsSignatures() {
  const { signatureProviders, updateSignatureProvider } = useApp();
  const { toast } = useToast();
  const [connecting, setConnecting] = React.useState(null);
  const active = signatureProviders.filter(p => p.status === "connected");
  const native = signatureProviders.find(p => p.id === "native");

  return (
    <div className="col gap-20">
      {/* Top explainer */}
      <Card>
        <div className="col gap-10">
          <div className="row gap-12" style={{ alignItems: "flex-start" }}>
            <div style={{ width: 38, height: 38, borderRadius: 10, background: "var(--primary-soft)", color: "var(--primary)", display: "grid", placeItems: "center", flexShrink: 0 }}>
              <Icon.signature cls="ico"/>
            </div>
            <div className="col gap-4" style={{ flex: 1 }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>Native e-sign is on by default — and that's usually all you need</div>
              <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.65 }}>
                A typed signature + IP + timestamp + tamper-evident PDF is <strong>legally binding under the US ESIGN Act, UETA, and EU eIDAS</strong> for routine business contracts. It's what Bonsai, HoneyBook, and Dubsado use. Connect DocuSign, Dropbox Sign, or PandaDoc only if an enterprise client requires it or you work in a regulated industry (healthcare, finance, real estate).
              </div>
              <div className="row gap-6" style={{ marginTop: 6, padding: "6px 10px", background: "var(--surface-2)", border: "1px solid var(--line-2)", borderRadius: 6, alignSelf: "flex-start" }}>
                <Icon.shield cls="ico-sm" style={{ color: "var(--primary)" }}/>
                <span style={{ fontSize: 11.5 }}><strong>Bring your own subscription.</strong> When you connect DocuSign / PandaDoc / Adobe, you log into your own account and pay them directly. Relay just handles the OAuth.</span>
              </div>
            </div>
          </div>
          <div className="hr"/>
          <div className="row gap-16" style={{ paddingTop: 4 }}>
            <ConnectedBadge n={active.length} total={signatureProviders.length}/>
            <div className="ink-3" style={{ fontSize: 12 }}>· Available on contracts:</div>
            <div className="row gap-6" style={{ flexWrap: "wrap" }}>
              {active.map(p => (
                <span key={p.id} className="badge" style={{ background: "var(--surface-2)", border: "1px solid var(--line)", color: "var(--ink-2)" }}>
                  <span style={{ width: 6, height: 6, borderRadius: "50%", background: p.color }}/>
                  {p.name}{p.isDefault && " (default)"}
                </span>
              ))}
            </div>
          </div>
        </div>
      </Card>

      {/* Native — featured callout */}
      <Card>
        <div className="row gap-14" style={{ alignItems: "flex-start" }}>
          <div style={{ width: 44, height: 44, borderRadius: 10, background: native.color, color: "#fff", display: "grid", placeItems: "center", flexShrink: 0 }}>
            <Icon.check cls="ico"/>
          </div>
          <div className="col gap-8" style={{ flex: 1 }}>
            <div className="row gap-8" style={{ alignItems: "center" }}>
              <span style={{ fontSize: 14, fontWeight: 500 }}>{native.name}</span>
              <span className="badge pill-active" style={{ fontSize: 10 }}>Default · always on</span>
              <span className="badge" style={{ background: "var(--bg-2)", color: "var(--ink-3)", fontSize: 10 }}>{native.cost}</span>
              <span className="ink-3" style={{ fontSize: 11, marginLeft: "auto" }}>{native.legal}</span>
            </div>
            <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.55 }}>{native.tagline} · {native.region}</div>
            <div className="hr" style={{ margin: "4px 0" }}/>
            <div className="col gap-4">
              <span className="label" style={{ fontSize: 10.5 }}>What we capture on every signature</span>
              <div className="row gap-6" style={{ flexWrap: "wrap" }}>
                {native.captures.map(c => (
                  <span key={c} className="badge" style={{ background: "var(--surface-2)", color: "var(--ink-2)", border: "1px solid var(--line-2)", fontSize: 11 }}>
                    <Icon.check cls="ico-sm" style={{ width: 10, height: 10, color: "var(--primary)" }}/>
                    {c}
                  </span>
                ))}
              </div>
            </div>
            <div className="ink-3" style={{ fontSize: 11.5, lineHeight: 1.5, padding: 10, background: "var(--surface-2)", borderRadius: 8, border: "1px solid var(--line-2)" }}>
              <strong style={{ color: "var(--ink-2)" }}>When to use external instead:</strong> {native.note}
            </div>
          </div>
        </div>
      </Card>

      {/* External providers */}
      <div className="col gap-10">
        <div className="row" style={{ justifyContent: "space-between" }}>
          <div style={{ fontSize: 14, fontWeight: 500 }}>External providers</div>
          <span className="ink-3" style={{ fontSize: 12 }}>Connect any that your clients require. Per-document override available.</span>
        </div>
        {signatureProviders.filter(p => p.id !== "native").map(p => (
          <SignatureProviderCard key={p.id} provider={p}
            expanded={connecting === p.id}
            onToggle={() => setConnecting(connecting === p.id ? null : p.id)}
            onConnect={(account) => { updateSignatureProvider(p.id, { status: "connected", account: account || "demo-account" }); setConnecting(null); }}
            onDisconnect={() => updateSignatureProvider(p.id, { status: "not_connected", account: null })}
          />
        ))}
      </div>

      {/* Decision helper */}
      <Card>
        <div className="col gap-10">
          <div style={{ fontSize: 14, fontWeight: 500 }}>Which one should you connect?</div>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 10, marginTop: 4 }}>
            <DecisionCard
              when="Solo freelancer · normal clients"
              recommendation="Just use native"
              detail="Free, fast, in-portal. ESIGN-compliant. You're covered."
              color="var(--primary)"
            />
            <DecisionCard
              when="Enterprise client requires DocuSign"
              recommendation="Connect DocuSign"
              detail="Per-doc override sends just that contract through DocuSign while everything else stays native."
              color="#FFCC22"
            />
            <DecisionCard
              when="Regulated industry (health, finance)"
              recommendation="DocuSign or Adobe Sign"
              detail="Need KBA identity verification or 21 CFR Part 11. Native won't satisfy auditors."
              color="#FA0F00"
            />
          </div>
        </div>
      </Card>
    </div>
  );
}

function SignatureProviderCard({ provider, expanded, onToggle, onConnect, onDisconnect }) {
  const isConnected = provider.status === "connected";
  return (
    <Card pad={false}>
      <div className="row" style={{ padding: 16, gap: 14, alignItems: "center" }}>
        <div style={{ width: 40, height: 40, borderRadius: 8, background: provider.color, color: "#fff", display: "grid", placeItems: "center", fontWeight: 700, fontSize: 14, flexShrink: 0, letterSpacing: "-0.02em" }}>
          {provider.name.slice(0, 1)}
        </div>
        <div className="col" style={{ flex: 1, minWidth: 0, lineHeight: 1.3 }}>
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <span style={{ fontSize: 14, fontWeight: 500 }}>{provider.name}</span>
            {provider.popular_for && <span className="badge" style={{ background: "var(--surface-2)", color: "var(--ink-3)", fontSize: 10, border: "1px solid var(--line-2)" }}>Popular: {provider.popular_for}</span>}
          </div>
          <div className="ink-3" style={{ fontSize: 12, marginTop: 2 }}>{provider.tagline}</div>
          {isConnected && (
            <div className="row gap-6" style={{ marginTop: 4, fontSize: 11.5 }}>
              <span style={{ color: "var(--success)" }}>● Connected</span>
              <span className="ink-3 mono">· {provider.account || "live"}</span>
            </div>
          )}
        </div>
        <div className="col" style={{ minWidth: 130, textAlign: "right", lineHeight: 1.3 }}>
          <span className="ink-3 mono" style={{ fontSize: 11 }}>COST</span>
          <span style={{ fontSize: 12.5 }}>{provider.cost}</span>
        </div>
        <div className="col" style={{ minWidth: 160, textAlign: "right", lineHeight: 1.3 }}>
          <span className="ink-3 mono" style={{ fontSize: 11 }}>LEGAL FRAMEWORK</span>
          <span style={{ fontSize: 11.5 }}>{provider.legal}</span>
        </div>
        <div className="row gap-6">
          {isConnected ? (
            <>
              <Button size="sm" icon={<Icon.settings cls="ico-sm"/>} onClick={onToggle}>Manage</Button>
              <Button size="sm" variant="ghost" onClick={onDisconnect}>Disconnect</Button>
            </>
          ) : (
            <Button size="sm" variant="primary" onClick={onToggle} iconR={<Icon.arrow cls="ico-sm"/>}>Connect</Button>
          )}
        </div>
      </div>

      {expanded && (
        <div className="fade-in" style={{ borderTop: "1px solid var(--line)", background: "var(--surface-2)", padding: 20 }}>
          <div className="col gap-14" style={{ maxWidth: 560 }}>
            <div className="col gap-4">
              <div style={{ fontSize: 13.5, fontWeight: 500 }}>Connect {provider.name} via OAuth</div>
              <div className="ink-3" style={{ fontSize: 12, lineHeight: 1.55 }}>{provider.note}</div>
            </div>
            <div className="col gap-6" style={{ padding: 12, background: "var(--surface)", borderRadius: 8, border: "1px solid var(--line)" }}>
              <span className="label" style={{ fontSize: 10.5 }}>What you'll get over native</span>
              <ul style={{ margin: 0, paddingLeft: 18, fontSize: 12.5, lineHeight: 1.65, color: "var(--ink-2)" }}>
                {provider.captures.map(c => <li key={c}>{c}</li>)}
              </ul>
            </div>
            <div className="row gap-8">
              <Button variant="primary" icon={<Icon.external cls="ico-sm"/>} onClick={() => onConnect(`${provider.id}@relayhq.studio`)}>
                Continue to {provider.name}
              </Button>
              <Button variant="ghost" onClick={onToggle}>Cancel</Button>
            </div>
          </div>
        </div>
      )}
    </Card>
  );
}

function DecisionCard({ when, recommendation, detail, color }) {
  return (
    <div style={{ padding: 14, background: "var(--surface-2)", borderRadius: 10, border: "1px solid var(--line-2)" }}>
      <div className="col gap-6">
        <div className="row gap-6">
          <span style={{ width: 6, height: 6, borderRadius: "50%", background: color, marginTop: 6 }}/>
          <div className="ink-3" style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: 0.04, fontWeight: 500 }}>If…</div>
        </div>
        <div style={{ fontSize: 13, fontWeight: 500 }}>{when}</div>
        <div style={{ fontSize: 12.5, color: "var(--primary)", fontWeight: 500 }}>→ {recommendation}</div>
        <div className="ink-3" style={{ fontSize: 11.5, lineHeight: 1.5 }}>{detail}</div>
      </div>
    </div>
  );
}

function ClientCodeTool() {
  const { copyToClipboard, toast } = useToast();
  const [code, setCode] = React.useState("");
  const [line, setLine] = React.useState("");
  const gen = async () => {
    if (!code.trim()) { toast("Type a code first", { kind: "warn" }); return; }
    if (!window.sha256Hex) { toast("Hasher not ready — refresh and retry", { kind: "warn" }); return; }
    const h = await window.sha256Hex(code.trim().toLowerCase());
    setLine(`window.RELAY_CONFIG.clientAccessCodeHash = "${h}";`);
  };
  return (
    <Card>
      <div className="col gap-12">
        <div className="row gap-8" style={{ alignItems: "center" }}>
          <Icon.shield cls="ico-sm" style={{ color: "var(--primary)" }}/>
          <div style={{ fontSize: 14, fontWeight: 500 }}>Client access code</div>
        </div>
        <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.55 }}>
          Clients type this code to open their portal on the live site. Type a new code below, copy the generated line, paste it into <span className="mono">config.public.js</span>, then redeploy. Current default code is <span className="mono">trendvibe2026</span>.
        </div>
        <div className="row gap-8">
          <input className="input" value={code} onChange={e => setCode(e.target.value)} placeholder="New access code (e.g. welcome2026)"/>
          <Button variant="primary" icon={<Icon.refresh cls="ico-sm"/>} onClick={gen}>Generate</Button>
        </div>
        {line && (
          <div className="col gap-6 fade-in">
            <span className="label" style={{ fontSize: 10.5 }}>Paste this line into config.public.js</span>
            <div className="row gap-8" style={{ alignItems: "center" }}>
              <code className="mono" style={{ flex: 1, fontSize: 11, background: "var(--surface-2)", padding: "8px 10px", borderRadius: 6, border: "1px solid var(--line-2)", wordBreak: "break-all" }}>{line}</code>
              <Button size="sm" icon={<Icon.copy cls="ico-sm"/>} onClick={() => copyToClipboard(line, "Config line copied")}>Copy</Button>
            </div>
            <span className="ink-3" style={{ fontSize: 11.5 }}>Then run <span className="mono">firebase deploy --only hosting</span> and give clients the new code: <strong>{code.trim().toLowerCase()}</strong></span>
          </div>
        )}
      </div>
    </Card>
  );
}

function SettingsBrand() {
  const { freelancer, saveProfile } = useApp();
  const { toast } = useToast();
  const [name, setName] = React.useState(freelancer.name);
  const [title, setTitle] = React.useState(freelancer.title);
  const [brand, setBrand] = React.useState(freelancer.brand);
  const [email, setEmail] = React.useState(freelancer.email);

  const save = () => {
    // Save the profile to the synced store → Firestore → every device, including
    // the client portal. Also mirror to local tweaks for offline/first-paint.
    saveProfile({ name: name.trim(), title: title.trim(), brand: brand.trim(), email: email.trim() });
    try {
      const saved = JSON.parse(localStorage.getItem("relay_v1_tweaks") || "{}");
      localStorage.setItem("relay_v1_tweaks", JSON.stringify({
        ...saved, freelancerName: name, freelancerTitle: title, brandName: brand, freelancerEmail: email,
      }));
    } catch {}
    window.dispatchEvent(new CustomEvent("tweakchange", { detail: { freelancerName: name, freelancerTitle: title, brandName: brand, freelancerEmail: email } }));
    toast("Profile saved — applied everywhere, including client portals", { kind: "success" });
  };

  return (
    <div className="col gap-16">
      <Card>
        <div className="col gap-14">
          <div className="row gap-12">
            <LogoMark size={48} color={freelancer.accent}/>
            <div className="col">
              <div style={{ fontSize: 15, fontWeight: 500 }}>{brand}</div>
              <div className="ink-3" style={{ fontSize: 12.5 }}>{title}</div>
            </div>
          </div>
          <div className="hr"/>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
            <Field label="Your full name"><input className="input" value={name} onChange={e => setName(e.target.value)}/></Field>
            <Field label="Your title"><input className="input" value={title} onChange={e => setTitle(e.target.value)}/></Field>
            <Field label="Brand / business name"><input className="input" value={brand} onChange={e => setBrand(e.target.value)}/></Field>
            <Field label="Contact email"><input className="input" type="email" value={email} onChange={e => setEmail(e.target.value)}/></Field>
          </div>
          <div className="ink-3" style={{ fontSize: 12, lineHeight: 1.55 }}>
            Accent color and currency are in the <strong>Tweaks panel</strong> (bottom-right corner).
          </div>
          <div className="row gap-8">
            <Button variant="primary" icon={<Icon.check cls="ico-sm"/>} onClick={save}>Save profile</Button>
          </div>
        </div>
      </Card>
      <Card>
        <div className="col gap-10">
          <div className="row gap-8" style={{ alignItems: "center" }}>
            <Icon.trash cls="ico-sm" style={{ color: "var(--danger)" }}/>
            <div style={{ fontSize: 13.5, fontWeight: 500 }}>Reset to demo data</div>
          </div>
          <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.55 }}>
            Clears all saved client data and settings — brings back the sample clients (Veltrix AI, Brightline Studio, etc.). Use this to restart fresh or test the onboarding flow again.
          </div>
          <Button icon={<Icon.refresh cls="ico-sm"/>} onClick={() => {
            if (!confirm("This will delete all your saved client data and reset to demo mode. Continue?")) return;
            lsClear();
            window.location.reload();
          }} style={{ alignSelf: "flex-start", color: "var(--danger)", borderColor: "var(--danger-soft)" }}>
            Reset to demo data
          </Button>
        </div>
      </Card>
    </div>
  );
}

function SettingsLegal() {
  const { template } = useApp();
  return (
    <Card>
      <div className="col gap-10">
        <div style={{ fontSize: 14, fontWeight: 500 }}>Legal defaults</div>
        <div className="ink-3" style={{ fontSize: 12.5 }}>
          Jurisdiction, attorney-reviewed clauses, and audit logs live in <strong>Templates → Legal & compliance</strong>. Currently set to: <span className="mono" style={{ color: "var(--ink)" }}>{template.jurisdiction}</span>.
        </div>
      </div>
    </Card>
  );
}

function SettingsNotifs() {
  const { freelancer } = useApp();
  const { toast } = useToast();
  const [cfg, setCfg] = React.useState(loadBrevoConfig);
  const [testing, setTesting] = React.useState(false);
  const [testEmail, setTestEmail] = React.useState("");

  const update = (patch) => { const next = { ...cfg, ...patch }; setCfg(next); saveBrevoConfig(next); };
  const updateReminders = (patch) => update({ reminders: { ...cfg.reminders, ...patch } });
  const connected = (cfg.apiKey || cfg.proxyUrl) && cfg.senderEmail;

  const sendTest = async () => {
    if ((!cfg.apiKey && !cfg.proxyUrl) || !cfg.senderEmail) { toast("Enter your sender email first", { kind: "warn" }); return; }
    const target = testEmail || cfg.senderEmail;
    setTesting(true);
    try {
      const { subject, html } = buildReminderEmail({
        client: { contact: "Test Client", company: "Test Co." },
        freelancer, amount: 1500, currencyCode: freelancer.currency,
        dueDate: daysAhead(3), invoiceNo: "INV-TEST-001", payLink: "https://example.com/pay", kind: "before",
      });
      await sendBrevoEmail({
        apiKey: cfg.apiKey, senderName: cfg.senderName || freelancer.brand, senderEmail: cfg.senderEmail,
        toEmail: target, toName: "Test", subject: "[TEST] " + subject, htmlContent: html,
      });
      toast(`Test reminder sent to ${target} — check your inbox`, { kind: "success" });
    } catch (e) {
      const msg = String(e.message || e);
      if (msg.includes("Failed to fetch") || msg.includes("CORS") || msg.includes("NetworkError")) {
        toast("Browser blocked the request (CORS). Brevo needs a tiny proxy — see the note below.", { kind: "danger", duration: 5000 });
      } else {
        toast(msg, { kind: "danger", duration: 5000 });
      }
    } finally { setTesting(false); }
  };

  return (
    <div className="col gap-20">
      {/* Brevo connection */}
      <Card>
        <div className="col gap-14">
          <div className="row gap-12" style={{ alignItems: "flex-start" }}>
            <div style={{ width: 38, height: 38, borderRadius: 10, background: "#0B996E", color: "#fff", display: "grid", placeItems: "center", flexShrink: 0, fontWeight: 700 }}>B</div>
            <div className="col gap-4" style={{ flex: 1 }}>
              <div className="row gap-8" style={{ alignItems: "center" }}>
                <span style={{ fontSize: 14, fontWeight: 500 }}>Brevo email</span>
                {connected
                  ? <span className="badge pill-active" style={{ fontSize: 10 }}>● Connected</span>
                  : <span className="badge" style={{ fontSize: 10, background: "var(--bg-2)", color: "var(--ink-3)" }}>Not connected</span>}
              </div>
              <div className="ink-3" style={{ fontSize: 12.5, lineHeight: 1.6 }}>
                Connect Brevo to send invoice reminders, welcome emails, and nudges automatically. Get your API key from <strong>Brevo → SMTP & API → API Keys</strong>.
              </div>
              <a href="https://app.brevo.com/settings/keys/api" target="_blank" rel="noreferrer" className="btn btn-sm" style={{ alignSelf: "flex-start", color: "#0B996E", borderColor: "#0B996E" }}>
                <Icon.external cls="ico-sm"/> Get Brevo API key
              </a>
            </div>
          </div>
          <div className="hr"/>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }}>
            <div style={{ gridColumn: "1 / -1" }}>
              <Field label="Brevo API key (starts with xkeysib-)">
                <input className="input" type="password" value={cfg.apiKey} onChange={e => update({ apiKey: e.target.value.trim() })}
                  placeholder="xkeysib-••••••••••••••••" style={{ fontFamily: "Geist Mono, monospace", fontSize: 12.5 }}/>
                {cfg.proxyUrl && !cfg.apiKey && (
                  <div style={{ fontSize: 11.5, color: "var(--primary)", marginTop: 5 }}>
                    ✓ Key stored server-side — emails route through the secure Cloud Function, no key needed here
                  </div>
                )}
              </Field>
            </div>
            <Field label="Sender name"><input className="input" value={cfg.senderName} onChange={e => update({ senderName: e.target.value })} placeholder={freelancer.name}/></Field>
            <Field label="Sender email (must be verified in Brevo)"><input className="input" type="email" value={cfg.senderEmail} onChange={e => update({ senderEmail: e.target.value.trim() })} placeholder="you@yourdomain.com"/></Field>
          </div>
          <div className="hr"/>
          <div className="row gap-8" style={{ alignItems: "flex-end", flexWrap: "wrap" }}>
            <div className="col gap-4" style={{ flex: 1, minWidth: 220 }}>
              <span className="label-lc" style={{ fontSize: 12 }}>Send a test reminder to</span>
              <input className="input" type="email" value={testEmail} onChange={e => setTestEmail(e.target.value.trim())} placeholder={cfg.senderEmail || "your@email.com"}/>
            </div>
            <Button variant="primary" icon={<Icon.send cls="ico-sm"/>} disabled={testing || !connected} onClick={sendTest}>
              {testing ? "Sending…" : "Send test reminder"}
            </Button>
          </div>
          <div className="row gap-8" style={{ padding: 10, background: "var(--primary-soft-2)", border: "1px solid var(--primary)", borderRadius: 8, fontSize: 11.5, lineHeight: 1.5 }}>
            <Icon.check cls="ico-sm" style={{ color: "var(--primary)", flexShrink: 0 }}/>
            <span><strong>Verified:</strong> Emails route through the deployed Cloud Function — your API key stays server-side and never touches the browser. Send a test to confirm delivery, then use the "Send reminder" buttons whenever you need them.</span>
          </div>
        </div>
      </Card>

      {/* Reminder schedule */}
      <Card>
        <div className="col gap-12">
          <div style={{ fontSize: 14, fontWeight: 500 }}>Automatic invoice reminders</div>
          <div className="ink-3" style={{ fontSize: 12.5 }}>When an invoice is unpaid, Relay can email the client on this schedule. Toggle the ones you want.</div>
          {[
            { key: "beforeDue", label: "1 day before due date", desc: "Gentle heads-up so it doesn't slip by" },
            { key: "onDue", label: "On the due date", desc: "Polite same-day reminder" },
            { key: "afterDue", label: "3 days after due (overdue)", desc: "Firmer past-due nudge" },
          ].map((r, i) => (
            <div key={r.key} className="row gap-12" style={{ padding: 12, border: "1px solid var(--line-2)", borderRadius: 8 }}>
              <Toggle on={cfg.reminders[r.key]} onClick={() => updateReminders({ [r.key]: !cfg.reminders[r.key] })}/>
              <div className="col" style={{ lineHeight: 1.3, flex: 1 }}>
                <div style={{ fontSize: 13 }}>{r.label}</div>
                <div className="ink-3" style={{ fontSize: 12 }}>{r.desc}</div>
              </div>
              <Icon.bell cls="ico-sm" style={{ color: cfg.reminders[r.key] ? "var(--primary)" : "var(--ink-3)" }}/>
            </div>
          ))}
          <div className="ink-3" style={{ fontSize: 11.5, lineHeight: 1.5, paddingTop: 4 }}>
            To run these <strong>on a schedule even when your computer is off</strong>, deploy the included Firebase scheduled function (one file). Until then, use the "Send reminder now" buttons on the dashboard — they fire instantly.
          </div>
        </div>
      </Card>

      {/* Client access code generator */}
      <ClientCodeTool/>

      {/* Other notifications */}
      <Card>
        <div className="col gap-12">
          <div style={{ fontSize: 14, fontWeight: 500 }}>Other notifications</div>
          {["Client signs an agreement", "Invoice gets paid", "Client opens portal for the first time", "Weekly client digest"].map((label, i) => (
            <div key={i} className="row gap-10" style={{ padding: "10px 0", borderBottom: i < 3 ? "1px solid var(--line-2)" : "none" }}>
              <Icon.bell cls="ico-sm"/>
              <span style={{ fontSize: 13, flex: 1 }}>{label}</span>
              <label className="row gap-6"><input type="checkbox" defaultChecked/> <span className="ink-3" style={{ fontSize: 12 }}>Email</span></label>
            </div>
          ))}
        </div>
      </Card>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Brand review — pulled from client website, editable swatches
// ─────────────────────────────────────────────────────────────────────
function BrandReviewCard({ brand, setBrand }) {
  const setPrimary = (c) => setBrand({ ...brand, primary: c });
  const setAccent  = (c) => setBrand({ ...brand, accent: c });
  const editColor = (i) => {
    const v = prompt("Edit color (hex or oklch):", brand.palette[i]);
    if (!v) return;
    const next = [...brand.palette];
    next[i] = v;
    setBrand({ ...brand, palette: next });
  };
  return (
    <Card>
      <div className="col gap-14">
        <div className="row" style={{ justifyContent: "space-between", alignItems: "flex-start" }}>
          <div>
            <div className="row gap-8" style={{ alignItems: "center" }}>
              <div style={{ fontSize: 14, fontWeight: 500 }}>Their brand</div>
              <span className="badge pill-active mono" style={{ fontSize: 10 }}>site → portal</span>
            </div>
            <div className="ink-3" style={{ fontSize: 12 }}>
              Pulled from <span className="mono">{brand.url}</span>. We'll skin the portal in their colors so it feels like theirs, not yours.
            </div>
          </div>
          <Button size="sm" variant="ghost" icon={<Icon.refresh cls="ico-sm"/>}>Re-scan</Button>
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "auto 1fr", gap: 16, alignItems: "stretch" }}>
          {/* Logo + voice */}
          <div className="col gap-10" style={{ width: 180 }}>
            <div style={{ background: brand.logo.bg, borderRadius: 10, padding: 18, display: "grid", placeItems: "center", aspectRatio: "1.6 / 1", border: "1px solid rgba(15,26,20,0.06)" }}>
              <span style={{ color: brand.logo.fg, fontFamily: "Instrument Serif, serif", fontWeight: 400, fontSize: 56, lineHeight: 1, letterSpacing: "-0.04em" }}>
                {brand.logo.mark}
              </span>
            </div>
            <div className="row gap-6" style={{ justifyContent: "center" }}>
              <Button size="sm" variant="ghost" icon={<Icon.upload cls="ico-sm"/>}>Replace</Button>
              <Button size="sm" variant="ghost" icon={<Icon.external cls="ico-sm"/>}>Open site</Button>
            </div>
          </div>

          <div className="col gap-12">
            {/* Palette */}
            <div className="col gap-6">
              <div className="row" style={{ justifyContent: "space-between" }}>
                <span className="label" style={{ fontSize: 10.5 }}>Palette · click to swap, set as primary</span>
                <span className="ink-3" style={{ fontSize: 10.5 }}>{brand.palette.length} colors</span>
              </div>
              <div className="row gap-8">
                {brand.palette.map((c, i) => {
                  const isPrimary = c === brand.primary;
                  const isAccent  = c === brand.accent;
                  return (
                    <div key={i} className="col gap-4" style={{ flex: 1 }}>
                      <button onClick={() => editColor(i)} title={c} style={{
                        height: 56, borderRadius: 8, background: c,
                        border: isPrimary ? "2px solid var(--ink)" : "1px solid rgba(15,26,20,0.08)",
                        cursor: "pointer", padding: 0, position: "relative",
                      }}>
                        {(isPrimary || isAccent) && (
                          <span style={{ position: "absolute", top: 4, right: 4, background: "rgba(15,26,20,0.85)", color: "#fff", fontSize: 9, padding: "1px 5px", borderRadius: 999, fontWeight: 600, letterSpacing: "0.02em", textTransform: "uppercase" }}>
                            {isPrimary ? "primary" : "accent"}
                          </span>
                        )}
                      </button>
                      <div className="row gap-2" style={{ fontSize: 9.5, justifyContent: "center" }}>
                        <button className="btn btn-ghost btn-sm" style={{ padding: "1px 5px", fontSize: 9.5 }} onClick={() => setPrimary(c)} disabled={isPrimary}>P</button>
                        <button className="btn btn-ghost btn-sm" style={{ padding: "1px 5px", fontSize: 9.5 }} onClick={() => setAccent(c)} disabled={isAccent}>A</button>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>

            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
              <div className="col gap-4" style={{ padding: 10, background: "var(--surface-2)", borderRadius: 8, border: "1px solid var(--line-2)" }}>
                <span className="label" style={{ fontSize: 10 }}>Type pairing</span>
                <span style={{ fontFamily: "Instrument Serif, serif", fontSize: 20, lineHeight: 1.1 }}>{brand.font.display}</span>
                <span className="mono" style={{ fontSize: 11, color: "var(--ink-3)" }}>{brand.font.body}</span>
              </div>
              <div className="col gap-4" style={{ padding: 10, background: "var(--surface-2)", borderRadius: 8, border: "1px solid var(--line-2)" }}>
                <span className="label" style={{ fontSize: 10 }}>Voice & tone</span>
                <span style={{ fontSize: 12.5, lineHeight: 1.4 }}>{brand.voice}</span>
                <span className="ink-3" style={{ fontSize: 11 }}>We'll echo this in the welcome copy.</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </Card>
  );
}

// ─────────────────────────────────────────────────────────────────────
// Themed portal preview — a mini portal rendered in the client's brand
// ─────────────────────────────────────────────────────────────────────
function BrandedPortalPreview({ brand, client, freelancer }) {
  const surface = brand.surface || "#FBFBF7";
  const ink = brand.ink || "#0F1A14";
  const primary = brand.primary;
  const accent = brand.accent;
  const first = (client.contact || "").split(" ")[0] || "there";
  return (
    <Card pad={false}>
      <div className="row" style={{ padding: "12px 16px", borderBottom: "1px solid var(--line)", justifyContent: "space-between" }}>
        <div className="row gap-8" style={{ alignItems: "center" }}>
          <Icon.layers cls="ico-sm"/>
          <span style={{ fontSize: 13, fontWeight: 500 }}>Portal preview · in their brand</span>
        </div>
        <span className="badge pill-active" style={{ fontSize: 10 }}>auto-themed</span>
      </div>
      <div style={{ background: surface, padding: 14, fontFamily: brand.font.body + ", Geist, sans-serif", color: ink }}>
        {/* Faux browser chrome */}
        <div className="row gap-4" style={{ marginBottom: 10 }}>
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: "rgba(15,26,20,0.18)" }}/>
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: "rgba(15,26,20,0.12)" }}/>
          <span style={{ width: 8, height: 8, borderRadius: "50%", background: "rgba(15,26,20,0.12)" }}/>
          <span className="mono" style={{ fontSize: 9.5, marginLeft: 8, color: "rgba(15,26,20,0.5)" }}>relayhq.studio/p/{clientSlug(client.company)}</span>
        </div>

        {/* Cover */}
        <div style={{ background: primary, color: "#fff", borderRadius: 10, padding: "16px 18px", position: "relative", overflow: "hidden" }}>
          <div className="row" style={{ justifyContent: "space-between", alignItems: "flex-start" }}>
            <span style={{ width: 28, height: 28, borderRadius: 6, background: brand.logo.bg === primary ? "rgba(255,255,255,0.15)" : brand.logo.bg, color: brand.logo.fg, display: "grid", placeItems: "center", fontFamily: "Instrument Serif, serif", fontSize: 16, fontWeight: 400 }}>
              {brand.logo.mark}
            </span>
            <span className="mono" style={{ fontSize: 9.5, color: "rgba(255,255,255,0.7)", textTransform: "uppercase", letterSpacing: "0.06em" }}>
              For {client.company}
            </span>
          </div>
          <div style={{ fontFamily: "Instrument Serif, serif", fontSize: 22, lineHeight: 1.1, marginTop: 12, letterSpacing: "-0.01em" }}>
            Welcome, {first}.
          </div>
          <div style={{ fontSize: 11.5, opacity: 0.85, marginTop: 4, maxWidth: 280 }}>
            A short, branded space to sign the agreement, pay the deposit, and meet {freelancer.name.split(" ")[0]}.
          </div>
          {/* Accent dot */}
          <span style={{ position: "absolute", right: -20, bottom: -20, width: 80, height: 80, borderRadius: "50%", background: accent, opacity: 0.65 }}/>
        </div>

        {/* Step rail */}
        <div className="row gap-6" style={{ marginTop: 12, fontSize: 10.5 }}>
          {["Welcome", "Intake", "Agreement", "Deposit"].map((s, i) => (
            <div key={s} className="row gap-4" style={{ alignItems: "center", padding: "4px 8px", background: i === 0 ? primary : "rgba(15,26,20,0.05)", color: i === 0 ? "#fff" : ink, borderRadius: 999, fontWeight: 500 }}>
              <span style={{ width: 5, height: 5, borderRadius: "50%", background: i === 0 ? accent : "rgba(15,26,20,0.3)" }}/>
              {s}
            </div>
          ))}
        </div>

        {/* CTA */}
        <div style={{ marginTop: 12, padding: "8px 12px", background: primary, color: "#fff", borderRadius: 8, fontSize: 11.5, fontWeight: 500, display: "inline-flex", alignItems: "center", gap: 6 }}>
          Start onboarding
          <span style={{ color: accent }}>→</span>
        </div>
        <div className="row" style={{ marginTop: 10, fontSize: 10, color: "rgba(15,26,20,0.5)", justifyContent: "space-between" }}>
          <span>Powered by {freelancer.brand}</span>
          <span className="mono">{brand.font.display} / {brand.font.body}</span>
        </div>
      </div>
    </Card>
  );
}

Object.assign(window, {
  AdminShell, AdminDashboard, AdminClients, AdminClientDetail, AdminNewClient, AdminTemplates, AdminInbox, AdminSettings, SOWDocument,
  BrandReviewCard, BrandedPortalPreview,
});
