// screens-a.jsx — Campaigns, Routing (list + editor), Team (live data)

const CHANNEL_OPTIONS = [
  { id: "google_ads", label: "Google Ads" },
  { id: "facebook", label: "Facebook" },
  { id: "direct_mail", label: "Direct Mail" },
  { id: "yelp", label: "Yelp" },
  { id: "seo", label: "SEO" },
  { id: "radio", label: "Radio" },
  { id: "organic", label: "Organic" },
  { id: "other", label: "Other" },
];

function channelLabel(id) {
  const c = CHANNEL_OPTIONS.find((c) => c.id === id);
  return c ? c.label : id;
}

function fmtMoney(cents) {
  if (cents == null) return "—";
  return "$" + (Number(cents) / 100).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

function Campaigns({ workspace }) {
  const wid = workspace.id;
  const list = useApi(() => API.campaigns.list(wid), [wid]);
  const [showNew, setShowNew] = React.useState(false);
  const [editing, setEditing] = React.useState(null);

  const rows = list.data || [];

  return (
    <div className="page-inner wide">
      <div className="row between" style={{alignItems:"flex-start", marginBottom:24}}>
        <div>
          <div className="eyebrow">Tracking</div>
          <h1 className="page-title" style={{marginTop:6}}>Campaigns</h1>
          <div className="page-sub">Attribution by source · ROI & cost-per-lead in real time</div>
        </div>
        <button className="btn btn-primary" onClick={() => setShowNew(true)}><I.plus size={13}/> New campaign</button>
      </div>

      {list.error && <ErrorChip msg={list.error.message}/>}

      <div className="card">
        <table className="table">
          <thead>
            <tr>
              <th>Campaign</th>
              <th>Channel</th>
              <th style={{textAlign:"right"}}>Calls</th>
              <th style={{textAlign:"right"}}>Qualified</th>
              <th style={{textAlign:"right"}}>Spend</th>
              <th style={{textAlign:"right"}}>Cost / lead</th>
              <th>Status</th>
              <th style={{width:60}}></th>
            </tr>
          </thead>
          <tbody>
            {list.loading && rows.length === 0 && <tr><td colSpan={8} style={{textAlign:"center", padding:30, color:"var(--ink-4)"}}>Loading…</td></tr>}
            {!list.loading && rows.length === 0 && <tr><td colSpan={8} style={{textAlign:"center", padding:30, color:"var(--ink-4)"}}>No campaigns yet</td></tr>}
            {rows.map((c) => (
              <tr key={c.id} style={{cursor:"pointer"}} onClick={() => setEditing(c)}>
                <td style={{color:"var(--ink)", fontWeight:500}}>{c.name}</td>
                <td className="muted">{channelLabel(c.channel)}</td>
                <td className="num" style={{textAlign:"right"}}>{c.calls || 0}</td>
                <td className="num" style={{textAlign:"right"}}>{c.qualifiedCalls || 0}</td>
                <td className="num" style={{textAlign:"right"}}>{fmtMoney(c.spendCents)}</td>
                <td className="num" style={{textAlign:"right"}}>{c.cplCents != null ? fmtMoney(c.cplCents) : "—"}</td>
                <td>
                  <span className={"pill " + (c.status === "active" ? "good" : "")}>
                    <span className="dot"/>{c.status}
                  </span>
                </td>
                <td onClick={(e) => e.stopPropagation()}>
                  <button className="icon-btn" title="Delete" onClick={async () => {
                    const ok = await window.confirmDialog({
                      title: "Delete campaign",
                      message: `Delete "${c.name}"? Calls already attributed to this campaign keep their attribution.`,
                      confirmLabel: "Delete",
                      danger: true,
                    });
                    if (!ok) return;
                    try { await API.campaigns.delete(wid, c.id); list.reload(); window.toast.success("Campaign deleted"); }
                    catch (err) { window.toast.error(err.message); }
                  }}><I.x size={14}/></button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      {showNew && <CampaignModal workspace={workspace} onClose={() => setShowNew(false)} onSaved={() => { setShowNew(false); list.reload(); }} />}
      {editing && <CampaignModal workspace={workspace} campaign={editing} onClose={() => setEditing(null)} onSaved={() => { setEditing(null); list.reload(); }} />}
    </div>
  );
}

function CampaignModal({ workspace, campaign, onClose, onSaved }) {
  const wid = workspace.id;
  const isEdit = !!campaign;
  const [name, setName] = React.useState(campaign?.name || "");
  const [channel, setChannel] = React.useState(campaign?.channel || "google_ads");
  const [spend, setSpend] = React.useState(campaign?.spendCents != null ? (campaign.spendCents / 100).toString() : "0");
  const [status, setStatus] = React.useState(campaign?.status || "active");
  const [submitting, setSubmitting] = React.useState(false);
  const [error, setError] = React.useState(null);

  async function submit(e) {
    e.preventDefault();
    setSubmitting(true); setError(null);
    try {
      const payload = {
        name: name.trim(),
        channel,
        spendCents: Math.round(Number(spend) * 100) || 0,
      };
      if (isEdit) {
        payload.status = status;
        await API.campaigns.patch(wid, campaign.id, payload);
      } else {
        await API.campaigns.create(wid, payload);
      }
      onSaved && onSaved();
    } catch (err) {
      setError(err.message);
    } finally {
      setSubmitting(false);
    }
  }

  return (
    <Modal onClose={onClose} title={isEdit ? "Edit campaign" : "New campaign"}>
      <form onSubmit={submit} className="col g16">
        <div className="field"><label>Name</label>
          <input className="input" value={name} onChange={(e) => setName(e.target.value)} required autoFocus/>
        </div>
        <div className="field"><label>Channel</label>
          <select className="select" value={channel} onChange={(e) => setChannel(e.target.value)}>
            {CHANNEL_OPTIONS.map((c) => <option key={c.id} value={c.id}>{c.label}</option>)}
          </select>
        </div>
        <div className="field"><label>Spend (USD)</label>
          <input className="input" type="number" step="0.01" min="0" value={spend} onChange={(e) => setSpend(e.target.value)}/>
        </div>
        {isEdit && (
          <div className="field"><label>Status</label>
            <select className="select" value={status} onChange={(e) => setStatus(e.target.value)}>
              <option value="active">Active</option>
              <option value="paused">Paused</option>
              <option value="archived">Archived</option>
            </select>
          </div>
        )}
        {error && <ErrorChip msg={error}/>}
        <div className="row g8" style={{justifyContent:"flex-end"}}>
          <button type="button" className="btn btn-ghost btn-sm" onClick={onClose}>Cancel</button>
          <button type="submit" className="btn btn-primary btn-sm" disabled={submitting}>
            {submitting ? "Saving…" : (isEdit ? "Save" : "Create")}
          </button>
        </div>
      </form>
    </Modal>
  );
}

// ── Routing ──────────────────────────────────────────────────────────

function Routing({ workspace }) {
  const [editingId, setEditingId] = React.useState(null);
  return editingId
    ? <RoutingEditor workspace={workspace} numberId={editingId} onBack={() => setEditingId(null)} />
    : <RoutingList workspace={workspace} onEdit={(id) => setEditingId(id)} />;
}

function RoutingList({ workspace, onEdit }) {
  const wid = workspace.id;
  const [q, setQ] = React.useState("");
  const [sort, setSort] = React.useState({ key: "calls", dir: "desc" });

  const list = useApi(
    () => API.routing.list(wid, { q: q.trim() || undefined, sort: sort.key, dir: sort.dir }),
    [wid, q, sort.key, sort.dir]
  );

  const toggleSort = (key) => setSort((s) => s.key === key ? { key, dir: s.dir === "asc" ? "desc" : "asc" } : { key, dir: "desc" });
  const SortH = ({ k, children, align = "left" }) => (
    <th style={{textAlign: align, cursor:"pointer"}} onClick={() => toggleSort(k)}>
      <span style={{display:"inline-flex", alignItems:"center", gap:4}}>
        {children}
        {sort.key === k && <span style={{fontSize:9, color:"var(--ink-3)"}}>{sort.dir === "asc" ? "▲" : "▼"}</span>}
      </span>
    </th>
  );

  const rows = list.data || [];

  return (
    <div className="page-inner wide">
      <div className="row between" style={{alignItems:"flex-start", marginBottom:24}}>
        <div>
          <div className="eyebrow">Tracking</div>
          <h1 className="page-title" style={{marginTop:6}}>Routing</h1>
          <div className="page-sub">{rows.length} numbers · click any row to configure</div>
        </div>
      </div>

      <div className="card">
        <div className="card-h" style={{padding:"12px 16px", gap:12}}>
          <div style={{flex:1, display:"flex", alignItems:"center", gap:10, height:34, padding:"0 12px", background:"var(--bg-elev)", borderRadius:8, border:".5px solid var(--line-2)"}}>
            <I.search size={14} style={{color:"var(--ink-4)"}}/>
            <input
              value={q}
              onChange={(e) => setQ(e.target.value)}
              placeholder="Search by friendly name or number…"
              style={{flex:1, border:0, outline:"none", background:"transparent", fontSize:13.5, color:"var(--ink)"}}
            />
            {q && <button className="icon-btn" style={{width:22, height:22}} onClick={() => setQ("")}><I.x size={12}/></button>}
          </div>
        </div>

        <table className="table">
          <thead>
            <tr>
              <SortH k="friendly_name">Friendly name</SortH>
              <th>Number</th>
              <SortH k="type">Routing</SortH>
              <th>Destination</th>
              <th>Features</th>
              <SortH k="calls" align="right">Calls</SortH>
              <th style={{width:40}}></th>
            </tr>
          </thead>
          <tbody>
            {list.loading && rows.length === 0 && <tr><td colSpan={7} style={{textAlign:"center", padding:30, color:"var(--ink-4)"}}>Loading…</td></tr>}
            {!list.loading && rows.length === 0 && <tr><td colSpan={7} style={{textAlign:"center", padding:30, color:"var(--ink-4)"}}>No numbers yet</td></tr>}
            {rows.map((r) => (
              <tr key={r.id} onClick={() => onEdit(r.id)} style={{cursor:"pointer"}}>
                <td style={{color: r.friendlyName ? "var(--ink)" : "var(--ink-4)", fontWeight:500}}>
                  {r.friendlyName || "— unnamed —"}
                </td>
                <td className="num">{fmtNumber(r.number)}</td>
                <td>
                  <div style={{color:"var(--ink-2)", textTransform:"capitalize"}}>{r.routingType ? r.routingType.replace(/_/g, " ") : "—"}</div>
                </td>
                <td className="muted num" style={{fontSize:12.5}}>{r.destination ? (fmtNumber(r.destination) || r.destination) : "—"}</td>
                <td>
                  <div className="row g8">
                    {r.recordCalls && <span title="Recording" style={{color:"var(--accent)"}}><I.mic size={13}/></span>}
                    {r.transcribeCalls && <span title="Transcription" style={{color:"#9333EA"}}><I.sparkle size={13}/></span>}
                  </div>
                </td>
                <td className="num" style={{textAlign:"right", color: r.calls > 0 ? "var(--ink)" : "var(--ink-4)"}}>{r.calls || 0}</td>
                <td><I.chev size={14} style={{color:"var(--ink-4)"}}/></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function RoutingEditor({ workspace, numberId, onBack }) {
  const wid = workspace.id;
  const detail = useApi(() => API.routing.get(wid, numberId), [wid, numberId]);
  const [form, setForm] = React.useState(null);
  const [ringGroup, setRingGroup] = React.useState([""]);
  const [ivrOptions, setIvrOptions] = React.useState([]);
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [okMsg, setOkMsg] = React.useState(null);

  React.useEffect(() => {
    if (!detail.data) return;
    const d = detail.data;
    setForm({
      friendlyName: d.friendlyName || "",
      type: d.type || "forward",
      destination: d.destination || "",
      greetingMessage: d.greetingMessage || "",
      whisperMessage: d.whisperMessage || "",
      recordCalls: d.recordCalls ?? true,
      transcribeCalls: d.transcribeCalls ?? true,
      spamFilter: d.spamFilter ?? true,
      cnamLookup: d.cnamLookup ?? false,
      failoverEnabled: d.failoverEnabled ?? false,
      failoverNumber: d.failoverNumber || "",
    });
    // Hydrate ring group from comma-separated destination
    if (d.type === "ring_group") {
      const parts = (d.destination || "").split(",").map((s) => s.trim()).filter(Boolean);
      setRingGroup(parts.length ? parts : [""]);
    } else {
      setRingGroup([""]);
    }
    setIvrOptions(d.ivrOptions || []);
  }, [detail.data]);

  // Dirty detection — compare current state to last-loaded snapshot.
  // MUST be defined before any early returns (Rules of Hooks).
  const isDirty = React.useMemo(() => {
    const d = detail.data;
    if (!d || !form) return false;
    const norm = (v) => v == null ? "" : v;
    const ne = (v) => (window.Phone && Phone.toE164(v)) || "";
    const ringE164 = (s) => (s || "").split(",").map((p) => ne(p)).filter(Boolean).join(",");

    const effectiveDest = form.type === "ring_group"
      ? ringGroup.map(ne).filter(Boolean).join(",")
      : (form.type === "forward" ? ne(form.destination) : norm(form.destination));
    const originalDest = d.type === "ring_group"
      ? ringE164(d.destination)
      : (d.type === "forward" ? ne(d.destination) : norm(d.destination));

    if (norm(form.friendlyName) !== norm(d.friendlyName)) return true;
    if (form.type !== (d.type || "forward")) return true;
    if (effectiveDest !== originalDest) return true;
    if (norm(form.greetingMessage) !== norm(d.greetingMessage)) return true;
    if (norm(form.whisperMessage) !== norm(d.whisperMessage)) return true;
    if (form.recordCalls !== (d.recordCalls ?? true)) return true;
    if (form.transcribeCalls !== (d.transcribeCalls ?? true)) return true;
    if (form.spamFilter !== (d.spamFilter ?? true)) return true;
    if (form.cnamLookup !== (d.cnamLookup ?? false)) return true;
    if (form.failoverEnabled !== (d.failoverEnabled ?? false)) return true;
    if (ne(form.failoverNumber) !== ne(d.failoverNumber)) return true;

    if (ivrOptions.some((o) => o._new || o._dirty)) return true;
    const originalIvrIds = new Set((d.ivrOptions || []).map((o) => o.id));
    const currentIvrIds = new Set(ivrOptions.filter((o) => !o._new).map((o) => o.id));
    if (originalIvrIds.size !== currentIvrIds.size) return true;
    for (const id of originalIvrIds) if (!currentIvrIds.has(id)) return true;

    return false;
  }, [form, ringGroup, ivrOptions, detail.data]);

  if (detail.loading || !form) {
    return <div className="page-inner wide"><div style={{padding:30, color:"var(--ink-4)"}}>Loading routing…</div></div>;
  }
  if (detail.error) {
    return <div className="page-inner wide"><ErrorChip msg={detail.error.message}/></div>;
  }

  const setF = (k, v) => setForm((f) => ({ ...f, [k]: v }));

  async function save() {
    setSaving(true); setError(null); setOkMsg(null);
    try {
      // Build the destination payload based on the chosen type
      let destination = form.destination;
      if (form.type === "ring_group") {
        destination = ringGroup.map((n) => n.trim()).filter(Boolean).join(", ");
      }
      const payload = { ...form, destination };

      await API.routing.put(wid, numberId, payload);
      if (form.friendlyName !== detail.data.friendlyName) {
        await API.numbers.patch(wid, numberId, { friendlyName: form.friendlyName });
      }
      // IVR sync — adds/updates only; deletions go through the inline ✕
      for (const opt of ivrOptions) {
        if (opt._deleted) continue;
        if (opt._new) {
          if (!opt.keyPress || !opt.label || !opt.destination) continue;
          await API.routing.addIvr(wid, numberId, {
            keyPress: opt.keyPress, label: opt.label, destination: opt.destination, sortOrder: opt.sortOrder ?? 0,
          });
        } else if (opt._dirty) {
          await API.routing.updateIvr(wid, numberId, opt.id, {
            keyPress: opt.keyPress, label: opt.label, destination: opt.destination, sortOrder: opt.sortOrder ?? 0,
          });
        }
      }
      detail.reload();
      setOkMsg("Saved.");
      setTimeout(() => setOkMsg(null), 2000);
    } catch (err) {
      setError(err.message);
    } finally {
      setSaving(false);
    }
  }

  // Ring group helpers
  function addRingNumber() { setRingGroup((g) => [...g, ""]); }
  function removeRingNumber(idx) {
    setRingGroup((g) => g.length === 1 ? [""] : g.filter((_, i) => i !== idx));
  }
  function updateRingNumber(idx, v) {
    setRingGroup((g) => g.map((x, i) => i === idx ? v : x));
  }

  // IVR helpers
  function addIvr() {
    setIvrOptions((opts) => {
      const used = new Set(opts.filter((o) => !o._deleted).map((o) => o.keyPress));
      const candidates = ["1","2","3","4","5","6","7","8","9","0","*","#"];
      const next = candidates.find((k) => !used.has(k)) || "";
      return [...opts, { _new: true, keyPress: next, label: "", destination: "", sortOrder: opts.length }];
    });
  }
  async function removeIvr(opt, idx) {
    if (opt._new) {
      setIvrOptions((opts) => opts.filter((_, i) => i !== idx));
      return;
    }
    try {
      await API.routing.deleteIvr(wid, numberId, opt.id);
      setIvrOptions((opts) => opts.filter((_, i) => i !== idx));
    } catch (err) { window.toast.error(err.message); }
  }
  function updateIvr(idx, patch) {
    setIvrOptions((opts) => opts.map((o, i) => i === idx ? { ...o, ...patch, _dirty: !o._new } : o));
  }

  // Optional steps state
  const hasGreeting = !!form.greetingMessage;
  const hasWhisper = !!form.whisperMessage;
  const showWhisper = form.type === "forward" || form.type === "ring_group";
  const showFailover = form.type !== "voicemail";

  return (
    <div className="page-inner wide">
      <div className="row g8" style={{marginBottom:12}}>
        <button className="btn btn-ghost btn-sm" onClick={onBack}>
          <I.chev size={13} style={{transform:"rotate(180deg)"}}/> Back to routing
        </button>
      </div>

      <div className="row between" style={{alignItems:"flex-start", marginBottom:24}}>
        <div style={{flex:1, minWidth:0}}>
          <div className="eyebrow row g8">
            Routing · <span className="num">{fmtNumber(detail.data.number)}</span>
            <span className={"pill " + (detail.data.status === "live" ? "good" : "warn")} style={{height:18, fontSize:10}}>
              <span className="dot"/>{detail.data.status}
            </span>
          </div>
          <input
            value={form.friendlyName}
            onChange={(e) => setF("friendlyName", e.target.value)}
            className="page-title"
            style={{marginTop:6, width:"100%", border:0, background:"transparent", outline:"none", padding:0, font:"inherit", fontFamily:"var(--serif)", fontSize:40, lineHeight:1.15, color:"var(--ink)", letterSpacing:"-0.015em"}}
            placeholder={fmtNumber(detail.data.number)}
          />
          <div className="page-sub">Click the title to give this number a friendly name. Build the call's journey below.</div>
        </div>
        <div className="row g8" style={{marginLeft:16, flexShrink:0}}>
          {isDirty && (
            <button className="btn btn-secondary btn-sm" onClick={() => detail.reload()} disabled={saving}>
              Discard
            </button>
          )}
          <button className="btn btn-primary btn-sm" onClick={save} disabled={saving || !isDirty}>
            {saving ? "Saving…" : isDirty ? "Save changes" : "Saved"}
          </button>
        </div>
      </div>

      {error && <ErrorChip msg={error}/>}
      {okMsg && <div style={{margin:"12px 0", padding:"10px 14px", background:"rgba(16,185,129,.1)", border:".5px solid rgba(16,185,129,.3)", borderRadius:8, fontSize:13, color:"var(--good)"}}>{okMsg}</div>}

      <div style={{display:"grid", gridTemplateColumns:"1.6fr 1fr", gap:16}}>
        <div className="flow-canvas">
          {/* Step 1 — Incoming */}
          <FlowCard
            icon={<I.phone size={16}/>}
            iconBg="linear-gradient(135deg,#0A84FF,#9333EA)"
            iconColor="white"
            title={<>Incoming — <span className="num">{fmtNumber(detail.data.number)}</span></>}
            subtitle={form.friendlyName || "Untitled number"}
            badge={<span className="pill" style={{height:18, fontSize:10}}>caller dials</span>}
          />

          {/* + Greeting / Greeting card */}
          {!hasGreeting ? (
            <FlowAddStep label="Add greeting" onClick={() => setF("greetingMessage", "Thanks for calling. Please hold while we connect you.")}/>
          ) : (
            <>
              <FlowArrow/>
              <FlowCard
                icon={<I.sparkle size={15}/>}
                iconBg="color-mix(in oklab, #16A34A 15%, transparent)"
                iconColor="#16A34A"
                title="Greeting"
                subtitle="Played to the caller before routing"
                action={<button className="icon-btn" title="Remove greeting" onClick={() => setF("greetingMessage", "")}><I.x size={14}/></button>}
              >
                <textarea
                  className="input"
                  rows={2}
                  value={form.greetingMessage}
                  onChange={(e) => setF("greetingMessage", e.target.value)}
                  placeholder="Thanks for calling…"
                  style={{marginTop:10}}
                />
              </FlowCard>
            </>
          )}

          <FlowArrow/>

          {/* Step 2 — Core routing */}
          <FlowCard
            icon={<RouteIcon type={form.type}/>}
            iconBg={routeIconBg(form.type)}
            iconColor={routeIconColor(form.type)}
            title={routeTitle(form.type)}
            subtitle={routeSubtitle(form.type, form.destination, ringGroup, ivrOptions)}
            badge={<span className="pill info" style={{height:18, fontSize:10}}>core</span>}
          >
            {/* Type switcher */}
            <div className="route-types">
              {[
                { id: "forward", label: "Forward", icon: <I.phone size={13}/> },
                { id: "ring_group", label: "Ring group", icon: <I.users size={13}/> },
                { id: "ivr", label: "IVR menu", icon: <I.route size={13}/> },
                { id: "voicemail", label: "Voicemail", icon: <I.mic size={13}/> },
              ].map((t) => (
                <button
                  key={t.id}
                  className={"route-types__btn" + (form.type === t.id ? " on" : "")}
                  onClick={() => setF("type", t.id)}
                  type="button"
                >
                  {t.icon}<span>{t.label}</span>
                </button>
              ))}
            </div>

            {/* Per-type body */}
            <div style={{marginTop:14}}>
              {form.type === "forward" && (
                <div className="field"><label>Forward to</label>
                  <PhoneInput value={form.destination} onChange={(v) => setF("destination", v)}/>
                </div>
              )}

              {form.type === "ring_group" && (
                <div className="field">
                  <label>Ring all of these at once</label>
                  <div className="col g8">
                    {ringGroup.map((num, idx) => (
                      <div key={idx} className="ring-row">
                        <span className="ring-row__idx">{idx + 1}</span>
                        <div style={{flex:1}}>
                          <PhoneInput
                            value={num}
                            onChange={(v) => updateRingNumber(idx, v)}
                            className=""
                            style={{border:0, background:"transparent", height:36, padding:0, width:"100%", outline:"none", fontSize:13.5, color:"var(--ink)"}}
                          />
                        </div>
                        <button className="icon-btn" title="Remove" onClick={() => removeRingNumber(idx)}><I.x size={13}/></button>
                      </div>
                    ))}
                  </div>
                  <button type="button" className="btn btn-ghost btn-sm" style={{alignSelf:"flex-start", marginTop:8}} onClick={addRingNumber}>
                    <I.plus size={12}/> Add another phone
                  </button>
                  <div className="muted" style={{fontSize:12, marginTop:6}}>First to pick up wins. Others stop ringing.</div>
                </div>
              )}

              {form.type === "ivr" && (
                <IvrEditor
                  options={ivrOptions}
                  onAdd={addIvr}
                  onUpdate={updateIvr}
                  onRemove={removeIvr}
                />
              )}

              {form.type === "voicemail" && (
                <div className="field"><label>Send recording + transcript to</label>
                  <input className="input" value={form.destination} onChange={(e) => setF("destination", e.target.value)} placeholder="voicemail@example.com"/>
                  <div className="muted" style={{fontSize:12}}>Email, Slack channel, or webhook URL</div>
                </div>
              )}
            </div>
          </FlowCard>

          {/* + Whisper / Whisper card */}
          {showWhisper && (
            !hasWhisper ? (
              <FlowAddStep label="Add whisper to agent" onClick={() => setF("whisperMessage", "Spring promo lead")}/>
            ) : (
              <>
                <FlowArrow/>
                <FlowCard
                  icon={<I.mic size={15}/>}
                  iconBg="color-mix(in oklab, #DB2777 15%, transparent)"
                  iconColor="#DB2777"
                  title="Whisper to agent"
                  subtitle="Played to the agent before connect — caller doesn't hear"
                  action={<button className="icon-btn" title="Remove whisper" onClick={() => setF("whisperMessage", "")}><I.x size={14}/></button>}
                >
                  <input
                    className="input"
                    value={form.whisperMessage}
                    onChange={(e) => setF("whisperMessage", e.target.value)}
                    placeholder="Spring promo lead"
                    style={{marginTop:10}}
                  />
                </FlowCard>
              </>
            )
          )}

          {/* + Failover / Failover card */}
          {showFailover && (
            !form.failoverEnabled ? (
              <FlowAddStep label="Add fallback number" onClick={() => setF("failoverEnabled", true)}/>
            ) : (
              <>
                <FlowArrow label="no answer"/>
                <FlowCard
                  icon={<I.clock size={15}/>}
                  iconBg="color-mix(in oklab, #F97316 15%, transparent)"
                  iconColor="#F97316"
                  title="Fallback number"
                  subtitle="Ring this if the primary doesn't answer"
                  action={<button className="icon-btn" title="Remove fallback" onClick={() => { setF("failoverEnabled", false); setF("failoverNumber", ""); }}><I.x size={14}/></button>}
                >
                  <div style={{marginTop:10}}>
                    <PhoneInput
                      value={form.failoverNumber}
                      onChange={(v) => setF("failoverNumber", v)}
                      placeholder="+14155551300"
                    />
                  </div>
                </FlowCard>
              </>
            )
          )}
        </div>

        <div className="col g16">
          <div className="card">
            <div className="card-h"><h3>Recording & filters</h3></div>
            <div className="card-b col g12">
              <Toggle label="Record all calls" sub="Dual-channel · 90 day retention" value={form.recordCalls} onChange={(v) => setF("recordCalls", v)} />
              <Toggle label="Transcribe calls" sub="Live transcript + AI summary" value={form.transcribeCalls} onChange={(v) => setF("transcribeCalls", v)} />
              <Toggle label="Spam / robocall filter" sub="STIR/SHAKEN + reputation" value={form.spamFilter} onChange={(v) => setF("spamFilter", v)} />
              <Toggle label="CNAM lookup" sub="$0.008 · caller name enrichment" value={form.cnamLookup} onChange={(v) => setF("cnamLookup", v)} />
            </div>
          </div>

          <div className="card">
            <div className="card-h"><h3>Quick info</h3></div>
            <div className="card-b col g12" style={{fontSize:13.5}}>
              <KV k="Number" v={fmtNumber(detail.data.number)} mono />
              <KV k="Status" v={<span className={"pill " + (detail.data.status === "live" ? "good" : "warn")}>{detail.data.status}</span>} />
            </div>
          </div>

          <div className="card">
            <div className="card-h"><h3>Danger zone</h3></div>
            <div className="card-b col g8">
              <button className="btn btn-secondary btn-sm" style={{justifyContent:"flex-start"}}
                onClick={async () => {
                  const ok = await window.confirmDialog({
                    title: "Pause routing",
                    message: "Inbound calls to this number will be rejected until you re-enable routing.",
                    confirmLabel: "Pause",
                  });
                  if (!ok) return;
                  try { await API.numbers.patch(wid, numberId, { status: "paused" }); detail.reload(); window.toast.success("Routing paused"); }
                  catch (err) { window.toast.error(err.message); }
                }}>
                Pause routing
              </button>
              <button className="btn btn-secondary btn-sm" style={{justifyContent:"flex-start", color:"var(--bad)"}}
                onClick={async () => {
                  const ok = await window.confirmDialog({
                    title: "Release number",
                    message: "The number returns to the available inventory pool. Anyone can claim it after that.",
                    confirmLabel: "Release",
                    danger: true,
                  });
                  if (!ok) return;
                  try { await API.numbers.delete(wid, numberId); window.toast.success("Number released"); onBack(); }
                  catch (err) { window.toast.error(err.message); }
                }}>
                Release number
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Phone input with inline validation ───────────────────────────────

function PhoneInput({ value, onChange, placeholder = "+14155551200", className = "input", style, autoFocus }) {
  // Surface validation only after the field has been touched (avoid red-on-mount)
  const [touched, setTouched] = React.useState(false);
  const invalid = touched && Phone.isInvalidIfFilled(value);

  return (
    <div style={{display:"flex", flexDirection:"column", gap:4, width:"100%"}}>
      <input
        className={className}
        style={{
          ...style,
          ...(invalid ? { borderColor: "#DC2626", boxShadow: "0 0 0 3px rgba(220,38,38,.12)" } : {}),
        }}
        value={value || ""}
        onChange={(e) => onChange(e.target.value)}
        onBlur={() => {
          setTouched(true);
          // Snap to formatted display when valid
          const e164 = Phone.toE164(value);
          if (e164) onChange(Phone.format(e164));
        }}
        onFocus={() => {
          // Restore raw E.164 for editing — easier to backspace than parens
          if (Phone.isValid(value)) onChange(Phone.toE164(value));
        }}
        placeholder={placeholder}
        inputMode="tel"
        autoComplete="tel"
        autoFocus={autoFocus}
      />
      {invalid && (
        <div style={{fontSize:11.5, color:"#DC2626"}}>Not a valid US phone number</div>
      )}
    </div>
  );
}

// ── Flow primitives ──────────────────────────────────────────────────

function FlowCard({ icon, iconBg, iconColor, title, subtitle, badge, action, children }) {
  return (
    <div className="flow-card">
      <div className="flow-card__head">
        <div className="flow-card__icon" style={{background: iconBg, color: iconColor}}>{icon}</div>
        <div className="flow-card__text">
          <div className="flow-card__title">{title}</div>
          {subtitle && <div className="flow-card__sub">{subtitle}</div>}
        </div>
        <div className="flow-card__right">
          {badge}
          {action}
        </div>
      </div>
      {children && <div className="flow-card__body">{children}</div>}
    </div>
  );
}

function FlowArrow({ label }) {
  return (
    <div className="flow-arrow">
      <svg width="14" height="18" viewBox="0 0 14 18" fill="none">
        <path d="M7 1 V15 M2 10 L7 15 L12 10" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
      {label && <span className="flow-arrow__lbl">{label}</span>}
    </div>
  );
}

function FlowAddStep({ label, onClick }) {
  return (
    <div className="flow-add-wrap">
      <button type="button" className="flow-add" onClick={onClick}>
        <I.plus size={12}/> {label}
      </button>
    </div>
  );
}

function RouteIcon({ type }) {
  if (type === "ring_group") return <I.users size={15}/>;
  if (type === "ivr") return <I.route size={15}/>;
  if (type === "voicemail") return <I.mic size={15}/>;
  return <I.phone size={15}/>;
}
function routeIconBg(type) {
  if (type === "ring_group") return "color-mix(in oklab, #6366F1 18%, transparent)";
  if (type === "ivr") return "color-mix(in oklab, #9333EA 18%, transparent)";
  if (type === "voicemail") return "color-mix(in oklab, #6B7280 18%, transparent)";
  return "color-mix(in oklab, #0A84FF 18%, transparent)";
}
function routeIconColor(type) {
  if (type === "ring_group") return "#6366F1";
  if (type === "ivr") return "#9333EA";
  if (type === "voicemail") return "#6B7280";
  return "#0A84FF";
}
function routeTitle(type) {
  if (type === "ring_group") return "Ring multiple phones";
  if (type === "ivr") return "Caller chooses with keypad";
  if (type === "voicemail") return "Send straight to voicemail";
  return "Forward to one phone";
}
function routeSubtitle(type, destination, ringGroup, ivrOptions) {
  if (type === "ring_group") {
    const valid = (ringGroup || []).map((s) => s && s.trim()).filter(Boolean);
    if (!valid.length) return "Add at least one phone below";
    return `${valid.length} phone${valid.length === 1 ? "" : "s"} ring at once`;
  }
  if (type === "ivr") {
    const live = (ivrOptions || []).filter((o) => !o._deleted);
    return live.length ? `${live.length} option${live.length === 1 ? "" : "s"}` : "No options yet — add one below";
  }
  if (type === "voicemail") return destination ? `→ ${destination}` : "Add a destination below";
  return destination ? `→ ${fmtNumber(destination) || destination}` : "Add a destination below";
}

function IvrEditor({ options, onAdd, onUpdate, onRemove }) {
  return (
    <div className="ivr-grid">
      {options.length === 0 && (
        <div style={{padding:"18px 0", textAlign:"center", color:"var(--ink-4)", fontSize:13}}>
          No options yet. Add the first one below.
        </div>
      )}
      {options.map((opt, idx) => (
        <div key={idx} className="ivr-row">
          <div className="ivr-row__key">
            <input
              value={opt.keyPress}
              onChange={(e) => {
                const v = (e.target.value.match(/[0-9*#]/) || [""])[0];
                onUpdate(idx, { keyPress: v });
              }}
              onKeyDown={(e) => {
                if (e.metaKey || e.ctrlKey || e.altKey) return;
                if (["Backspace","Delete","Tab","ArrowLeft","ArrowRight","Home","End","Enter","Escape"].includes(e.key)) return;
                if (!/^[0-9*#]$/.test(e.key)) e.preventDefault();
              }}
              maxLength={1}
              inputMode="numeric"
              placeholder="1"
              aria-label="Key press"
            />
          </div>
          <div className="ivr-row__body">
            <input
              className="ivr-row__label"
              value={opt.label}
              onChange={(e) => onUpdate(idx, { label: e.target.value })}
              placeholder="What this option is for (e.g. New patient)"
            />
            <div style={{flex:1, minWidth:0}}>
              <PhoneInput
                value={opt.destination}
                onChange={(v) => onUpdate(idx, { destination: v })}
                className="ivr-row__dest num"
                style={{height:36, padding:"0 10px", border:0, outline:0, background:"transparent", fontSize:13, color:"var(--ink)", width:"100%"}}
              />
            </div>
          </div>
          <button className="icon-btn" onClick={() => onRemove(opt, idx)} title="Remove option"><I.x size={14}/></button>
        </div>
      ))}
      <button type="button" className="btn btn-ghost btn-sm" onClick={onAdd} style={{alignSelf:"flex-start", marginTop:4}}>
        <I.plus size={12}/> Add option
      </button>
    </div>
  );
}

function Toggle({ label, sub, value, onChange }) {
  return (
    <div className="row between">
      <div>
        <div style={{fontSize:13.5, color:"var(--ink)", fontWeight:500}}>{label}</div>
        {sub && <div className="muted" style={{fontSize:12}}>{sub}</div>}
      </div>
      <button onClick={() => onChange(!value)} style={{width:36, height:22, borderRadius:999, background: value ? "var(--accent)" : "var(--ink-5)", border:0, padding:0, position:"relative", transition:"background .15s", cursor:"pointer"}}>
        <span style={{position:"absolute", top:2, left: value ? 16 : 2, width:18, height:18, borderRadius:"50%", background:"white", boxShadow:"0 1px 2px rgba(0,0,0,.2)", transition:"left .15s"}}/>
      </button>
    </div>
  );
}

// ── Team ──────────────────────────────────────────────────────────

const ROLE_LABEL = {
  owner: "Owner", admin: "Admin", account_manager: "Account manager", viewer: "Viewer",
};

function Team({ workspace }) {
  const wid = workspace.id;
  const team = useApi(() => API.team.list(wid), [wid]);
  const allWs = useApi(() => API.workspaces.list(), []);
  const [showInvite, setShowInvite] = React.useState(false);
  const [openMemberId, setOpenMemberId] = React.useState(null);
  const [search, setSearch] = React.useState("");
  const [roleFilter, setRoleFilter] = React.useState("all");

  const members = team.data || [];
  const clientWorkspaces = (allWs.data || []).filter((w) => w.parentWorkspaceId === wid);

  const filtered = React.useMemo(() => {
    const needle = search.trim().toLowerCase();
    return members.filter((m) => {
      if (roleFilter !== "all" && m.role !== roleFilter) return false;
      if (!needle) return true;
      return (m.fullName || "").toLowerCase().includes(needle)
        || (m.email || "").toLowerCase().includes(needle);
    });
  }, [members, search, roleFilter]);

  const counts = React.useMemo(() => {
    const c = { all: members.length, owner: 0, admin: 0, account_manager: 0, viewer: 0, pending: 0 };
    for (const m of members) {
      c[m.role] = (c[m.role] || 0) + 1;
      if (!m.acceptedAt) c.pending += 1;
    }
    return c;
  }, [members]);

  return (
    <div className="page-inner wide">
      <div className="row between" style={{alignItems:"flex-start", marginBottom:24}}>
        <div>
          <div className="eyebrow">Account</div>
          <h1 className="page-title" style={{marginTop:6}}>Team & clients</h1>
          <div className="page-sub">{members.length} teammate{members.length === 1 ? "" : "s"} · scope access per workspace</div>
        </div>
        <div className="row g8">
          <button className="btn btn-primary" onClick={() => setShowInvite(true)}><I.plus size={13}/> Invite teammate</button>
        </div>
      </div>

      {team.error && <ErrorChip msg={team.error.message}/>}

      <div className="card" style={{marginBottom:16}}>
        <div className="card-h" style={{padding:"12px 16px", gap:12}}>
          <div style={{flex:1, display:"flex", alignItems:"center", gap:10, height:34, padding:"0 12px", background:"var(--bg-elev)", borderRadius:8, border:".5px solid var(--line-2)"}}>
            <I.search size={14} style={{color:"var(--ink-4)"}}/>
            <input
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              placeholder="Search by name or email…"
              style={{flex:1, border:0, outline:"none", background:"transparent", fontSize:13.5, color:"var(--ink)"}}
            />
            {search && <button className="icon-btn" style={{width:22, height:22}} onClick={() => setSearch("")}><I.x size={12}/></button>}
          </div>
          <div className="seg">
            <button className={roleFilter === "all" ? "on" : ""} onClick={() => setRoleFilter("all")}>All ({counts.all})</button>
            {counts.owner > 0 && <button className={roleFilter === "owner" ? "on" : ""} onClick={() => setRoleFilter("owner")}>Owner</button>}
            {counts.admin > 0 && <button className={roleFilter === "admin" ? "on" : ""} onClick={() => setRoleFilter("admin")}>Admin ({counts.admin})</button>}
            {counts.account_manager > 0 && <button className={roleFilter === "account_manager" ? "on" : ""} onClick={() => setRoleFilter("account_manager")}>Acct mgr ({counts.account_manager})</button>}
            {counts.viewer > 0 && <button className={roleFilter === "viewer" ? "on" : ""} onClick={() => setRoleFilter("viewer")}>Viewer ({counts.viewer})</button>}
          </div>
        </div>
        <table className="table">
          <thead><tr><th>Name</th><th>Role</th><th>Status</th><th>Last active</th><th style={{width:60}}></th></tr></thead>
          <tbody>
            {team.loading && members.length === 0 && <tr><td colSpan={5} style={{textAlign:"center", padding:30, color:"var(--ink-4)"}}>Loading…</td></tr>}
            {!team.loading && filtered.length === 0 && (
              <tr><td colSpan={5} style={{textAlign:"center", padding:30, color:"var(--ink-4)"}}>
                {search ? <>No teammates match "<strong style={{color:"var(--ink-2)"}}>{search}</strong>"</> : "No teammates yet — invite one above"}
              </td></tr>
            )}
            {filtered.map((m) => (
              <TeamMemberRow key={m.id} m={m} workspace={workspace}
                onOpen={() => setOpenMemberId(m.id)}
                onChanged={() => team.reload()}/>
            ))}
          </tbody>
        </table>
      </div>

      {clientWorkspaces.length > 0 && (
        <div className="card">
          <div className="card-h"><div><h3>Client workspaces ({clientWorkspaces.length})</h3><div className="sub">Sandboxed sub-workspaces under {workspace.name}</div></div></div>
          <div style={{padding:16, display:"grid", gridTemplateColumns:"repeat(2, 1fr)", gap:12}}>
            {clientWorkspaces.map((c) => {
              const letters = c.name.trim().split(/\s+/).slice(0, 2).map((w) => w[0]).join("").toUpperCase();
              return (
                <div key={c.id} style={{padding:"16px 18px", borderRadius:"var(--radius-lg)", background:"var(--bg-elev)", border:".5px solid var(--line)"}}>
                  <div className="row g12">
                    <div className="ws-avatar" style={{background:"linear-gradient(135deg,#F97316,#DB2777)", width:36, height:36, fontSize:13, borderRadius:9}}>{letters}</div>
                    <div style={{flex:1}}>
                      <div style={{fontSize:14, fontWeight:500, color:"var(--ink)"}}>{c.name}</div>
                      <div className="muted" style={{fontSize:12}}>Balance {fmtMoney(c.prepayBalanceCents)} · {c.numberCount || 0} number{c.numberCount === 1 ? "" : "s"}</div>
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {showInvite && <InviteModal workspace={workspace} onClose={() => setShowInvite(false)} onSaved={() => { setShowInvite(false); team.reload(); }}/>}
      {openMemberId && (
        <MemberDetailModal
          workspace={workspace}
          memberId={openMemberId}
          onClose={() => setOpenMemberId(null)}
          onChanged={() => team.reload()}
        />
      )}
    </div>
  );
}

function TeamMemberRow({ m, workspace, onOpen, onChanged }) {
  const initials = (m.fullName || m.email || "·").split(/\s+/).slice(0, 2).map((w) => w[0]).join("").toUpperCase();

  return (
    <tr style={{cursor:"pointer"}} onClick={onOpen}>
      <td>
        <div className="row g12">
          <div className="ws-avatar" style={{background:"linear-gradient(135deg,#0A84FF,#9333EA)", width:32, height:32, fontSize:13}}>{initials}</div>
          <div>
            <div style={{color:"var(--ink)", fontWeight:500}}>{m.fullName || "—"}</div>
            <div className="muted" style={{fontSize:12}}>{m.email}</div>
          </div>
        </div>
      </td>
      <td>
        <span className={"pill " + (m.role === "owner" ? "info" : "")}>{ROLE_LABEL[m.role] || m.role}</span>
      </td>
      <td>{m.acceptedAt ? <span className="pill good"><span className="dot"/>Active</span> : <span className="pill warn"><span className="dot"/>Pending</span>}</td>
      <td className="muted">{m.lastSeenAt ? fmtRelative(m.lastSeenAt) : "—"}</td>
      <td><I.chev size={14} style={{color:"var(--ink-4)"}}/></td>
    </tr>
  );
}

function MemberDetailModal({ workspace, memberId, onClose, onChanged }) {
  const wid = workspace.id;
  const detail = useApi(() => API.team.get(wid, memberId), [wid, memberId]);
  const [editingRole, setEditingRole] = React.useState(false);
  const [role, setRole] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [err, setErr] = React.useState(null);
  const [tempPassword, setTempPassword] = React.useState(null);
  const [showResetConfirm, setShowResetConfirm] = React.useState(false);

  React.useEffect(() => {
    if (detail.data) setRole(detail.data.role);
  }, [detail.data]);

  if (detail.loading || !detail.data) {
    return (
      <Modal onClose={onClose} title="Member" maxWidth={560}>
        <div style={{padding:30, textAlign:"center", color:"var(--ink-4)"}}>Loading…</div>
      </Modal>
    );
  }

  const m = detail.data;
  const isOwner = m.role === "owner";
  const initials = (m.fullName || m.email || "·").split(/\s+/).slice(0, 2).map((w) => w[0]).join("").toUpperCase();

  async function saveRole() {
    setBusy(true); setErr(null);
    try {
      await API.team.patch(wid, m.id, { role });
      setEditingRole(false);
      detail.reload(); onChanged && onChanged();
    } catch (e) { setErr(e.message); }
    finally { setBusy(false); }
  }

  async function remove() {
    const ok = await window.confirmDialog({
      title: "Remove from workspace",
      message: `${m.fullName || m.email} will lose access to ${workspace.name} immediately. They can be re-invited later.`,
      confirmLabel: "Remove",
      danger: true,
    });
    if (!ok) return;
    setBusy(true); setErr(null);
    try {
      await API.team.remove(wid, m.id);
      window.toast.success("Removed from workspace");
      onChanged && onChanged();
      onClose();
    } catch (e) { setErr(e.message); setBusy(false); }
  }

  async function resetPassword() {
    setBusy(true); setErr(null);
    try {
      const res = await API.team.resetPassword(wid, m.id);
      setTempPassword(res.data.tempPassword);
      setShowResetConfirm(false);
    } catch (e) { setErr(e.message); }
    finally { setBusy(false); }
  }

  return (
    <Modal onClose={onClose} title={null} maxWidth={560}>
      <div className="col g16">
        {/* Header */}
        <div className="row g12" style={{paddingBottom:14, borderBottom:".5px solid var(--line)"}}>
          <div className="ws-avatar" style={{background:"linear-gradient(135deg,#0A84FF,#9333EA)", width:48, height:48, fontSize:16, borderRadius:10}}>{initials}</div>
          <div style={{flex:1, minWidth:0}}>
            <div className="serif" style={{fontSize:22, color:"var(--ink)", letterSpacing:"-0.01em"}}>{m.fullName || "—"}</div>
            <div className="muted" style={{fontSize:13}}>{m.email}</div>
          </div>
        </div>

        {err && <ErrorChip msg={err}/>}

        {/* Reset-password result */}
        {tempPassword && (
          <div style={{padding:14, background:"rgba(16,185,129,.1)", border:".5px solid rgba(16,185,129,.3)", borderRadius:8}}>
            <div style={{fontSize:12.5, color:"var(--ink-2)", marginBottom:8}}>
              Temporary password for <strong>{m.email}</strong>. Copy and share it securely — it won't be shown again.
            </div>
            <div className="row g8">
              <div className="mono" style={{flex:1, padding:"10px 12px", background:"var(--panel)", borderRadius:6, fontSize:13, color:"var(--ink)", letterSpacing:"0.05em"}}>{tempPassword}</div>
              <button className="btn btn-secondary btn-sm" onClick={() => navigator.clipboard?.writeText(tempPassword)}>Copy</button>
            </div>
          </div>
        )}

        {/* Profile */}
        <div className="card-b col g12" style={{fontSize:13.5, padding:0}}>
          <KVRow k="Role">
            {editingRole && !isOwner ? (
              <div className="row g4">
                <select className="select" style={{height:28, fontSize:12}} value={role} onChange={(e) => setRole(e.target.value)}>
                  <option value="admin">Admin</option>
                  <option value="account_manager">Account manager</option>
                  <option value="viewer">Viewer</option>
                </select>
                <button className="btn btn-primary btn-sm" onClick={saveRole} disabled={busy}>Save</button>
                <button className="btn btn-ghost btn-sm" onClick={() => { setEditingRole(false); setRole(m.role); }}>Cancel</button>
              </div>
            ) : (
              <div className="row g8">
                <span className={"pill " + (m.role === "owner" ? "info" : "")}>{ROLE_LABEL[m.role] || m.role}</span>
                {!isOwner && <button className="btn btn-ghost btn-sm" onClick={() => setEditingRole(true)}>Change</button>}
              </div>
            )}
          </KVRow>
          <KVRow k="Status">
            {m.acceptedAt
              ? <span className="pill good"><span className="dot"/>Active</span>
              : <span className="pill warn"><span className="dot"/>Pending invite</span>}
          </KVRow>
          <KVRow k="Last active">{m.lastSeenAt ? fmtRelative(m.lastSeenAt) : "Never"}</KVRow>
          <KVRow k="Joined">{m.acceptedAt ? new Date(m.acceptedAt).toLocaleDateString() : "—"}</KVRow>
          <KVRow k="2FA">{m.twoFactorEnabled ? <span className="pill good">Enabled</span> : <span className="muted">Off</span>}</KVRow>
          <KVRow k="Email verified">{m.emailVerifiedAt ? "Yes" : <span className="muted">No</span>}</KVRow>
        </div>

        {/* Activity */}
        {m.stats && (m.stats.callsAssigned || m.stats.notesAuthored || m.stats.tagsAdded) ? (
          <div>
            <div style={{fontSize:11, fontWeight:600, letterSpacing:".06em", textTransform:"uppercase", color:"var(--ink-4)", marginBottom:8}}>
              Activity in this workspace
            </div>
            <div style={{display:"grid", gridTemplateColumns:"repeat(3, 1fr)", gap:8}}>
              <Stat lbl="Calls assigned" v={m.stats.callsAssigned}/>
              <Stat lbl="Notes authored" v={m.stats.notesAuthored}/>
              <Stat lbl="Tags added" v={m.stats.tagsAdded}/>
            </div>
          </div>
        ) : null}

        {/* Other workspaces */}
        {m.otherWorkspaces && m.otherWorkspaces.length > 0 && (
          <div>
            <div style={{fontSize:11, fontWeight:600, letterSpacing:".06em", textTransform:"uppercase", color:"var(--ink-4)", marginBottom:8}}>
              Other workspaces ({m.otherWorkspaces.length})
            </div>
            <div className="col g4">
              {m.otherWorkspaces.map((w) => (
                <div key={w.id} className="row between" style={{padding:"8px 10px", background:"var(--bg-sunken)", borderRadius:6, fontSize:13}}>
                  <span style={{color:"var(--ink-2)"}}>{w.name}</span>
                  <span className="pill" style={{height:18, fontSize:10}}>{ROLE_LABEL[w.role] || w.role}</span>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* Actions */}
        <div className="row between" style={{paddingTop:12, borderTop:".5px solid var(--line)"}}>
          <div className="row g8">
            {!isOwner && (
              <button className="btn btn-secondary btn-sm" onClick={() => setShowResetConfirm(true)} disabled={busy}>
                Reset password
              </button>
            )}
          </div>
          <div className="row g8">
            <button className="btn btn-ghost btn-sm" onClick={onClose}>Close</button>
            {!isOwner && (
              <button className="btn btn-ghost btn-sm" style={{color:"var(--bad)"}} onClick={remove} disabled={busy}>
                Remove from workspace
              </button>
            )}
          </div>
        </div>

        {showResetConfirm && (
          <div style={{padding:14, background:"rgba(245,158,11,.08)", border:".5px solid rgba(245,158,11,.3)", borderRadius:8}}>
            <div style={{fontSize:13, color:"var(--ink-2)", marginBottom:10}}>
              Reset {m.email}'s password? They'll be logged out everywhere and you'll get a one-time temporary password to share with them.
            </div>
            <div className="row g8" style={{justifyContent:"flex-end"}}>
              <button className="btn btn-ghost btn-sm" onClick={() => setShowResetConfirm(false)} disabled={busy}>Cancel</button>
              <button className="btn btn-primary btn-sm" onClick={resetPassword} disabled={busy}>
                {busy ? "Resetting…" : "Reset password"}
              </button>
            </div>
          </div>
        )}
      </div>
    </Modal>
  );
}

function KVRow({ k, children }) {
  return (
    <div className="row between" style={{minHeight:32, alignItems:"center"}}>
      <div style={{color:"var(--ink-4)", fontSize:12.5}}>{k}</div>
      <div style={{color:"var(--ink)", fontWeight:500}}>{children}</div>
    </div>
  );
}

function Stat({ lbl, v }) {
  return (
    <div style={{padding:"10px 12px", background:"var(--bg-sunken)", borderRadius:8}}>
      <div className="muted" style={{fontSize:11}}>{lbl}</div>
      <div className="num" style={{fontSize:18, color:"var(--ink)", fontWeight:500, marginTop:2}}>{v ?? 0}</div>
    </div>
  );
}

function InviteModal({ workspace, onClose, onSaved }) {
  const [email, setEmail] = React.useState("");
  const [role, setRole] = React.useState("viewer");
  const [submitting, setSubmitting] = React.useState(false);
  const [error, setError] = React.useState(null);

  async function submit(e) {
    e.preventDefault();
    setSubmitting(true); setError(null);
    try {
      await API.team.invite(workspace.id, { email: email.trim(), role });
      onSaved && onSaved();
    } catch (err) { setError(err.message); }
    finally { setSubmitting(false); }
  }

  return (
    <Modal onClose={onClose} title="Invite teammate">
      <form onSubmit={submit} className="col g16">
        <div className="field"><label>Email</label>
          <input className="input" type="email" required value={email} onChange={(e) => setEmail(e.target.value)} autoFocus placeholder="teammate@example.com"/>
        </div>
        <div className="field"><label>Role</label>
          <select className="select" value={role} onChange={(e) => setRole(e.target.value)}>
            <option value="admin">Admin</option>
            <option value="account_manager">Account manager</option>
            <option value="viewer">Viewer</option>
          </select>
        </div>
        <div style={{fontSize:12, color:"var(--ink-4)"}}>
          The invitee must already have a Call tracking account. They'll see the workspace appear in their switcher.
        </div>
        {error && <ErrorChip msg={error}/>}
        <div className="row g8" style={{justifyContent:"flex-end"}}>
          <button type="button" className="btn btn-ghost btn-sm" onClick={onClose}>Cancel</button>
          <button type="submit" className="btn btn-primary btn-sm" disabled={submitting}>
            {submitting ? "Inviting…" : "Send invite"}
          </button>
        </div>
      </form>
    </Modal>
  );
}

// ── Modal ─────────────────────────────────────────────────────────

function Modal({ children, onClose, title, maxWidth = 440 }) {
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onClose && onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onClose]);

  return (
    <div
      onClick={onClose}
      style={{position:"fixed", inset:0, background:"rgba(0,0,0,.4)", zIndex:100, display:"grid", placeItems:"center", padding:20, animation:"fadeSlide .12s", overflowY:"auto"}}>
      <div onClick={(e) => e.stopPropagation()}
        style={{background:"var(--panel)", borderRadius:"var(--radius-lg)", boxShadow:"var(--shadow-lg)", border:".5px solid var(--line)", width:"100%", maxWidth, padding:24, animation:"fadeSlide .15s", maxHeight:"calc(100vh - 40px)", overflowY:"auto"}}>
        {title && <h2 className="serif" style={{fontSize:22, marginBottom:16, fontWeight:400}}>{title}</h2>}
        {children}
      </div>
    </div>
  );
}

Object.assign(window, { Campaigns, Routing, RoutingList, RoutingEditor, FlowCard, FlowArrow, FlowAddStep, IvrEditor, PhoneInput, Team, MemberDetailModal, KVRow, Stat, Modal, Toggle, channelLabel, fmtMoney });
