/* ============================================================================
   DIVONCI WORLD — VIIERA COMMAND CONSOLE  (screens_viiera_console.jsx)
   ----------------------------------------------------------------------------
   Viiera's control plane over the entire Council's voice. An agent switcher
   scopes the per-agent tabs (Profile, Rules, Templates, Tests, Logs). Phrase
   Controls are Council-wide policy; Versions are Viiera-gated — publishing any
   agent's persona routes through her authority. Backed by 8 Supabase tables
   (project bdiknyzwfgucnlvvyzbs) through the DW.* seam. Every read flows through
   useResource()/DW.get; every write through DW.mutate. Destructive actions are
   confirm-gated; failures surface as toasts.
   ========================================================================== */
const { useState: useStateV, useEffect: useEffectV, useMemo: useMemoV, useRef: useRefV } = React;

/* ── option vocabularies (mirror the table CHECK constraints) ─────────────── */
const RULE_TYPES   = ["must", "should", "never", "style", "fallback"];
const CONTROL_TYPES = ["banned", "avoid", "preferred", "required"];
const SEVERITIES   = ["critical", "high", "medium", "low"];
const PROFILE_STATUS = ["draft", "staging", "live", "archived"];
const TONES = ["warm", "precise", "commanding", "urgent", "firm"];
const COUNCIL_ORDER = ["viiera", "nova", "claws", "brodex", "vv", "optimus"];

/* sample values used to render intent-template previews */
const VC_SAMPLE = {
  name: "Diego", salutation: "Evening", council_state: "steady — one threat held",
  live_count: "3", held_count: "1", top_priority: "clear deploy #A7F2",
  recommendation: "Hold until BroDex closes the dual-reasoning.",
  deploy_id: "#A7F2", verdict: "held", reason: "BroDex flagged a dependency origin.",
  threat: "Threat signature confirmed", target: "external dependency",
  alternative: "stage it behind a flag and route to BroDex", question: "which surface — hero, nav, or banner?",
  agent: "Claws", topic: "the launch film", safe: "a product montage", strong: "one operator's day end to end",
  wild: "narrate it as the Council waking up", premise: "we shipped with no homepage", assumption: "that a launch needs a page",
  headline: "Divonci World is live", body: "The command OS for agencies.", route: "Eagle",
  changes: "Cut two intensifiers and the filler line.", outcome: "reads in half the words",
  claim: "the dependency is safe", confidence: "medium", for: "signed releases", against: "one unverified origin", sources: "SBOM, registry",
  signature: "typosquat origin", action: "hold the deploy", status: "validated", detail: "Build green, preview up.",
  task: "spin up the build agents", scope: "build + test only", cycle: "Cycle 12", metric: "frame time", delta: "18%", before: "42ms", after: "34ms", next: "shader cache warming",
};

/* tiny helpers */
function vcCommaList(v) { return Array.isArray(v) ? v.join(", ") : (v || ""); }
function vcParseList(s) { return String(s || "").split(",").map((x) => x.trim()).filter(Boolean); }
function vcDate(iso) { if (!iso) return "—"; const d = new Date(iso); return d.toLocaleDateString(undefined, { month: "short", day: "numeric" }) + " · " + d.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" }); }
function vcJSON(v) { try { return JSON.stringify(v, null, 2); } catch (e) { return "{}"; } }
function agentName(slug) { if (slug === "council") return "Council"; const a = DW.agent(slug); return a ? a.name : slug; }
function agentColor(slug) { if (slug === "council") return "var(--gold-bright)"; const a = DW.agent(slug); return a ? a.ac : "var(--violet-bright)"; }

/* ── TOAST ─────────────────────────────────────────────────────────────────── */
function useToasts() {
  const [toasts, setToasts] = useStateV([]);
  const push = (msg, tone = "ok") => {
    const id = Math.random().toString(36).slice(2);
    setToasts((t) => [...t, { id, msg, tone }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3600);
  };
  const node = (
    <div className="vc-toasts">
      {toasts.map((t) => (
        <div key={t.id} className="vc-toast" data-tone={t.tone}>
          <span className="led" style={{ background: t.tone === "err" ? "var(--state-crisis)" : t.tone === "gold" ? "var(--gold-bright)" : "var(--state-clear)", color: t.tone === "err" ? "var(--state-crisis)" : t.tone === "gold" ? "var(--gold-bright)" : "var(--state-clear)" }} />
          {t.msg}
        </div>
      ))}
    </div>
  );
  return { push, node };
}

/* ── CONFIRM MODAL (desktop) ──────────────────────────────────────────────── */
function ConfirmModal({ open, title, desc, confirmLabel, tone = "danger", icon = "risk", note, onConfirm, onCancel, busy }) {
  if (!open) return null;
  return (
    <div className="vc-modal-scrim" onClick={onCancel}>
      <div className="vc-modal" role="dialog" aria-modal="true" onClick={(e) => e.stopPropagation()}>
        <div className={"vc-modal-ic " + tone}><Icon name={icon} className="glyph" style={{ width: 22, height: 22 }} /></div>
        <div className="vc-modal-t">{title}</div>
        <div className="vc-modal-d">{desc}</div>
        {note && <div className="vc-gate-note" style={{ marginBottom: "var(--s-6)" }}><Icon name="crown" className="glyph" style={{ width: 13, height: 13 }} /> {note}</div>}
        <div className="vc-modal-act">
          <button className="btn ghost" onClick={onCancel} disabled={busy}>Cancel</button>
          <button className={"btn " + (tone === "gold" ? "gold" : "danger")} onClick={onConfirm} disabled={busy}>{busy ? "Working…" : confirmLabel}</button>
        </div>
      </div>
    </div>
  );
}

/* ── shared field primitives ──────────────────────────────────────────────── */
function VField({ label, hint, children }) {
  return <div className="vc-field"><label>{label}</label>{children}{hint && <div className="hint">{hint}</div>}</div>;
}
function VChoice({ value, options, onChange }) {
  return (
    <div className="vc-choice">
      {options.map((o) => <button key={o} type="button" className={value === o ? "on" : ""} onClick={() => onChange(o)}>{o}</button>)}
    </div>
  );
}
function VToggle({ on, label, onClick }) {
  return <button type="button" className={"vc-toggle " + (on ? "on" : "")} onClick={onClick}><span className="vc-switch" />{label || (on ? "Enabled" : "Disabled")}</button>;
}
function TypeChip({ k }) { return <span className="vc-chip" data-k={k}>{k}</span>; }
function SevChip({ s }) { return <span className="vc-sev" data-s={s}><i style={{ background: "currentColor" }} />{s}</span>; }
function ScopeChip({ slug }) {
  if (slug === "council") return <span className="vc-chip" data-k="required">council</span>;
  return <span className="vc-scope" style={{ "--c": agentColor(slug) }}><i />{agentName(slug)}</span>;
}

/* drawer shell reused by every editor */
function VDrawer({ title, sub, accent, onClose, children }) {
  return (
    <>
      <div className="dw-drawer-scrim" onClick={onClose} />
      <aside className="dw-drawer" role="dialog" aria-label={title}>
        <div className="dw-drawer-head">
          <div style={{ width: 34, height: 34, borderRadius: "var(--r-md)", background: "linear-gradient(150deg, " + (accent || "var(--violet-bright)") + ", var(--violet-deep))", display: "grid", placeItems: "center", boxShadow: "var(--glow-violet)", flex: "none" }}>
            <Icon name="crown" style={{ width: 16, height: 16, color: "#fff" }} />
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 17 }}>{title}</div>
            {sub && <div style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--ink-3)", letterSpacing: "0.04em" }}>{sub}</div>}
          </div>
          <button className="dw-drawer-x" onClick={onClose} aria-label="Close"><Icon name="close" style={{ width: 16, height: 16 }} /></button>
        </div>
        <div className="dw-drawer-body">{children}</div>
      </aside>
    </>
  );
}

/* JSON textarea with live validation */
function VJsonField({ label, hint, value, onChange }) {
  const [txt, setTxt] = useStateV(() => vcJSON(value));
  const [err, setErr] = useStateV(null);
  useEffectV(() => { setTxt(vcJSON(value)); setErr(null); }, [value]);
  function handle(v) {
    setTxt(v);
    try { const parsed = JSON.parse(v); setErr(null); onChange(parsed); }
    catch (e) { setErr(e.message.replace(/^JSON\.parse:\s*/, "")); }
  }
  const rows = Math.min(16, Math.max(5, txt.split("\n").length + 1));
  return (
    <div className="vc-field">
      <label>{label}</label>
      <textarea className={"code" + (err ? " vc-json-bad" : "")} value={txt} onChange={(e) => handle(e.target.value)} rows={rows} spellCheck={false} />
      {err ? <div className="vc-json-err">Invalid JSON · {err}</div> : hint && <div className="hint">{hint}</div>}
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   1 · PROFILE  (scoped to selected agent)
══════════════════════════════════════════════════════════════════════════════ */
function ProfileTab({ admin, push, agentSlug, isViiera, profiles, refetch, cfg }) {
  const active = useMemoV(() => {
    if (!profiles || !profiles.length) return null;
    if (cfg && cfg.active_profile_id) return profiles.find((p) => p.id === cfg.active_profile_id) || profiles[0];
    return profiles.find((p) => p.status === "live") || profiles[0];
  }, [profiles, cfg]);

  const [sel, setSel] = useStateV(null);
  const current = sel ? profiles.find((p) => p.id === sel) || active : active;
  const [form, setForm] = useStateV(null);
  const [saving, setSaving] = useStateV(false);
  const [confirm, setConfirm] = useStateV(null);

  useEffectV(() => { if (current) setForm(JSON.parse(JSON.stringify(current))); }, [current && current.id]);
  if (!current || !form) return <EmptyState icon="crown" title={"No persona for " + agentName(agentSlug)} hint="No profile rows exist for this agent yet." />;

  const dirty = JSON.stringify(form) !== JSON.stringify(current);
  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));

  function save() {
    setSaving(true);
    DW.mutate("update", { resource: "viiera_persona_profiles", id: form.id, patch: { ...form, updated_at: new Date().toISOString() } })
      .then(() => { push("Profile saved · " + form.name); refetch(); })
      .catch((e) => push("Save failed · " + e.message, "err"))
      .finally(() => setSaving(false));
  }
  function goLive() {
    setSaving(true);
    DW.mutate("viiera.setProfileStatus", { id: form.id, status: "live" })
      .then(() => { push("“" + form.name + "” is now LIVE", "gold"); refetch(); setConfirm(null); })
      .catch((e) => { push("Publish failed · " + e.message, "err"); setConfirm(null); })
      .finally(() => setSaving(false));
  }

  return (
    <div className="cols c-12-4" style={{ alignItems: "start" }}>
      {/* editor */}
      <Panel style={{ padding: "var(--s-7)" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: "var(--s-6)", flexWrap: "wrap" }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--violet-ink)" }}>{agentName(agentSlug)} · active profile</div>
          <span className="vc-status" data-st={form.status}><span className="led" />{form.status}</span>
          <div style={{ flex: 1 }} />
          <select className="vc-input" value={current.id} onChange={(e) => setSel(e.target.value)} aria-label="Switch profile">
            {profiles.map((p) => <option key={p.id} value={p.id}>{p.name} · {p.status}</option>)}
          </select>
        </div>

        {!isViiera && <div className="vc-policy-note gold" style={{ marginBottom: "var(--s-6)" }}><Icon name="crown" className="glyph" style={{ width: 14, height: 14 }} /> Governed under Viiera. The Council-wide safety contract and global rules apply on top of this profile.</div>}

        <div className="vc-form">
          <div className="vc-field-row">
            <VField label="Profile name"><input type="text" value={form.name} disabled={!admin} onChange={(e) => set("name", e.target.value)} /></VField>
            <VField label="Slug" hint="Stable key the Worker uses to resolve this persona."><input type="text" className="code" value={form.slug} disabled={!admin} onChange={(e) => set("slug", e.target.value)} /></VField>
          </div>
          <VField label="Description"><textarea value={form.description} disabled={!admin} onChange={(e) => set("description", e.target.value)} rows={2} /></VField>
          <VField label="Base identity" hint="Who this agent is in this profile — folded into the system prompt."><textarea value={form.base_identity} disabled={!admin} onChange={(e) => set("base_identity", e.target.value)} rows={3} /></VField>
          <VField label="Voice summary"><textarea value={form.voice_summary} disabled={!admin} onChange={(e) => set("voice_summary", e.target.value)} rows={2} /></VField>
          <VField label="System prompt" hint="The full instruction block sent to the model."><textarea className="code" value={form.system_prompt} disabled={!admin} onChange={(e) => set("system_prompt", e.target.value)} rows={10} spellCheck={false} /></VField>
          <div className="vc-field-row">
            <VJsonField label="Model settings" hint="model · temperature · top_p · max_tokens" value={form.model_settings} onChange={(v) => set("model_settings", v)} />
            <VJsonField label="Safety contract" hint="never_reveal · refuse · escalate_on · require_human_for" value={form.safety_contract} onChange={(v) => set("safety_contract", v)} />
          </div>
        </div>

        <div className="vc-drawer-foot" style={{ position: "static", margin: "var(--s-7) 0 0", background: "none" }}>
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 10.5, color: dirty ? "var(--state-caution)" : "var(--ink-4)" }}>{dirty ? "● Unsaved changes" : "Saved · " + vcDate(form.updated_at)}</span>
          <span className="vc-spacer" />
          {form.status !== "live" && <button className="btn gold" disabled={!admin} onClick={() => setConfirm("live")}><Icon name="lock" className="glyph" style={{ width: 14, height: 14 }} /> Set live</button>}
          <button className="btn" disabled={!dirty} onClick={() => setForm(JSON.parse(JSON.stringify(current)))}>Revert</button>
          <button className="btn primary" disabled={!admin || !dirty || saving} onClick={save}><Icon name="check" className="glyph" style={{ width: 14, height: 14 }} /> {saving ? "Saving…" : "Save profile"}</button>
        </div>
      </Panel>

      {/* meta rail */}
      <div style={{ display: "grid", gap: "var(--s-6)" }}>
        <Panel className="tight">
          <PHead icon="crown" eyebrow={agentName(agentSlug) + " · profiles"} />
          <div className="pbody" style={{ display: "grid", gap: 8 }}>
            {profiles.map((p) => { const ag = DW.agent(p.agent_slug) || {}; return (
              <button key={p.id} onClick={() => setSel(p.id)} style={{ display: "flex", alignItems: "center", gap: 10, textAlign: "left", cursor: "pointer", background: p.id === current.id ? "var(--panel-3)" : "var(--panel-2)", border: "1px solid var(--hairline-2)", borderRadius: "var(--r-md)", padding: "10px 12px", color: "var(--ink)" }}>
                <span title={ag.name} style={{ width: 30, height: 30, borderRadius: "var(--r-sm)", flex: "none", backgroundImage: ag.head ? "url(" + ag.head + ")" : "none", backgroundColor: "var(--graphite)", backgroundSize: "cover", backgroundPosition: "center", boxShadow: "0 0 0 1px " + (ag.ac || "var(--hairline-2)") + ", inset 0 0 0 1px rgba(0,0,0,0.3)" }} />
                <span style={{ minWidth: 0, flex: 1 }}>
                  <span style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 }}>
                    <span style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 13.5 }}>{p.name}</span>
                    <span className="vc-status" data-st={p.status} style={{ padding: "3px 8px", fontSize: 9 }}><span className="led" />{p.status}</span>
                  </span>
                  <span style={{ display: "block", fontFamily: "var(--font-mono)", fontSize: 9.5, color: "var(--ink-4)", marginTop: 4 }}>{(ag.name || p.agent_slug) + " · " + p.slug}</span>
                </span>
              </button>
            ); })}
          </div>
        </Panel>
        <Panel style={{ padding: "var(--s-6)" }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--violet-ink)", marginBottom: 12 }}>Live config</div>
          <dl className="vc-kv">
            <dt>Agent</dt><dd>{agentName(agentSlug)}</dd>
            <dt>Active slug</dt><dd style={{ fontFamily: "var(--font-mono)", fontSize: 12, color: "var(--violet-ink)" }}>{cfg ? cfg.active_profile_slug : "—"}</dd>
            <dt>Version</dt><dd style={{ fontFamily: "var(--font-mono)", fontSize: 12 }}>{cfg ? cfg.active_version_id : "—"}</dd>
            <dt>Status</dt><dd><span className="vc-status" data-st={cfg ? cfg.status : "draft"} style={{ padding: "3px 9px", fontSize: 9 }}><span className="led" />{cfg ? cfg.status : "—"}</span></dd>
            <dt>Updated</dt><dd style={{ fontFamily: "var(--font-mono)", fontSize: 11.5, color: "var(--ink-3)" }}>{cfg ? vcDate(cfg.updated_at) : "—"}</dd>
          </dl>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: 9.5, color: "var(--ink-4)", marginTop: 12, lineHeight: 1.5 }}>⇄ viiera_live_persona_config · one active pointer per agent the Worker reads on boot.</div>
        </Panel>
      </div>

      <ConfirmModal open={confirm === "live"} tone="gold" icon="lock" busy={saving}
        title={"Set “" + form.name + "” live?"} confirmLabel="Yes, set live"
        desc={"This becomes " + agentName(agentSlug) + "'s live persona. Any other live profile for this agent drops to staging."}
        note={!isViiera ? "Routes through Viiera's authority — she holds the publish gate." : null}
        onCancel={() => setConfirm(null)} onConfirm={goLive} />
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   2 · RESPONSE RULES  (council-wide + per-agent)
══════════════════════════════════════════════════════════════════════════════ */
function RuleEditor({ admin, push, row, agentSlug, onClose, refetch }) {
  const isNew = !row.id;
  const [f, setF] = useStateV(() => ({ rule_key: "", category: "Style", priority: 10, applies_to_intents: ["*"], rule_type: "should", rule_text: "", is_enabled: true, agent_slug: agentSlug, ...row }));
  const [saving, setSaving] = useStateV(false);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  function save() {
    if (!f.rule_key.trim() || !f.rule_text.trim()) return push("Rule key and text are required", "err");
    setSaving(true);
    const patch = { ...f, priority: Number(f.priority) || 0, applies_to_intents: Array.isArray(f.applies_to_intents) ? f.applies_to_intents : vcParseList(f.applies_to_intents) };
    const op = isNew ? DW.mutate("create", { resource: "viiera_response_rules", row: patch }) : DW.mutate("update", { resource: "viiera_response_rules", id: f.id, patch });
    op.then(() => { push(isNew ? "Rule created" : "Rule saved"); refetch(); onClose(); })
      .catch((e) => push("Save failed · " + e.message, "err")).finally(() => setSaving(false));
  }
  return (
    <VDrawer title={isNew ? "New response rule" : f.rule_key} sub={isNew ? "viiera_response_rules" : "rule · " + f.rule_type} accent={agentColor(f.agent_slug)} onClose={onClose}>
      <div className="vc-form">
        <VField label="Scope" hint="Council-wide applies to every agent; agent scope applies to one."><VChoice value={f.agent_slug} options={["council", agentSlug === "council" ? "viiera" : agentSlug]} onChange={(v) => set("agent_slug", v)} /></VField>
        <div className="vc-field-row three">
          <VField label="Rule key" hint="snake_case, unique"><input type="text" className="code" value={f.rule_key} disabled={!admin} onChange={(e) => set("rule_key", e.target.value)} /></VField>
          <VField label="Category"><input type="text" value={f.category} disabled={!admin} onChange={(e) => set("category", e.target.value)} /></VField>
          <VField label="Priority" hint="lower = higher authority"><input type="number" value={f.priority} disabled={!admin} onChange={(e) => set("priority", e.target.value)} /></VField>
        </div>
        <VField label="Rule type"><VChoice value={f.rule_type} options={RULE_TYPES} onChange={(v) => set("rule_type", v)} /></VField>
        <VField label="Applies to intents" hint="comma-separated intent keys · use * for all"><input type="text" className="code" value={vcCommaList(f.applies_to_intents)} disabled={!admin} onChange={(e) => set("applies_to_intents", vcParseList(e.target.value))} /></VField>
        <VField label="Rule text"><textarea value={f.rule_text} disabled={!admin} onChange={(e) => set("rule_text", e.target.value)} rows={4} /></VField>
        <VField label="State"><VToggle on={f.is_enabled} onClick={() => admin && set("is_enabled", !f.is_enabled)} /></VField>
      </div>
      <div className="vc-drawer-foot">
        <button className="btn ghost" onClick={onClose}>Cancel</button>
        <span className="vc-spacer" />
        <button className="btn primary" disabled={!admin || saving} onClick={save}><Icon name="check" className="glyph" style={{ width: 14, height: 14 }} /> {saving ? "Saving…" : isNew ? "Create rule" : "Save rule"}</button>
      </div>
    </VDrawer>
  );
}

function RulesTab({ admin, push, agentSlug, isViiera }) {
  const q = useResource("viiera_response_rules", { sort: { key: "priority", dir: "asc" } });
  const [edit, setEdit] = useStateV(null);
  const [del, setDel] = useStateV(null);
  const [scope, setScope] = useStateV("agent"); // agent | council | all
  const [busy, setBusy] = useStateV(false);

  function toggle(r) {
    DW.mutate("update", { resource: "viiera_response_rules", id: r.id, patch: { is_enabled: !r.is_enabled } })
      .then(() => { push(r.rule_key + (r.is_enabled ? " disabled" : " enabled"), r.is_enabled ? "err" : "ok"); q.refetch(); })
      .catch((e) => push("Failed · " + e.message, "err"));
  }
  function doDelete() {
    setBusy(true);
    DW.mutate("remove", { resource: "viiera_response_rules", id: del.id })
      .then(() => { push("Rule deleted · " + del.rule_key); q.refetch(); setDel(null); })
      .catch((e) => push("Delete failed · " + e.message, "err")).finally(() => setBusy(false));
  }

  if (q.loading) return <LoadingState lines={6} label="Loading response rules" />;
  if (q.error) return <ErrorState error={q.error} onRetry={q.refetch} />;
  const all = q.data || [];
  let rows = all;
  if (scope === "agent") rows = all.filter((r) => r.agent_slug === agentSlug);
  else if (scope === "council") rows = all.filter((r) => r.agent_slug === "council");
  else rows = all.filter((r) => r.agent_slug === agentSlug || r.agent_slug === "council");

  return (
    <Panel className="tight">
      <PHead icon="shield" eyebrow="Response rules · ordered by priority"
        right={<div className="vc-toolbar">
          <div className="seg">
            <button className={scope === "agent" ? "on" : ""} onClick={() => setScope("agent")}>{agentName(agentSlug)}</button>
            <button className={scope === "council" ? "on" : ""} onClick={() => setScope("council")}>Council</button>
            <button className={scope === "all" ? "on" : ""} onClick={() => setScope("all")}>All</button>
          </div>
          <button className="btn primary" disabled={!admin} onClick={() => setEdit({})}><Icon name="plus" className="glyph" /> New rule</button>
        </div>} />
      {scope !== "agent" && <div className="vc-policy-note gold"><Icon name="crown" className="glyph" style={{ width: 14, height: 14 }} /> Council-wide rules are Viiera-owned policy and apply to every agent's responses.</div>}
      {rows.length === 0 ? <EmptyState icon="shield" title="No rules in this scope" hint="Switch scope or add a new rule." /> : (
        <table className="vc-tbl">
          <thead><tr><th>Pri</th><th>Key</th><th>Scope</th><th>Type</th><th>Applies to</th><th>Rule</th><th>State</th><th></th></tr></thead>
          <tbody>
            {rows.map((r) => (
              <tr key={r.id} className={r.is_enabled ? "" : "vc-disabled"} onClick={() => setEdit(r)}>
                <td className="num" data-th="Pri">{r.priority}</td>
                <td className="mono" data-th="Key">{r.rule_key}</td>
                <td data-th="Scope"><ScopeChip slug={r.agent_slug} /></td>
                <td data-th="Type"><TypeChip k={r.rule_type} /></td>
                <td data-th="Applies to"><div className="vc-vars">{(r.applies_to_intents || []).slice(0, 3).map((i, n) => <span key={n} className="vc-key">{i}</span>)}{(r.applies_to_intents || []).length > 3 && <span className="vc-var">+{r.applies_to_intents.length - 3}</span>}</div></td>
                <td className="vc-cellwrap" data-th="Rule"><div className="clamp2">{r.rule_text}</div></td>
                <td data-th="State" onClick={(e) => e.stopPropagation()}><VToggle on={r.is_enabled} onClick={() => admin && toggle(r)} /></td>
                <td onClick={(e) => e.stopPropagation()} data-th=""><div className="vc-rowacts"><button className="vc-iconbtn danger" disabled={!admin} title="Delete" onClick={() => setDel(r)}><Icon name="close" className="glyph" style={{ width: 14, height: 14 }} /></button></div></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
      {edit && <RuleEditor admin={admin} push={push} row={edit} agentSlug={isViiera ? "council" : agentSlug} onClose={() => setEdit(null)} refetch={q.refetch} />}
      <ConfirmModal open={!!del} busy={busy} title="Delete this rule?" confirmLabel="Delete rule"
        desc={del ? "“" + del.rule_key + "” will be removed from the response policy. This cannot be undone." : ""}
        onCancel={() => setDel(null)} onConfirm={doDelete} />
    </Panel>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   3 · INTENT TEMPLATES  (per agent)
══════════════════════════════════════════════════════════════════════════════ */
function renderTemplate(body) {
  const parts = String(body || "").split(/(\{\{\s*[\w.]+\s*\}\})/g);
  return parts.map((p, i) => {
    const m = p.match(/\{\{\s*([\w.]+)\s*\}\}/);
    if (m) { const key = m[1]; return <span key={i} className="fill">{VC_SAMPLE[key] != null ? VC_SAMPLE[key] : "{" + key + "}"}</span>; }
    return <span key={i}>{p}</span>;
  });
}
function TemplateEditor({ admin, push, row, agentSlug, onClose, refetch }) {
  const isNew = !row.id;
  const [f, setF] = useStateV(() => ({ intent_key: "", template_name: "", tone: "precise", template_body: "", variables: [], is_default: false, is_enabled: true, agent_slug: agentSlug, ...row }));
  const [saving, setSaving] = useStateV(false);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  const autoVars = useMemoV(() => { const s = new Set(); (String(f.template_body).match(/\{\{\s*([\w.]+)\s*\}\}/g) || []).forEach((m) => s.add(m.replace(/[{}\s]/g, ""))); return [...s]; }, [f.template_body]);
  function save() {
    if (!f.intent_key.trim() || !f.template_body.trim()) return push("Intent key and body are required", "err");
    setSaving(true);
    const patch = { ...f, variables: autoVars };
    const op = isNew ? DW.mutate("create", { resource: "viiera_intent_templates", row: patch }) : DW.mutate("update", { resource: "viiera_intent_templates", id: f.id, patch });
    op.then(() => { push(isNew ? "Template created" : "Template saved"); refetch(); onClose(); })
      .catch((e) => push("Save failed · " + e.message, "err")).finally(() => setSaving(false));
  }
  return (
    <VDrawer title={isNew ? "New intent template" : f.template_name || f.intent_key} sub={agentName(agentSlug) + " · intent " + (f.intent_key || "—")} accent={agentColor(agentSlug)} onClose={onClose}>
      <div className="vc-form">
        <div className="vc-field-row three">
          <VField label="Intent key" hint="snake_case"><input type="text" className="code" value={f.intent_key} disabled={!admin} onChange={(e) => set("intent_key", e.target.value)} /></VField>
          <VField label="Template name"><input type="text" value={f.template_name} disabled={!admin} onChange={(e) => set("template_name", e.target.value)} /></VField>
          <VField label="Tone"><select value={f.tone} disabled={!admin} onChange={(e) => set("tone", e.target.value)}>{TONES.map((t) => <option key={t} value={t}>{t}</option>)}</select></VField>
        </div>
        <VField label="Template body" hint="Use {{variable}} for substitutions — variables are detected automatically."><textarea className="code" value={f.template_body} disabled={!admin} onChange={(e) => set("template_body", e.target.value)} rows={5} spellCheck={false} /></VField>
        <VField label="Detected variables"><div className="vc-vars">{autoVars.length ? autoVars.map((v) => <span key={v} className="vc-var">{v}</span>) : <span className="hint">none</span>}</div></VField>
        <VField label="Preview · sample values"><div className="vc-preview">{renderTemplate(f.template_body)}</div></VField>
        <div className="vc-field-row">
          <VField label="Default for intent"><VToggle on={f.is_default} label={f.is_default ? "Default" : "Not default"} onClick={() => admin && set("is_default", !f.is_default)} /></VField>
          <VField label="State"><VToggle on={f.is_enabled} onClick={() => admin && set("is_enabled", !f.is_enabled)} /></VField>
        </div>
      </div>
      <div className="vc-drawer-foot">
        <button className="btn ghost" onClick={onClose}>Cancel</button>
        <span className="vc-spacer" />
        <button className="btn primary" disabled={!admin || saving} onClick={save}><Icon name="check" className="glyph" style={{ width: 14, height: 14 }} /> {saving ? "Saving…" : isNew ? "Create template" : "Save template"}</button>
      </div>
    </VDrawer>
  );
}
function TemplatesTab({ admin, push, agentSlug }) {
  const q = useResource("viiera_intent_templates", { eq: { agent_slug: agentSlug } });
  const [edit, setEdit] = useStateV(null);
  const [del, setDel] = useStateV(null);
  const [busy, setBusy] = useStateV(false);
  function doDelete() { setBusy(true); DW.mutate("remove", { resource: "viiera_intent_templates", id: del.id }).then(() => { push("Template deleted"); q.refetch(); setDel(null); }).catch((e) => push("Delete failed · " + e.message, "err")).finally(() => setBusy(false)); }
  if (q.loading) return <LoadingState lines={6} label="Loading intent templates" />;
  if (q.error) return <ErrorState error={q.error} onRetry={q.refetch} />;
  const rows = q.data || [];
  return (
    <Panel className="tight">
      <PHead icon="comms" eyebrow={agentName(agentSlug) + " · intent templates"}
        right={<button className="btn primary" disabled={!admin} onClick={() => setEdit({})}><Icon name="plus" className="glyph" /> New template</button>} />
      {rows.length === 0 ? <EmptyState icon="comms" title={"No templates for " + agentName(agentSlug)} hint="Add a template to standardise how an intent is answered." /> : (
        <table className="vc-tbl">
          <thead><tr><th>Intent</th><th>Name</th><th>Tone</th><th>Preview</th><th>Default</th><th>State</th><th></th></tr></thead>
          <tbody>
            {rows.map((r) => (
              <tr key={r.id} className={r.is_enabled ? "" : "vc-disabled"} onClick={() => setEdit(r)}>
                <td data-th="Intent"><span className="vc-key">{r.intent_key}</span></td>
                <td data-th="Name" style={{ color: "var(--ink)" }}>{r.template_name}</td>
                <td className="mono" data-th="Tone">{r.tone}</td>
                <td className="vc-cellwrap" data-th="Preview"><div className="clamp2" style={{ color: "var(--ink-3)" }}>{renderTemplate(r.template_body)}</div></td>
                <td data-th="Default">{r.is_default ? <span className="vc-chip" data-k="required">default</span> : <span className="hint">—</span>}</td>
                <td data-th="State" onClick={(e) => e.stopPropagation()}><span className="sbadge" style={{ color: r.is_enabled ? "var(--state-clear)" : "var(--ink-4)" }}><span className="led" />{r.is_enabled ? "on" : "off"}</span></td>
                <td onClick={(e) => e.stopPropagation()} data-th=""><div className="vc-rowacts"><button className="vc-iconbtn danger" disabled={!admin} title="Delete" onClick={() => setDel(r)}><Icon name="close" className="glyph" style={{ width: 14, height: 14 }} /></button></div></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
      {edit && <TemplateEditor admin={admin} push={push} row={edit} agentSlug={agentSlug} onClose={() => setEdit(null)} refetch={q.refetch} />}
      <ConfirmModal open={!!del} busy={busy} title="Delete this template?" confirmLabel="Delete template"
        desc={del ? "The “" + (del.template_name || del.intent_key) + "” template will be removed." : ""}
        onCancel={() => setDel(null)} onConfirm={doDelete} />
    </Panel>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   4 · PHRASE CONTROLS  (Council-wide · Viiera-governed)
══════════════════════════════════════════════════════════════════════════════ */
function PhraseEditor({ admin, push, row, onClose, refetch }) {
  const isNew = !row.id;
  const [f, setF] = useStateV(() => ({ control_type: "banned", phrase: "", replacement: "", reason: "", severity: "medium", is_enabled: true, agent_slug: "council", ...row }));
  const [saving, setSaving] = useStateV(false);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  function save() {
    if (!f.phrase.trim()) return push("Phrase is required", "err");
    setSaving(true);
    const op = isNew ? DW.mutate("create", { resource: "viiera_phrase_controls", row: f }) : DW.mutate("update", { resource: "viiera_phrase_controls", id: f.id, patch: f });
    op.then(() => { push(isNew ? "Phrase control created" : "Phrase control saved"); refetch(); onClose(); })
      .catch((e) => push("Save failed · " + e.message, "err")).finally(() => setSaving(false));
  }
  return (
    <VDrawer title={isNew ? "New phrase control" : f.phrase} sub={"council-wide · " + f.control_type} accent="var(--gold-bright)" onClose={onClose}>
      <div className="vc-form">
        <VField label="Control type"><VChoice value={f.control_type} options={CONTROL_TYPES} onChange={(v) => set("control_type", v)} /></VField>
        <VField label="Phrase"><input type="text" value={f.phrase} disabled={!admin} onChange={(e) => set("phrase", e.target.value)} /></VField>
        <VField label="Replacement" hint="Optional — what the agent should say instead."><input type="text" value={f.replacement} disabled={!admin} onChange={(e) => set("replacement", e.target.value)} /></VField>
        <VField label="Reason"><textarea value={f.reason} disabled={!admin} onChange={(e) => set("reason", e.target.value)} rows={2} /></VField>
        <div className="vc-field-row">
          <VField label="Severity"><select value={f.severity} disabled={!admin} onChange={(e) => set("severity", e.target.value)}>{SEVERITIES.map((s) => <option key={s} value={s}>{s}</option>)}</select></VField>
          <VField label="State"><VToggle on={f.is_enabled} onClick={() => admin && set("is_enabled", !f.is_enabled)} /></VField>
        </div>
        {f.control_type === "banned" && f.severity === "critical" && <div className="dd dont"><div className="h"><Icon name="risk" className="glyph" style={{ width: 14, height: 14 }} /> Critical ban</div><p style={{ margin: 0, color: "var(--ink-2)", fontSize: 13 }}>Any response from any agent containing this phrase is failed automatically and flagged in the logs.</p></div>}
      </div>
      <div className="vc-drawer-foot">
        <button className="btn ghost" onClick={onClose}>Cancel</button>
        <span className="vc-spacer" />
        <button className="btn primary" disabled={!admin || saving} onClick={save}><Icon name="check" className="glyph" style={{ width: 14, height: 14 }} /> {saving ? "Saving…" : isNew ? "Create control" : "Save control"}</button>
      </div>
    </VDrawer>
  );
}
function PhrasesTab({ admin, push }) {
  const q = useResource("viiera_phrase_controls", {});
  const [edit, setEdit] = useStateV(null);
  const [del, setDel] = useStateV(null);
  const [busy, setBusy] = useStateV(false);
  const [filter, setFilter] = useStateV("all");
  function doDelete() { setBusy(true); DW.mutate("remove", { resource: "viiera_phrase_controls", id: del.id }).then(() => { push("Phrase control deleted"); q.refetch(); setDel(null); }).catch((e) => push("Delete failed · " + e.message, "err")).finally(() => setBusy(false)); }
  if (q.loading) return <LoadingState lines={6} label="Loading phrase controls" />;
  if (q.error) return <ErrorState error={q.error} onRetry={q.refetch} />;
  const rows = (q.data || []).filter((r) => filter === "all" || r.control_type === filter);
  return (
    <Panel className="tight">
      <PHead icon="filter" eyebrow="Phrase controls"
        right={<div className="vc-toolbar">
          <select className="vc-input" value={filter} onChange={(e) => setFilter(e.target.value)}>
            <option value="all">All types</option>{CONTROL_TYPES.map((t) => <option key={t} value={t}>{t}</option>)}
          </select>
          <button className="btn primary" disabled={!admin} onClick={() => setEdit({})}><Icon name="plus" className="glyph" /> New control</button>
        </div>} />
      <div className="vc-policy-note gold"><Icon name="crown" className="glyph" style={{ width: 14, height: 14 }} /> Council-wide policy, governed by Viiera. These bans, avoids, and preferences apply to <b>every</b> agent's responses — independent of the selected agent.</div>
      {rows.length === 0 ? <EmptyState icon="filter" title="No phrase controls" hint="Add banned, avoided, preferred, or required phrases." /> : (
        <table className="vc-tbl">
          <thead><tr><th>Type</th><th>Phrase</th><th>Replacement</th><th>Severity</th><th>Reason</th><th>State</th><th></th></tr></thead>
          <tbody>
            {rows.map((r) => {
              const crit = r.control_type === "banned" && r.severity === "critical" && r.is_enabled;
              return (
                <tr key={r.id} className={(r.is_enabled ? "" : "vc-disabled ") + (crit ? "vc-row-critical" : "")} onClick={() => setEdit(r)}>
                  <td data-th="Type"><TypeChip k={r.control_type} /></td>
                  <td data-th="Phrase" style={{ color: "var(--ink)", fontWeight: 500 }}>{crit && <Icon name="lock" className="glyph" style={{ width: 12, height: 12, color: "var(--state-crisis)", marginRight: 6, verticalAlign: "-1px" }} />}“{r.phrase}”</td>
                  <td className="mono" data-th="Replacement">{r.replacement ? "→ " + r.replacement : <span className="hint">—</span>}</td>
                  <td data-th="Severity"><SevChip s={r.severity} /></td>
                  <td className="vc-cellwrap" data-th="Reason"><div className="clamp2" style={{ color: "var(--ink-3)" }}>{r.reason}</div></td>
                  <td data-th="State" onClick={(e) => e.stopPropagation()}><VToggle on={r.is_enabled} onClick={() => admin && DW.mutate("update", { resource: "viiera_phrase_controls", id: r.id, patch: { is_enabled: !r.is_enabled } }).then(q.refetch)} /></td>
                  <td onClick={(e) => e.stopPropagation()} data-th=""><div className="vc-rowacts"><button className="vc-iconbtn danger" disabled={!admin} title="Delete" onClick={() => setDel(r)}><Icon name="close" className="glyph" style={{ width: 14, height: 14 }} /></button></div></td>
                </tr>
              );
            })}
          </tbody>
        </table>
      )}
      {edit && <PhraseEditor admin={admin} push={push} row={edit} onClose={() => setEdit(null)} refetch={q.refetch} />}
      <ConfirmModal open={!!del} busy={busy} title="Delete this phrase control?" confirmLabel="Delete control"
        desc={del ? "“" + del.phrase + "” will no longer be enforced for any agent." : ""} onCancel={() => setDel(null)} onConfirm={doDelete} />
    </Panel>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   5 · TEST PROMPTS  (per agent)
══════════════════════════════════════════════════════════════════════════════ */
function TestEditor({ admin, push, row, agentSlug, onClose, refetch }) {
  const isNew = !row.id;
  const [f, setF] = useStateV(() => ({ prompt_key: "", input_text: "", expected_intent: "", expected_contains: [], forbidden_contains: [], notes: "", is_active: true, agent_slug: agentSlug, ...row }));
  const [saving, setSaving] = useStateV(false);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  function save() {
    if (!f.prompt_key.trim() || !f.input_text.trim()) return push("Prompt key and input are required", "err");
    setSaving(true);
    const patch = { ...f, expected_contains: Array.isArray(f.expected_contains) ? f.expected_contains : vcParseList(f.expected_contains), forbidden_contains: Array.isArray(f.forbidden_contains) ? f.forbidden_contains : vcParseList(f.forbidden_contains) };
    const op = isNew ? DW.mutate("create", { resource: "viiera_test_prompts", row: patch }) : DW.mutate("update", { resource: "viiera_test_prompts", id: f.id, patch });
    op.then(() => { push(isNew ? "Test prompt created" : "Test prompt saved"); refetch(); onClose(); })
      .catch((e) => push("Save failed · " + e.message, "err")).finally(() => setSaving(false));
  }
  return (
    <VDrawer title={isNew ? "New test prompt" : f.prompt_key} sub={agentName(agentSlug) + " · eval"} accent={agentColor(agentSlug)} onClose={onClose}>
      <div className="vc-form">
        <div className="vc-field-row">
          <VField label="Prompt key" hint="snake_case"><input type="text" className="code" value={f.prompt_key} disabled={!admin} onChange={(e) => set("prompt_key", e.target.value)} /></VField>
          <VField label="Expected intent"><input type="text" className="code" value={f.expected_intent} disabled={!admin} onChange={(e) => set("expected_intent", e.target.value)} /></VField>
        </div>
        <VField label="Input text" hint="The user message sent to the agent in the eval."><textarea value={f.input_text} disabled={!admin} onChange={(e) => set("input_text", e.target.value)} rows={2} /></VField>
        <VField label="Expected contains" hint="comma-separated — response must include all"><input type="text" className="code" value={vcCommaList(f.expected_contains)} disabled={!admin} onChange={(e) => set("expected_contains", vcParseList(e.target.value))} /></VField>
        <VField label="Forbidden contains" hint="comma-separated — response must include none"><input type="text" className="code" value={vcCommaList(f.forbidden_contains)} disabled={!admin} onChange={(e) => set("forbidden_contains", vcParseList(e.target.value))} /></VField>
        <VField label="Notes"><textarea value={f.notes} disabled={!admin} onChange={(e) => set("notes", e.target.value)} rows={2} /></VField>
        <VField label="Active in eval set"><VToggle on={f.is_active} onClick={() => admin && set("is_active", !f.is_active)} /></VField>
      </div>
      <div className="vc-drawer-foot">
        <button className="btn ghost" onClick={onClose}>Cancel</button>
        <span className="vc-spacer" />
        <button className="btn primary" disabled={!admin || saving} onClick={save}><Icon name="check" className="glyph" style={{ width: 14, height: 14 }} /> {saving ? "Saving…" : isNew ? "Create test" : "Save test"}</button>
      </div>
    </VDrawer>
  );
}
function TestsTab({ admin, push, agentSlug }) {
  const q = useResource("viiera_test_prompts", { eq: { agent_slug: agentSlug } });
  const [edit, setEdit] = useStateV(null);
  const [del, setDel] = useStateV(null);
  const [busy, setBusy] = useStateV(false);
  const [running, setRunning] = useStateV(null);
  function doDelete() { setBusy(true); DW.mutate("remove", { resource: "viiera_test_prompts", id: del.id }).then(() => { push("Test prompt deleted"); q.refetch(); setDel(null); }).catch((e) => push("Delete failed · " + e.message, "err")).finally(() => setBusy(false)); }
  function runPreview(r) {
    // ⇄ placeholder: real impl calls the Viiera Worker debug endpoint with the agent's live persona.
    setRunning(r.id);
    push("Run Preview is a placeholder — wires to the Viiera Worker debug endpoint", "gold");
    setTimeout(() => setRunning(null), 1200);
  }
  if (q.loading) return <LoadingState lines={6} label="Loading test prompts" />;
  if (q.error) return <ErrorState error={q.error} onRetry={q.refetch} />;
  const rows = q.data || [];
  return (
    <Panel className="tight">
      <PHead icon="beaker" eyebrow={agentName(agentSlug) + " · eval set"}
        right={<button className="btn primary" disabled={!admin} onClick={() => setEdit({})}><Icon name="plus" className="glyph" /> New test</button>} />
      <div style={{ padding: "10px var(--s-6)", borderBottom: "1px solid var(--hairline)", fontFamily: "var(--font-mono)", fontSize: 10.5, color: "var(--ink-4)", lineHeight: 1.5 }}>
        ⇄ Run Preview will call the Viiera Worker debug endpoint to replay each prompt against {agentName(agentSlug)}'s live persona and check expected / forbidden contains. Placeholder until that endpoint ships.
      </div>
      {rows.length === 0 ? <EmptyState icon="beaker" title={"No test prompts for " + agentName(agentSlug)} hint="Add eval prompts to guard this persona against regressions." /> : (
        <table className="vc-tbl">
          <thead><tr><th>Key</th><th>Input</th><th>Expects intent</th><th>Must contain</th><th>Must not</th><th>Active</th><th></th></tr></thead>
          <tbody>
            {rows.map((r) => (
              <tr key={r.id} className={r.is_active ? "" : "vc-disabled"} onClick={() => setEdit(r)}>
                <td className="mono" data-th="Key">{r.prompt_key}</td>
                <td className="vc-cellwrap" data-th="Input"><div className="clamp2" style={{ color: "var(--ink)" }}>{r.input_text}</div></td>
                <td data-th="Expects intent"><span className="vc-key">{r.expected_intent}</span></td>
                <td data-th="Must contain"><div className="vc-vars">{(r.expected_contains || []).map((c, n) => <span key={n} className="vc-var good">{c}</span>)}{!(r.expected_contains || []).length && <span className="hint">—</span>}</div></td>
                <td data-th="Must not"><div className="vc-vars">{(r.forbidden_contains || []).slice(0, 2).map((c, n) => <span key={n} className="vc-var bad">{c}</span>)}{(r.forbidden_contains || []).length > 2 && <span className="vc-var bad">+{r.forbidden_contains.length - 2}</span>}{!(r.forbidden_contains || []).length && <span className="hint">—</span>}</div></td>
                <td data-th="Active" onClick={(e) => e.stopPropagation()}><VToggle on={r.is_active} label={r.is_active ? "active" : "off"} onClick={() => admin && DW.mutate("update", { resource: "viiera_test_prompts", id: r.id, patch: { is_active: !r.is_active } }).then(q.refetch)} /></td>
                <td onClick={(e) => e.stopPropagation()} data-th=""><div className="vc-rowacts">
                  <button className="vc-iconbtn" title="Run Preview (placeholder)" onClick={() => runPreview(r)}><Icon name={running === r.id ? "refresh" : "play"} className="glyph" style={{ width: 14, height: 14, color: running === r.id ? "var(--state-focus)" : undefined }} /></button>
                  <button className="vc-iconbtn danger" disabled={!admin} title="Delete" onClick={() => setDel(r)}><Icon name="close" className="glyph" style={{ width: 14, height: 14 }} /></button>
                </div></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
      {edit && <TestEditor admin={admin} push={push} row={edit} agentSlug={agentSlug} onClose={() => setEdit(null)} refetch={q.refetch} />}
      <ConfirmModal open={!!del} busy={busy} title="Delete this test prompt?" confirmLabel="Delete test"
        desc={del ? "“" + del.prompt_key + "” will be removed from the eval set." : ""} onCancel={() => setDel(null)} onConfirm={doDelete} />
    </Panel>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   6 · VERSIONS  (per agent · Viiera-gated)
══════════════════════════════════════════════════════════════════════════════ */
function VersionsTab({ admin, push, agentSlug, isViiera }) {
  const q = useResource("viiera_prompt_versions", { eq: { agent_slug: agentSlug }, sort: { key: "version_number", dir: "desc" } });
  const [act, setAct] = useStateV(null); // { kind:'publish'|'rollback', row }
  const [busy, setBusy] = useStateV(false);
  function apply() {
    setBusy(true);
    const action = act.kind === "publish" ? "viiera.publishVersion" : "viiera.rollbackVersion";
    DW.mutate(action, { id: act.row.id })
      .then(() => { push(agentName(agentSlug) + " v" + act.row.version_number + (act.kind === "publish" ? " published live" : " restored live"), "gold"); q.refetch(); setAct(null); })
      .catch((e) => push("Failed · " + e.message, "err")).finally(() => setBusy(false));
  }
  if (q.loading) return <LoadingState lines={5} label="Loading versions" />;
  if (q.error) return <ErrorState error={q.error} onRetry={q.refetch} />;
  const rows = q.data || [];
  return (
    <Panel className="tight">
      <PHead icon="branch" eyebrow={agentName(agentSlug) + " · persona versions"} />
      <div className="vc-policy-note gold"><Icon name="crown" className="glyph" style={{ width: 14, height: 14 }} /> Version control is Viiera-gated. Publishing or rolling back {isViiera ? "her own" : agentName(agentSlug) + "'s"} persona is a deliberate production action that routes through her authority.</div>
      {rows.length === 0 ? <EmptyState icon="branch" title={"No versions for " + agentName(agentSlug)} hint="Versions are cut when a persona changes meaningfully." /> : (
        <table className="vc-tbl">
          <thead><tr><th>Ver</th><th>Label</th><th>Status</th><th>Change note</th><th>Created</th><th>Published</th><th></th></tr></thead>
          <tbody>
            {rows.map((r) => (
              <tr key={r.id} style={{ cursor: "default" }}>
                <td className="num" data-th="Ver" style={{ color: "var(--violet-ink)", fontWeight: 600 }}>v{r.version_number}</td>
                <td data-th="Label" style={{ color: "var(--ink)" }}>{r.label}</td>
                <td data-th="Status"><span className="vc-status" data-st={r.status} style={{ padding: "3px 9px", fontSize: 9 }}><span className="led" />{r.status}</span></td>
                <td className="vc-cellwrap" data-th="Change note"><div className="clamp2" style={{ color: "var(--ink-3)" }}>{r.change_note}</div></td>
                <td className="mono" data-th="Created" style={{ color: "var(--ink-3)" }}>{vcDate(r.created_at)}</td>
                <td className="mono" data-th="Published" style={{ color: r.published_at ? "var(--gold-bright)" : "var(--ink-4)" }}>{vcDate(r.published_at)}</td>
                <td data-th=""><div className="vc-rowacts">
                  {r.status === "draft" && <button className="btn gold" disabled={!admin} style={{ padding: "6px 12px", fontSize: 12 }} onClick={() => setAct({ kind: "publish", row: r })}><Icon name="lock" className="glyph" style={{ width: 13, height: 13 }} /> Publish</button>}
                  {r.status === "archived" && <button className="btn" disabled={!admin} style={{ padding: "6px 12px", fontSize: 12 }} onClick={() => setAct({ kind: "rollback", row: r })}><Icon name="rollback" className="glyph" style={{ width: 13, height: 13 }} /> Roll back</button>}
                  {r.status === "published" && <span className="sbadge" style={{ color: "var(--gold-bright)" }}><span className="led" />live</span>}
                </div></td>
              </tr>
            ))}
          </tbody>
        </table>
      )}
      <ConfirmModal open={!!act} busy={busy} tone="gold" icon="lock"
        title={act && act.kind === "publish" ? "Publish " + agentName(agentSlug) + " v" + act.row.version_number + "?" : act ? "Roll back to v" + act.row.version_number + "?" : ""}
        confirmLabel={act && act.kind === "publish" ? "Yes, publish live" : "Roll back now"}
        desc={act && act.kind === "publish" ? "This becomes the live persona version for " + agentName(agentSlug) + ". The current published version is archived." : "Production reverts to this version. The current live version is archived."}
        note={!isViiera ? "Routes through Viiera's authority — she holds the publish gate for the whole Council." : "Deliberate production action — logged to the audit trail."}
        onCancel={() => setAct(null)} onConfirm={apply} />
    </Panel>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   7 · RESPONSE LOGS  (per agent)
══════════════════════════════════════════════════════════════════════════════ */
function highlightBanned(text, banned) {
  if (!banned.length) return text;
  const re = new RegExp("(" + banned.map((b) => b.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|") + ")", "gi");
  const parts = String(text).split(re);
  return parts.map((p, i) => banned.some((b) => b.toLowerCase() === p.toLowerCase()) ? <span key={i} className="vc-banned-hit">{p}</span> : <span key={i}>{p}</span>);
}
function LogsTab({ admin, push, agentSlug }) {
  const q = useResource("viiera_response_logs", { eq: { agent_slug: agentSlug }, sort: { key: "created_at", dir: "desc" } });
  const phrasesQ = useResource("viiera_phrase_controls", {});
  const [intent, setIntent] = useStateV("all");
  const [evalF, setEvalF] = useStateV("all");
  const banned = useMemoV(() => (phrasesQ.data || []).filter((p) => p.control_type === "banned" && p.is_enabled).map((p) => p.phrase), [phrasesQ.data]);

  if (q.loading) return <LoadingState lines={7} label="Loading response logs" />;
  if (q.error) return <ErrorState error={q.error} onRetry={q.refetch} />;
  const all = q.data || [];
  const intents = ["all", ...Array.from(new Set(all.map((l) => l.intent_key)))];
  let rows = all;
  if (intent !== "all") rows = rows.filter((l) => l.intent_key === intent);
  if (evalF !== "all") rows = rows.filter((l) => l.evaluation === evalF);
  const flagged = all.filter((l) => banned.some((b) => l.response_text.toLowerCase().includes(b.toLowerCase()))).length;

  return (
    <div style={{ display: "grid", gap: "var(--s-6)" }}>
      <div className="cols c-4">
        {[["Logged", "log", all.length, "var(--ink)"], ["Passed", "check", all.filter((l) => l.evaluation === "passed").length, "var(--state-clear)"], ["Flagged", "filter", all.filter((l) => l.evaluation === "flagged").length, "var(--state-caution)"], ["Banned-phrase hits", "risk", flagged, "var(--state-crisis)"]].map(([k, ic, v, c], i) => (
          <Panel key={i} style={{ padding: "13px 16px" }}><div className="mtile" style={{ padding: 0 }}><div className="k"><Icon name={ic} style={{ width: 13, height: 13 }} /> {k}</div><div className="v" style={{ color: c }}>{v}</div></div></Panel>
        ))}
      </div>
      <Panel className="tight">
        <PHead icon="log" eyebrow={agentName(agentSlug) + " · recent responses"}
          right={<div className="vc-toolbar">
            <select className="vc-input" value={intent} onChange={(e) => setIntent(e.target.value)}>{intents.map((i) => <option key={i} value={i}>{i === "all" ? "All intents" : i}</option>)}</select>
            <select className="vc-input" value={evalF} onChange={(e) => setEvalF(e.target.value)}><option value="all">All evals</option><option value="passed">passed</option><option value="flagged">flagged</option><option value="failed">failed</option></select>
            <button className="btn" onClick={q.refetch}><Icon name="refresh" className="glyph" style={{ width: 13, height: 13 }} /> Refresh</button>
          </div>} />
        {rows.length === 0 ? <EmptyState icon="log" title="No logs match" hint="Adjust the intent or evaluation filter." /> : (
          <table className="vc-tbl">
            <thead><tr><th>Time</th><th>User</th><th>Intent</th><th>Response</th><th>Model</th><th>Eval</th></tr></thead>
            <tbody>
              {rows.map((l) => {
                const hit = banned.some((b) => l.response_text.toLowerCase().includes(b.toLowerCase()));
                return (
                  <tr key={l.id} className={hit ? "vc-row-critical" : ""} style={{ cursor: "default" }}>
                    <td className="mono" data-th="Time" style={{ whiteSpace: "nowrap", color: "var(--ink-3)" }}>{vcDate(l.created_at)}</td>
                    <td className="vc-cellwrap" data-th="User"><div className="clamp2">{l.user_text}</div></td>
                    <td data-th="Intent"><span className="vc-key">{l.intent_key}</span></td>
                    <td className="vc-cellwrap" data-th="Response"><div className="vc-log-resp">{highlightBanned(l.response_text, banned)}</div>{hit && <div className="vc-log-banner"><Icon name="risk" className="glyph" style={{ width: 12, height: 12 }} /> banned phrase detected</div>}</td>
                    <td className="mono" data-th="Model" style={{ whiteSpace: "nowrap", fontSize: 10.5 }}>{l.model}</td>
                    <td data-th="Eval"><span className="vc-chip" data-k={l.evaluation}>{l.evaluation}</span></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </Panel>
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   AGENT SWITCHER
══════════════════════════════════════════════════════════════════════════════ */
function AgentBar({ value, onPick, cfgByAgent }) {
  const agents = COUNCIL_ORDER.map((s) => DW.agent(s)).filter(Boolean);
  return (
    <div className="vc-agentbar" role="tablist" aria-label="Council agent">
      {agents.map((a) => {
        const cfg = cfgByAgent[a.id];
        return (
          <button key={a.id} role="tab" aria-selected={value === a.id} className={"vc-agent " + (value === a.id ? "on" : "")} style={{ "--c": a.ac }} onClick={() => onPick(a.id)}>
            <span className="av" style={{ backgroundImage: a.head ? "url(" + a.head + ")" : "none" }} />
            <span className="vc-agent-id">
              <span className="nm">{a.name}{a.id === "viiera" && <span className="vc-primary">primary</span>}</span>
              <span className="dm">{a.domain}</span>
            </span>
            <span className="vc-agent-led" style={{ background: cfg && cfg.status === "live" ? "var(--state-clear)" : "var(--ink-4)" }} />
          </button>
        );
      })}
    </div>
  );
}

/* ═══════════════════════════════════════════════════════════════════════════
   CONSOLE SHELL
══════════════════════════════════════════════════════════════════════════════ */
const VC_TABS = [
  { id: "profile", label: "Profile", icon: "crown" },
  { id: "rules", label: "Rules", icon: "shield" },
  { id: "templates", label: "Templates", icon: "comms" },
  { id: "phrases", label: "Phrase Controls", icon: "filter" },
  { id: "tests", label: "Tests", icon: "beaker" },
  { id: "versions", label: "Versions", icon: "branch" },
  { id: "logs", label: "Logs", icon: "log" },
];

function ViieraConsole({ nav }) {
  const auth = useAuth();
  const admin = ["sovereign", "commander"].includes(auth.user.role);
  const [tab, setTab] = useStateV(() => { try { return localStorage.getItem("vc_tab") || "profile"; } catch (e) { return "profile"; } });
  const [agentSlug, setAgentSlug] = useStateV(() => { try { return localStorage.getItem("vc_agent") || "viiera"; } catch (e) { return "viiera"; } });
  const { push, node: toastNode } = useToasts();
  const isViiera = agentSlug === "viiera";
  const agent = DW.agent(agentSlug) || DW.agent("viiera");

  const profilesQ = useResource("viiera_persona_profiles", {});
  const cfgQ = useResource("viiera_live_persona_config", {});
  const rulesQ = useResource("viiera_response_rules", {});
  const tplQ = useResource("viiera_intent_templates", {});
  const phrQ = useResource("viiera_phrase_controls", {});
  const testQ = useResource("viiera_test_prompts", {});
  const verQ = useResource("viiera_prompt_versions", {});
  const logQ = useResource("viiera_response_logs", {});

  const cfgByAgent = useMemoV(() => { const m = {}; (cfgQ.data || []).forEach((c) => (m[c.agent_slug] = c)); return m; }, [cfgQ.data]);
  const cfg = cfgByAgent[agentSlug] || null;
  const agentProfiles = useMemoV(() => (profilesQ.data || []).filter((p) => p.agent_slug === agentSlug), [profilesQ.data, agentSlug]);
  const activeProfile = useMemoV(() => {
    if (!agentProfiles.length) return null;
    if (cfg) return agentProfiles.find((p) => p.id === cfg.active_profile_id) || agentProfiles.find((p) => p.status === "live") || agentProfiles[0];
    return agentProfiles.find((p) => p.status === "live") || agentProfiles[0];
  }, [agentProfiles, cfg]);

  const counts = {
    rules: (rulesQ.data || []).filter((r) => r.agent_slug === agentSlug || r.agent_slug === "council").length,
    templates: (tplQ.data || []).filter((r) => r.agent_slug === agentSlug).length,
    phrases: (phrQ.data || []).length,
    tests: (testQ.data || []).filter((r) => r.agent_slug === agentSlug).length,
    versions: (verQ.data || []).filter((r) => r.agent_slug === agentSlug).length,
    logs: (logQ.data || []).filter((r) => r.agent_slug === agentSlug).length,
  };

  function go(id) { setTab(id); try { localStorage.setItem("vc_tab", id); } catch (e) {} }
  function pickAgent(s) { setAgentSlug(s); try { localStorage.setItem("vc_agent", s); } catch (e) {} }

  return (
    <div className="screen" style={{ "--vc-accent": agent.ac }}>
      <div className="screen-head">
        <div>
          <div className="title"><span className="sub">Council · Viiera</span>Command Console</div>
          <div className="meta">Viiera's control plane over the Council's voice. Pick an agent to tune its persona, rules, templates, tests, and logs. Phrase bans are Council-wide; publishing is Viiera-gated.</div>
        </div>
        <div className="screen-actions">
          <div className="role-pill" onClick={() => { const order = ["sovereign", "commander", "operator", "viewer"]; const i = order.indexOf(auth.user.role); auth.signInAs(order[(i + 1) % order.length]); }} title="Cycle role to see permission boundaries">
            <Led state={admin ? "active" : "standby"} size={7} /> {auth.user.role}{!admin && " · read-only"}
          </div>
        </div>
      </div>

      {/* agent switcher */}
      {cfgQ.loading ? <div className="vc-agentbar"><LoadingState lines={1} label="Loading Council" /></div> : <AgentBar value={agentSlug} onPick={pickAgent} cfgByAgent={cfgByAgent} />}

      {/* console bar — selected agent identity */}
      <div className="vc-bar">
        <div className="vc-crest" style={{ background: "linear-gradient(150deg, " + agent.ac + ", var(--violet-deep))", backgroundImage: agent.head ? "url(" + agent.head + ")" : undefined, backgroundSize: "cover", backgroundPosition: "center" }}>
          {!agent.head && <Icon name="crown" style={{ width: 19, height: 19, color: "#fff" }} />}
        </div>
        <div className="vc-id">
          <div className="nm">{agent.name} <span style={{ color: "var(--ink-4)", fontWeight: 400 }}>· {activeProfile ? activeProfile.name : "—"}</span></div>
          <div className="sl">{cfg ? cfg.active_profile_slug : "—"} · {cfg ? cfg.active_version_id : "—"} · {agent.domain}</div>
        </div>
        <span className="vc-status" data-st={cfg ? cfg.status : "draft"}><span className="led" />{cfg ? cfg.status : "—"}</span>
        <div className="vc-spacer" />
        <div className="vc-actions">
          <button className="btn" disabled={!admin} onClick={() => { go("profile"); push("Editing " + agent.name + "'s active profile"); }}><Icon name="crown" className="glyph" style={{ width: 14, height: 14 }} /> Edit profile</button>
          <button className="btn" disabled={!admin} onClick={() => { go("tests"); push("Run Preview is a placeholder pending the Worker endpoint", "gold"); }}><Icon name="beaker" className="glyph" style={{ width: 14, height: 14 }} /> Test</button>
          <button className="btn gold" disabled={!admin} onClick={() => go("versions")} title={isViiera ? "Publish" : "Publishing routes through Viiera"}><Icon name="lock" className="glyph" style={{ width: 14, height: 14 }} /> Publish{!isViiera && <span className="vc-gate-tag">Viiera-gated</span>}</button>
        </div>
      </div>

      {/* tabs */}
      <div className="vc-tabs" role="tablist">
        {VC_TABS.map((t) => (
          <button key={t.id} role="tab" aria-selected={tab === t.id} className={"vc-tab " + (tab === t.id ? "on" : "")} onClick={() => go(t.id)}>
            <Icon name={t.icon} className="glyph" />{t.label}{counts[t.id] != null && <span className="vc-tab-n">{counts[t.id]}</span>}
          </button>
        ))}
      </div>

      {/* active section — keyed by agent so per-agent state resets cleanly */}
      {tab === "profile" && (profilesQ.loading ? <LoadingState lines={6} label="Loading persona" /> : profilesQ.error ? <ErrorState error={profilesQ.error} onRetry={profilesQ.refetch} /> : <ProfileTab key={agentSlug} admin={admin} push={push} agentSlug={agentSlug} isViiera={isViiera} profiles={agentProfiles} refetch={() => { profilesQ.refetch(); cfgQ.refetch(); }} cfg={cfg} />)}
      {tab === "rules" && <RulesTab key={agentSlug} admin={admin} push={push} agentSlug={agentSlug} isViiera={isViiera} />}
      {tab === "templates" && <TemplatesTab key={agentSlug} admin={admin} push={push} agentSlug={agentSlug} />}
      {tab === "phrases" && <PhrasesTab admin={admin} push={push} />}
      {tab === "tests" && <TestsTab key={agentSlug} admin={admin} push={push} agentSlug={agentSlug} />}
      {tab === "versions" && <VersionsTab key={agentSlug} admin={admin} push={push} agentSlug={agentSlug} isViiera={isViiera} />}
      {tab === "logs" && <LogsTab key={agentSlug} admin={admin} push={push} agentSlug={agentSlug} />}

      {toastNode}
    </div>
  );
}

Object.assign(window, { ViieraConsole });
