import React, { useEffect, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";
import {
  Activity,
  AppWindow,
  ArrowUpRight,
  Bot,
  Brain,
  CalendarDays,
  CheckCircle2,
  ChevronRight,
  CircleDot,
  Clock3,
  Command,
  Cpu,
  Database,
  ExternalLink,
  FileText,
  Gauge,
  Globe2,
  Goal,
  HardDrive,
  History,
  KeyRound,
  Layers3,
  LayoutDashboard,
  Library,
  MessageSquareText,
  Play,
  Plus,
  RefreshCw,
  Rocket,
  Search,
  Send,
  ShieldCheck,
  Sparkles,
  TerminalSquare,
  TimerReset,
  WandSparkles,
  Workflow
} from "lucide-react";
import "./styles.css";

const seedAgents = [
  {
    id: "hermes",
    name: "Hermes",
    accent: "#42dcbf",
    icon: Sparkles,
    role: "Research, orchestration, skills, crons",
    description: "Memory-backed research, scheduled workflows, keyword strategy, and SEO skill execution."
  },
  {
    id: "codex",
    name: "Codex",
    accent: "#f66aa5",
    icon: TerminalSquare,
    role: "Build partner and local workspace",
    description: "Implements the operating system, updates files, verifies the app, and keeps the workspace tidy."
  },
  {
    id: "claude",
    name: "Claude",
    accent: "#f5a866",
    icon: Brain,
    role: "Planning, writing, review",
    description: "Long-form reasoning, article review, prompts, strategy, and beginner-friendly explanations."
  }
];

const memoryItems = [
  "Default human-assisted web work to ChatGPT Atlas.",
  "Use the Sodexo form design standard for branded documents and sheets.",
  "Keep Agent OS local-first and write durable memory to the Obsidian vault.",
  "Route research through Hermes, builds through Codex, and planning through Claude."
];

const defaultWorkspace = {
  keywords: [],
  deployments: [],
  generated: [],
  history: [],
  caseStudies: [],
  sites: [],
  calendar: [],
  journal: [],
  skill: {
    title: "James SEO Content Skill",
    body: "Given a keyword, case study, and target site, create a practical SEO article with a clear title, meta description, outline, internal links, FAQ, original James-specific angle, and deploy checklist."
  }
};

const navItems = [
  { id: "mission", label: "Mission", icon: LayoutDashboard, title: "Mission Control", subtitle: "Live agent status, local health, queue pressure, and current operating signals." },
  { id: "kanban", label: "Kanban", icon: Layers3, title: "Hermes Kanban", subtitle: "Shared task board for Hal, Oracle, and future agent workers." },
  { id: "seo", label: "SEO", icon: Search, title: "SEO Command", subtitle: "Keyword queue, topic clusters, quick publish, and weekly targeting." },
  { id: "generator", label: "Generator", icon: WandSparkles, title: "Content Generator", subtitle: "Turn keywords, case studies, and memory into article drafts and deploy checklists." },
  { id: "deploys", label: "Deploys", icon: Rocket, title: "Deploys", subtitle: "Recently deployed URLs, indexing state, multi-site toggles, and alerts." },
  { id: "memory", label: "Memory", icon: Database, title: "Memory", subtitle: "Obsidian journal, shared rules, skill editor, and durable local context." },
  { id: "cases", label: "Cases", icon: Library, title: "Case Studies", subtitle: "Store results and proof points to make articles feel specific to your work." },
  { id: "prompts", label: "Prompts", icon: KeyRound, title: "Prompt Library", subtitle: "The prompt pack adapted for your Hermes, Codex, and Claude stack." },
  { id: "calendar", label: "Calendar", icon: CalendarDays, title: "Calendar", subtitle: "Weekly publishing rhythm and ownership across the agent team." },
  { id: "history", label: "History", icon: History, title: "History", subtitle: "Journal entries, generated drafts, deploy events, and agent handoffs." }
];

function resolveViewFromPath(pathname = "/") {
  const normalized = typeof pathname === "string" ? pathname.replace(/^\/+|\/+$/g, "").toLowerCase() : "";
  if (!normalized) return "mission";
  return navItems.find((item) => item.id === normalized)?.id || "mission";
}

const promptGroups = [
  {
    title: "Build Agent OS",
    range: "1-10",
    owner: "Codex",
    prompts: [
      "Build a local Agent OS dashboard for Claude, Hermes, and Codex.",
      "Open a command palette to switch views, launch apps, and jump to agents.",
      "Show recently deployed URLs with keyword, site, status, and timestamp.",
      "Maintain a keyword queue that can be generated, drafted, and published.",
      "Save daily notes into the Obsidian Agent OS journal.",
      "Monitor local health for Hermes, Codex, and Claude.",
      "Edit the Hermes SEO content skill from the dashboard.",
      "Store case studies for article proof points.",
      "Choose one, three, or all enabled sites before publishing.",
      "Show weekly keyword and publishing analytics."
    ]
  },
  {
    title: "Keyword Research",
    range: "11-20",
    owner: "Hermes",
    prompts: [
      "Generate trending AI-agent SEO keywords for this week.",
      "Find low-competition high-intent keywords from James's active tools.",
      "Prioritize pasted Search Console terms by impressions and position.",
      "Create Hermes Agent problem-solution keyword ideas.",
      "Build a topical cluster around Agent OS and AI SEO workflows."
    ]
  },
  {
    title: "Content Generation",
    range: "21-35",
    owner: "Claude",
    prompts: [
      "Create a practical SEO article using a keyword and case study.",
      "Rewrite drafts for beginners without losing authority.",
      "Add James-specific proof, callouts, FAQ, and CTAs.",
      "Generate outlines, meta descriptions, H2s, conclusions, and comparisons."
    ]
  },
  {
    title: "Deployment",
    range: "36-40",
    owner: "Hermes",
    prompts: [
      "Track pending, deployed, indexed, and failed publish states.",
      "Prepare Netlify and indexer handoff checklists without storing credentials.",
      "Publish to selected enabled sites and log alerts when a step fails."
    ]
  },
  {
    title: "Memory and Obsidian",
    range: "41-50",
    owner: "Hermes",
    prompts: [
      "Extract reusable facts from daily notes into memory.",
      "Create bio snippets, case-study templates, and topic authority maps.",
      "Save summaries into Obsidian so future content can reuse them."
    ]
  },
  {
    title: "Agent Setup",
    range: "51-60",
    owner: "Hermes",
    prompts: [
      "Check Hermes setup, skills, models, workflows, and scheduled jobs.",
      "Use the SEO skill to create articles and repurpose YouTube transcripts.",
      "Confirm Obsidian access and local agent memory rules."
    ]
  },
  {
    title: "SEO Strategy",
    range: "61-75",
    owner: "Claude",
    prompts: [
      "Build 90-day SEO strategy, topical authority maps, and internal linking.",
      "Improve originality with anecdotes, proof, schema, and external trust links.",
      "Review drafts for on-page SEO and content quality."
    ]
  },
  {
    title: "Publishing Automation",
    range: "76-80",
    owner: "Hermes",
    prompts: [
      "Monitor publishing health and deployment workflows inside Mission Control.",
      "List tools, diagnose slowdowns, and coordinate local execution.",
      "Prepare Obsidian read-access workflows without exposing secrets."
    ]
  },
  {
    title: "Advanced Growth",
    range: "81-105",
    owner: "Codex",
    prompts: [
      "Add notifications, analytics, content calendar, competitor research, and repurposing.",
      "Bulk import keywords and queue them for publishing.",
      "Track backlinks, quick publish, monthly reports, ROI, and 6-month projections."
    ]
  }
];

const ideaSeeds = [
  "Hermes Agent OS tutorial",
  "Claude desktop SEO writing workflow",
  "AI agent content calendar",
  "local AI agent dashboard",
  "AI SEO operating system",
  "Obsidian memory for SEO content",
  "AI agent keyword research",
  "Netlify SEO publishing workflow"
];

function makeId(prefix) {
  return `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2, 7)}`;
}

function slugify(value) {
  return String(value || "article")
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-|-$/g, "")
    .slice(0, 80);
}

function formatTime(value) {
  if (!value) return "not checked";
  return new Intl.DateTimeFormat(undefined, { hour: "numeric", minute: "2-digit", second: "2-digit" }).format(new Date(value));
}

function formatDate(value) {
  if (!value) return "unknown";
  return new Intl.DateTimeFormat(undefined, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }).format(new Date(value));
}

function statusLabel(agent) {
  if (agent?.installed === undefined || agent?.installed === null) return "checking";
  if (!agent?.installed) return "missing";
  if (agent.health === "live" || agent.running) return "live";
  if (agent.health === "ready") return "ready";
  return "offline";
}

function statusTone(label) {
  if (label === "live" || label === "indexed" || label === "done") return "good";
  if (label === "ready" || label === "checking" || label === "deployed" || label === "drafting") return "warn";
  return "bad";
}

function gatewaySignal(agent) {
  if (agent?.installed === undefined || agent?.installed === null) return "checking";
  if (!agent?.installed) return "missing";
  return agent?.running ? "up" : "down";
}

function gatewayTone(agent) {
  const state = gatewaySignal(agent);
  if (state === "up") return "blue";
  if (state === "down") return "amber";
  return "pink";
}

function gatewayDetail(agent) {
  const state = gatewaySignal(agent);
  if (state === "up") return "gateway process running";
  if (state === "down") return "installed, not running";
  return "status unknown";
}

function isUnassignedAssignee(value) {
  const normalized = String(value || "").trim().toLowerCase();
  return !normalized || normalized === "unassigned" || normalized === "none" || normalized === "default";
}

function displayAssignee(value) {
  if (isUnassignedAssignee(value)) return "Unassigned";
  const normalized = String(value).trim();
  const normalizedLower = normalized.toLowerCase();
  if (normalizedLower === "hal") return "Hal";
  if (normalizedLower === "lcar") return "LCAR";
  if (normalizedLower === "trinity") return "Trinity";
  return normalized
    .split(/[\s_-]+/)
    .map((part) => {
      const lower = part.toLowerCase();
      return lower.charAt(0).toUpperCase() + lower.slice(1);
    })
    .join(" ");
}

function createDraft({ keyword, caseStudy, site, angle }) {
  const cleanKeyword = keyword || "Hermes Agent OS";
  const title = `${cleanKeyword}: A Practical Workflow for James's Agent OS`;
  const meta = `A local-first guide to using ${cleanKeyword} with Hermes, Claude, Codex, memory, and SEO publishing.`;
  return {
    id: makeId("draft"),
    title,
    keyword: cleanKeyword,
    site,
    status: "draft",
    timestamp: new Date().toISOString(),
    body: [
      `Title: ${title}`,
      "",
      `Meta: ${meta}`,
      "",
      "Angle:",
      angle || "Show how James can turn one keyword into a researched, memory-aware, publish-ready article from the Agent OS dashboard.",
      "",
      "Outline:",
      "1. What the workflow does",
      "2. Which agent owns each step",
      "3. How the keyword moves from queue to draft",
      "4. Where case studies and Obsidian memory improve originality",
      "5. Deploy and indexing checklist",
      "",
      "James-specific proof point:",
      caseStudy?.result || "The local dashboard already monitors Hermes, Codex, and Claude in one place.",
      "",
      "FAQ:",
      `Q: Can this be used for ${cleanKeyword}?`,
      "A: Yes. Add the keyword to the queue, generate a draft, attach a case study, then publish to the selected site.",
      "",
      "CTA:",
      "Open the Agent OS dashboard, pick the next keyword, and run the workflow from queue to deploy."
    ].join("\n")
  };
}

function App() {
  const [status, setStatus] = useState(null);
  const [workspace, setWorkspace] = useState(defaultWorkspace);
  const [kanbanBoard, setKanbanBoard] = useState({ tasks: [], profiles: ["hal", "oracle"], statuses: ["ready", "running", "blocked", "done"] });
  const [selectedId, setSelectedId] = useState("hermes");
  const [activeView, setActiveView] = useState(() => resolveViewFromPath(window.location.pathname));
  function goToView(viewId, syncRoute = true) {
    const nextView = navItems.find((item) => item.id === viewId)?.id || "mission";
    if (syncRoute) {
      const path = nextView === "mission" ? "/" : `/${nextView}`;
      if (window.location.pathname !== path) window.history.pushState({}, "", path);
    }
    setActiveView(nextView);
  }
  const [toast, setToast] = useState("");
  const [isRefreshing, setRefreshing] = useState(false);
  const [paletteOpen, setPaletteOpen] = useState(false);
  const [paletteQuery, setPaletteQuery] = useState("");
  const [message, setMessage] = useState("");
  const [note, setNote] = useState("");
  const [keywordForm, setKeywordForm] = useState({ keyword: "", intent: "tutorial", priority: "high", site: "main" });
  const [generator, setGenerator] = useState({ keyword: "", caseId: "", site: "main", angle: "" });
  const [caseForm, setCaseForm] = useState({ title: "", topic: "", result: "", proof: "" });
  const [skillDraft, setSkillDraft] = useState(defaultWorkspace.skill.body);
  const [kanbanForm, setKanbanForm] = useState({ title: "", body: "", assignee: "unassigned", priority: 0 });
  const [kanbanFilter, setKanbanFilter] = useState({ assignee: "all", status: "active" });
  const [kanbanComments, setKanbanComments] = useState({});

  const mergedAgents = useMemo(() => seedAgents.map((agent) => ({ ...agent, ...(status?.agents?.find((item) => item.id === agent.id) || {}) })), [status]);
  const selected = mergedAgents.find((agent) => agent.id === selectedId) || mergedAgents[0];
  const liveCount = mergedAgents.filter((agent) => statusLabel(agent) === "live").length;
  const viewMeta = navItems.find((item) => item.id === activeView) || navItems[0];
  const enabledSites = workspace.sites?.filter((site) => site.enabled) || [];

  async function refreshStatus() {
    setRefreshing(true);
    try {
      const response = await fetch("/api/status");
      setStatus(await response.json());
    } catch {
      setToast("The local helper server is not responding yet.");
    } finally {
      setRefreshing(false);
    }
  }

  async function loadWorkspace() {
    try {
      const response = await fetch("/api/workspace");
      const data = await response.json();
      setWorkspace({ ...defaultWorkspace, ...data });
      setSkillDraft(data.skill?.body || defaultWorkspace.skill.body);
    } catch {
      setToast("Could not load Agent OS workspace data.");
    }
  }

  async function loadKanban() {
    try {
      const response = await fetch("/api/kanban");
      const data = await response.json();
      if (data.ok === false) {
        setToast(data.message || "Could not load Hermes Kanban.");
        return;
      }
      setKanbanBoard(data);
    } catch {
      setToast("Could not reach the Hermes Kanban API.");
    }
  }

  async function saveWorkspace(nextWorkspace, messageText = "Saved.") {
    setWorkspace(nextWorkspace);
    try {
      const response = await fetch("/api/workspace", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(nextWorkspace)
      });
      setWorkspace(await response.json());
      setToast(messageText);
    } catch {
      setToast("Could not save workspace data.");
    }
  }

  function withHistory(nextWorkspace, title, detail, type = "event") {
    return {
      ...nextWorkspace,
      history: [{ id: makeId("hist"), type, title, detail, timestamp: new Date().toISOString() }, ...(nextWorkspace.history || [])].slice(0, 80)
    };
  }

  useEffect(() => {
    refreshStatus();
    loadWorkspace();
    loadKanban();
    const timer = window.setInterval(refreshStatus, 15000);
    const kanbanTimer = window.setInterval(loadKanban, 10000);
    return () => {
      window.clearInterval(timer);
      window.clearInterval(kanbanTimer);
    };
  }, []);

  useEffect(() => {
    function onKeyDown(event) {
      if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
        event.preventDefault();
        setPaletteOpen((value) => !value);
      }
      if (event.key === "Escape") setPaletteOpen(false);
    }
    window.addEventListener("keydown", onKeyDown);
    return () => window.removeEventListener("keydown", onKeyDown);
  }, []);

  useEffect(() => {
    const syncFromPath = () => {
      goToView(resolveViewFromPath(window.location.pathname), false);
    };
    window.addEventListener("popstate", syncFromPath);
    return () => window.removeEventListener("popstate", syncFromPath);
  }, []);

  async function launch(target, label) {
    try {
      const response = await fetch("/api/launch", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ target })
      });
      const data = await response.json();
      setToast(data.ok ? `${label} requested.` : data.message || "Launch failed.");
    } catch {
      setToast("The local helper server could not launch that target.");
    }
  }

  function selectAgent(id) {
    setSelectedId(id);
    goToView("mission");
  }

  async function createKanbanTask(event) {
    event.preventDefault();
    const title = kanbanForm.title.trim();
    if (!title) return;
    try {
      const response = await fetch("/api/kanban/tasks", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(kanbanForm)
      });
      const data = await response.json();
      if (!data.ok) throw new Error(data.message || data.stderr || "Task creation failed.");
      setKanbanBoard(data.board);
      setKanbanForm({ title: "", body: "", assignee: kanbanForm.assignee, priority: 0 });
      setToast("Hermes Kanban task created.");
    } catch (error) {
      setToast(error.message);
    }
  }

  async function updateKanbanTask(taskId, action, payload = {}) {
    const endpoints = {
      assign: `/api/kanban/tasks/${taskId}/assign`,
      status: `/api/kanban/tasks/${taskId}/status`,
      comment: `/api/kanban/tasks/${taskId}/comment`
    };
    try {
      const response = await fetch(endpoints[action], {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(payload)
      });
      const data = await response.json();
      if (!data.ok) throw new Error(data.message || data.stderr || "Kanban update failed.");
      setKanbanBoard(data.board);
      if (action === "comment") setKanbanComments((items) => ({ ...items, [taskId]: "" }));
      setToast("Kanban updated.");
    } catch (error) {
      setToast(error.message);
    }
  }

  function addKeyword(event) {
    event.preventDefault();
    const keyword = keywordForm.keyword.trim();
    if (!keyword) return;
    const item = { id: makeId("kw"), ...keywordForm, keyword, status: "queued", createdAt: new Date().toISOString() };
    const next = withHistory({ ...workspace, keywords: [item, ...(workspace.keywords || [])] }, "Keyword queued", keyword, "keyword");
    saveWorkspace(next, "Keyword added to the queue.");
    setKeywordForm({ ...keywordForm, keyword: "" });
  }

  function generateKeywordIdeas() {
    const existing = new Set((workspace.keywords || []).map((item) => item.keyword.toLowerCase()));
    const ideas = ideaSeeds
      .filter((keyword) => !existing.has(keyword.toLowerCase()))
      .slice(0, 5)
      .map((keyword, index) => ({
        id: makeId("kw"),
        keyword,
        intent: index % 2 ? "comparison" : "tutorial",
        priority: index < 2 ? "high" : "medium",
        status: "queued",
        site: enabledSites[index % Math.max(enabledSites.length, 1)]?.id || "main",
        createdAt: new Date().toISOString()
      }));
    const next = withHistory({ ...workspace, keywords: [...ideas, ...(workspace.keywords || [])] }, "Keyword ideas generated", `${ideas.length} new AI-agent SEO keywords added.`, "keyword");
    saveWorkspace(next, "Keyword ideas added.");
  }

  function generateDraft(sourceKeyword) {
    const keyword = sourceKeyword?.keyword || generator.keyword.trim();
    if (!keyword) {
      setToast("Add a keyword before generating a draft.");
      return;
    }
    const caseStudy = (workspace.caseStudies || []).find((item) => item.id === generator.caseId) || workspace.caseStudies?.[0];
    const draft = createDraft({ keyword, caseStudy, site: sourceKeyword?.site || generator.site, angle: generator.angle });
    const keywords = sourceKeyword
      ? (workspace.keywords || []).map((item) => (item.id === sourceKeyword.id ? { ...item, status: "drafting" } : item))
      : workspace.keywords;
    const next = withHistory({ ...workspace, keywords, generated: [draft, ...(workspace.generated || [])] }, "Draft generated", draft.title, "draft");
    saveWorkspace(next, "Draft generated.");
    setGenerator({ ...generator, keyword });
    goToView("generator");
  }

  function quickPublish(keywordItem) {
    const item = keywordItem || (workspace.keywords || []).find((keyword) => keyword.status !== "published");
    if (!item) {
      setToast("No queued keyword is ready to publish.");
      return;
    }
    const site = (workspace.sites || []).find((entry) => entry.id === item.site) || workspace.sites?.[0] || { id: "main", name: "Main Site" };
    const deployment = {
      id: makeId("dep"),
      title: `${item.keyword}: practical guide`,
      keyword: item.keyword,
      url: `https://example.com/${slugify(item.keyword)}`,
      site: site.id,
      status: "deployed",
      timestamp: new Date().toISOString()
    };
    const keywords = (workspace.keywords || []).map((keyword) => (keyword.id === item.id ? { ...keyword, status: "published" } : keyword));
    const next = withHistory({ ...workspace, keywords, deployments: [deployment, ...(workspace.deployments || [])] }, "URL deployed", deployment.url, "deploy");
    saveWorkspace(next, "Deployment logged.");
    goToView("deploys");
  }

  function cycleDeployment(id) {
    const order = { pending: "deployed", deployed: "indexed", indexed: "failed", failed: "pending" };
    const deployments = (workspace.deployments || []).map((item) => (item.id === id ? { ...item, status: order[item.status] || "pending" } : item));
    saveWorkspace(withHistory({ ...workspace, deployments }, "Deploy status updated", "Status moved to next stage.", "deploy"), "Deploy status updated.");
  }

  function toggleSite(id) {
    const sites = (workspace.sites || []).map((site) => (site.id === id ? { ...site, enabled: !site.enabled } : site));
    saveWorkspace(withHistory({ ...workspace, sites }, "Site toggle updated", id, "site"), "Site selection updated.");
  }

  async function saveJournal() {
    const body = note.trim();
    if (!body) return;
    try {
      const response = await fetch("/api/journal", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ title: "Agent OS Daily Note", body })
      });
      const data = await response.json();
      await loadWorkspace();
      setNote("");
      setToast(data.filePath ? `Journal saved to Obsidian.` : "Journal saved.");
    } catch {
      setToast("Could not save the journal note.");
    }
  }

  function saveSkill() {
    const next = withHistory({ ...workspace, skill: { title: workspace.skill?.title || "James SEO Content Skill", body: skillDraft } }, "SEO skill updated", "Hermes content instructions were updated.", "skill");
    saveWorkspace(next, "SEO skill saved.");
  }

  function addCaseStudy(event) {
    event.preventDefault();
    if (!caseForm.title.trim() || !caseForm.result.trim()) return;
    const item = { id: makeId("case"), ...caseForm, updatedAt: new Date().toISOString() };
    const next = withHistory({ ...workspace, caseStudies: [item, ...(workspace.caseStudies || [])] }, "Case study added", item.title, "case");
    saveWorkspace(next, "Case study added.");
    setCaseForm({ title: "", topic: "", result: "", proof: "" });
  }

  const commands = [
    ...navItems.map((item) => ({ label: `Open ${item.title}`, hint: item.subtitle, run: () => goToView(item.id), icon: item.icon })),
    ...mergedAgents.map((agent) => ({ label: `Control ${agent.name}`, hint: agent.role, run: () => selectAgent(agent.id), icon: agent.icon })),
    { label: "Generate keyword ideas", hint: "Add AI-agent SEO ideas to the queue", run: generateKeywordIdeas, icon: Sparkles },
    { label: "Quick publish next keyword", hint: "Move the next queued keyword to deploys", run: () => quickPublish(), icon: Rocket },
    { label: "Refresh agent health", hint: "Read local Hermes, Codex, and Claude status", run: refreshStatus, icon: RefreshCw }
  ].filter((command) => command.label.toLowerCase().includes(paletteQuery.toLowerCase()));

  return (
    <div className="app-shell">
      <aside className="sidebar">
        <div className="brand">
          <div className="brand-mark">
            <Command size={19} />
          </div>
          <div>
            <strong>Agent OS</strong>
            <span>James local command center</span>
          </div>
        </div>

        <nav className="nav-block">
          {navItems.map((item) => {
            const Icon = item.icon;
            return (
              <button key={item.id} className={`nav-item ${activeView === item.id ? "active" : ""}`} onClick={() => goToView(item.id)}>
                <Icon size={18} />
                {item.label}
              </button>
            );
          })}
        </nav>

        <div className="agent-rail">
          <span className="rail-label">Agents</span>
          {mergedAgents.map((agent) => {
            const Icon = agent.icon;
            const label = statusLabel(agent);
            return (
              <button key={agent.id} className={`agent-rail-item ${selectedId === agent.id ? "selected" : ""}`} onClick={() => selectAgent(agent.id)}>
                <span className="agent-dot" style={{ "--accent": agent.accent }}>
                  <Icon size={16} />
                </span>
                <span>{agent.name}</span>
                <i className={`pulse ${statusTone(label)}`} />
              </button>
            );
          })}
        </div>

        <button className="sidebar-card command-card" onClick={() => setPaletteOpen(true)}>
          <Command size={18} />
          <div>
            <strong>Command palette</strong>
            <span>Press Cmd K to jump, generate, publish, or launch.</span>
          </div>
        </button>
      </aside>

      <main className="workspace">
        <header className="topbar">
          <div>
            <span className="eyeline">Local · {status?.machine?.platform || "macOS"}</span>
            <h1>{viewMeta.title}</h1>
            <p>{viewMeta.subtitle}</p>
          </div>

          <div className="top-actions">
            <button className="status-pill" onClick={() => goToView("mission")}>
              <CircleDot size={15} />
              {liveCount} of {mergedAgents.length} live
            </button>
            <button className="icon-button" onClick={refreshStatus} aria-label="Refresh status">
              <RefreshCw size={18} className={isRefreshing ? "spin" : ""} />
            </button>
            <button className="action-button" onClick={() => setPaletteOpen(true)}>
              <Command size={17} />
              Palette
            </button>
            <button className="action-button" onClick={() => launch("atlas", "ChatGPT Atlas")}>
              <AppWindow size={17} />
              Atlas
            </button>
          </div>
        </header>

        {activeView === "mission" && (
          <MissionView
            status={status}
            agents={mergedAgents}
            selected={selected}
            selectedId={selectedId}
            selectAgent={selectAgent}
            launch={launch}
            workspace={workspace}
            quickPublish={quickPublish}
          />
        )}
        {activeView === "kanban" && (
          <KanbanView
            board={kanbanBoard}
            form={kanbanForm}
            setForm={setKanbanForm}
            filter={kanbanFilter}
            setFilter={setKanbanFilter}
            comments={kanbanComments}
            setComments={setKanbanComments}
            createTask={createKanbanTask}
            updateTask={updateKanbanTask}
            refresh={loadKanban}
          />
        )}
        {activeView === "seo" && (
          <SeoView
            workspace={workspace}
            keywordForm={keywordForm}
            setKeywordForm={setKeywordForm}
            addKeyword={addKeyword}
            generateKeywordIdeas={generateKeywordIdeas}
            generateDraft={generateDraft}
            quickPublish={quickPublish}
          />
        )}
        {activeView === "generator" && (
          <GeneratorView
            workspace={workspace}
            generator={generator}
            setGenerator={setGenerator}
            generateDraft={generateDraft}
          />
        )}
        {activeView === "deploys" && <DeploysView workspace={workspace} quickPublish={quickPublish} cycleDeployment={cycleDeployment} toggleSite={toggleSite} />}
        {activeView === "memory" && (
          <MemoryView
            workspace={workspace}
            note={note}
            setNote={setNote}
            saveJournal={saveJournal}
            skillDraft={skillDraft}
            setSkillDraft={setSkillDraft}
            saveSkill={saveSkill}
          />
        )}
        {activeView === "cases" && <CasesView workspace={workspace} caseForm={caseForm} setCaseForm={setCaseForm} addCaseStudy={addCaseStudy} />}
        {activeView === "prompts" && <PromptsView />}
        {activeView === "calendar" && <CalendarView workspace={workspace} />}
        {activeView === "history" && <HistoryView workspace={workspace} />}
      </main>

      {paletteOpen && (
        <div className="palette-backdrop" onClick={() => setPaletteOpen(false)}>
          <div className="palette" onClick={(event) => event.stopPropagation()}>
            <div className="palette-search">
              <Search size={18} />
              <input autoFocus value={paletteQuery} onChange={(event) => setPaletteQuery(event.target.value)} placeholder="Search commands, agents, and views" />
            </div>
            <div className="palette-list">
              {commands.map((command) => {
                const Icon = command.icon;
                return (
                  <button
                    key={command.label}
                    onClick={() => {
                      command.run();
                      setPaletteOpen(false);
                      setPaletteQuery("");
                    }}
                  >
                    <Icon size={17} />
                    <span>
                      <strong>{command.label}</strong>
                      <small>{command.hint}</small>
                    </span>
                  </button>
                );
              })}
            </div>
          </div>
        </div>
      )}

      {toast ? (
        <button className="toast" onClick={() => setToast("")}>
          {toast}
        </button>
      ) : null}
    </div>
  );
}

function MissionView({ status, agents, selected, selectedId, selectAgent, launch, workspace, quickPublish }) {
  const queued = workspace.keywords?.filter((item) => item.status === "queued").length || 0;
  const deployed = workspace.deployments?.length || 0;
  const indexed = workspace.deployments?.filter((item) => item.status === "indexed").length || 0;
  const agentsById = Object.fromEntries(agents.map((agent) => [agent.id, agent]));
  const gatewayCards = [
    { id: "hermes", label: "Hermes Gateway", icon: ShieldCheck },
    { id: "codex", label: "Codex Gateway", icon: Cpu },
    { id: "claude", label: "Claude Gateway", icon: MessageSquareText }
  ];
  return (
    <>
      <section className="signal-grid">
        <SignalCard icon={Activity} label="Heartbeat" value="15s" detail="local refresh loop" tone="cyan" />
        {gatewayCards.map(({ id, label, icon: GatewayIcon }) => {
          const agent = agentsById[id];
          const state = gatewaySignal(agent);
          return (
            <SignalCard
              key={id}
              icon={GatewayIcon}
              label={label}
              value={state}
              detail={gatewayDetail(agent)}
              tone={gatewayTone(agent)}
            />
          );
        })}
        <SignalCard icon={Search} label="Queued" value={queued} detail="keywords waiting" tone="pink" />
        <SignalCard icon={Clock3} label="Checked" value={formatTime(status?.checkedAt)} detail="helper server readout" tone="amber" />
      </section>

      <section className="agent-grid">
        {agents.map((agent) => (
          <AgentCard key={agent.id} agent={agent} selected={selectedId === agent.id} onSelect={() => selectAgent(agent.id)} onLaunch={launch} />
        ))}
      </section>

      <section className="control-layout">
        <AgentControlPanel selected={selected} />
        <aside className="right-stack">
          <div className="panel">
            <div className="panel-heading compact">
              <h2>Operating Signals</h2>
              <Cpu size={18} />
            </div>
            <Metric icon={Search} label="Keywords queued" value={queued} pct={Math.min(queued * 12, 100)} />
            <Metric icon={Rocket} label="URLs deployed" value={deployed} pct={Math.min(deployed * 18, 100)} />
            <Metric icon={CheckCircle2} label="Indexed URLs" value={indexed} pct={deployed ? Math.round((indexed / deployed) * 100) : 0} />
          </div>
          <div className="panel">
            <div className="panel-heading compact">
              <h2>Quick Actions</h2>
              <Command size={18} />
            </div>
            <div className="launch-grid">
              <button onClick={() => quickPublish()}>Quick publish</button>
              <button onClick={() => launch("hermesDashboard", "Hermes dashboard")}>Hermes UI</button>
              <button onClick={() => launch("codex", "Codex")}>Codex UI</button>
              <button onClick={() => launch("claude", "Claude")}>Claude</button>
            </div>
          </div>
        </aside>
      </section>
    </>
  );
}

function KanbanView({ board, form, setForm, filter, setFilter, comments, setComments, createTask, updateTask, refresh }) {
  const statusLabels = {
    ready: "Ready",
    running: "In Progress",
    blocked: "Blocked",
    done: "Completed",
    scheduled: "Scheduled",
    review: "Review",
    todo: "Todo",
    triage: "Triage"
  };
  const activeStatuses = ["ready", "todo", "running", "blocked", "review", "scheduled"];
  const profiles = board.profiles?.length ? board.profiles : ["hal"];
  const visibleTasks = (board.tasks || []).filter((task) => {
    const assigneeMatch = filter.assignee === "all" || (filter.assignee === "unassigned" ? isUnassignedAssignee(task.assignee) : task.assignee === filter.assignee);
    const statusMatch = filter.status === "all" || (filter.status === "active" ? activeStatuses.includes(task.status) : task.status === filter.status);
    return assigneeMatch && statusMatch;
  });
  const grouped = activeStatuses.concat(["done"]).reduce((acc, status) => {
    acc[status] = visibleTasks.filter((task) => task.status === status);
    return acc;
  }, {});

  return (
    <section className="kanban-shell">
      <div className="panel kanban-create">
        <div className="panel-heading compact">
          <h2>Create Task</h2>
          <Plus size={18} />
        </div>
        <form className="stack-form" onSubmit={createTask}>
          <label>Title<input value={form.title} onChange={(event) => setForm({ ...form, title: event.target.value })} placeholder="Describe the agent task" /></label>
          <label>Description<textarea value={form.body} onChange={(event) => setForm({ ...form, body: event.target.value })} placeholder="What should Hal do?" /></label>
          <div className="two-fields">
            <label>Assignee<select value={form.assignee} onChange={(event) => setForm({ ...form, assignee: event.target.value })}>
              {profiles.map((profile) => <option key={profile} value={profile}>{displayAssignee(profile)}</option>)}
              <option value="unassigned">Unassigned</option>
            </select></label>
            <label>Priority<input type="number" value={form.priority} onChange={(event) => setForm({ ...form, priority: Number(event.target.value) })} /></label>
          </div>
          <button className="primary-command" type="submit"><Plus size={17} /> Create Kanban task</button>
        </form>
      </div>

      <div className="kanban-main">
        <div className="panel kanban-toolbar">
          <div>
            <strong>{visibleTasks.length} visible tasks</strong>
            <span>{board.dbPath || "/Users/james/.hermes/kanban.db"}</span>
          </div>
          <select value={filter.assignee} onChange={(event) => setFilter({ ...filter, assignee: event.target.value })}>
            <option value="all">All assignees</option>
            <option value="unassigned">Unassigned</option>
            {profiles.map((profile) => <option key={profile} value={profile}>{displayAssignee(profile)}</option>)}
          </select>
          <select value={filter.status} onChange={(event) => setFilter({ ...filter, status: event.target.value })}>
            <option value="active">Active statuses</option>
            <option value="all">All statuses</option>
            {(board.statuses || activeStatuses).map((status) => <option key={status} value={status}>{statusLabels[status] || status}</option>)}
          </select>
          <button onClick={refresh}><RefreshCw size={16} /> Refresh</button>
        </div>

        <div className="kanban-board">
          {Object.entries(grouped).map(([status, tasks]) => (
            <div className="kanban-column" key={status}>
              <div className="kanban-column-head">
                <strong>{statusLabels[status] || status}</strong>
                <span>{tasks.length}</span>
              </div>
              <div className="kanban-cards">
                {tasks.map((task) => (
                  <article className="kanban-card" key={task.id}>
                    <div className="kanban-card-head">
                      <span className={`badge ${statusTone(task.status)}`}>{task.status}</span>
                      <small>{displayAssignee(task.assignee)}</small>
                    </div>
                    <h3>{task.title}</h3>
                    {task.body ? <p>{task.body}</p> : null}
                    <div className="kanban-meta">
                      <span>{task.id}</span>
                      <span>{formatDate(task.updated_at_iso || task.created_at_iso)}</span>
                    </div>
                    <div className="kanban-meta">
                      <span>{task.comment_count || 0} comments</span>
                      <span>{task.parent_count || 0} parents · {task.child_count || 0} children</span>
                    </div>
                    <div className="kanban-controls">
                      <select value={isUnassignedAssignee(task.assignee) ? "unassigned" : task.assignee} onChange={(event) => updateTask(task.id, "assign", { assignee: event.target.value })}>
                        <option value="unassigned">Unassigned</option>
                        {profiles.map((profile) => <option key={profile} value={profile}>{displayAssignee(profile)}</option>)}
                      </select>
                      <button onClick={() => updateTask(task.id, "status", { status: "ready" })}>Ready</button>
                      <button onClick={() => updateTask(task.id, "status", { status: "blocked" })}>Block</button>
                      <button onClick={() => updateTask(task.id, "status", { status: "done" })}>Done</button>
                    </div>
                    <div className="kanban-comment">
                      <input value={comments[task.id] || ""} onChange={(event) => setComments({ ...comments, [task.id]: event.target.value })} placeholder="Add a comment" />
                      <button onClick={() => updateTask(task.id, "comment", { body: comments[task.id] || "" })}>Add</button>
                    </div>
                    {task.comments?.[0] ? <div className="last-comment">{task.comments[0].author}: {task.comments[0].body}</div> : null}
                  </article>
                ))}
                {!tasks.length ? <div className="empty-column">No tasks</div> : null}
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

function SeoView({ workspace, keywordForm, setKeywordForm, addKeyword, generateKeywordIdeas, generateDraft, quickPublish }) {
  return (
    <section className="view-grid wide-left">
      <div className="panel">
        <div className="panel-heading compact">
          <h2>Keyword Queue</h2>
          <Search size={18} />
        </div>
        <form className="inline-form" onSubmit={addKeyword}>
          <input value={keywordForm.keyword} onChange={(event) => setKeywordForm({ ...keywordForm, keyword: event.target.value })} placeholder="Add a keyword or topic" />
          <select value={keywordForm.intent} onChange={(event) => setKeywordForm({ ...keywordForm, intent: event.target.value })}>
            <option value="tutorial">Tutorial</option>
            <option value="comparison">Comparison</option>
            <option value="strategy">Strategy</option>
            <option value="troubleshooting">Troubleshooting</option>
          </select>
          <select value={keywordForm.site} onChange={(event) => setKeywordForm({ ...keywordForm, site: event.target.value })}>
            {(workspace.sites || []).map((site) => (
              <option key={site.id} value={site.id}>{site.name}</option>
            ))}
          </select>
          <button type="submit"><Plus size={16} /> Add</button>
        </form>
        <div className="table-list">
          {(workspace.keywords || []).map((item) => (
            <div className="table-row" key={item.id}>
              <div>
                <strong>{item.keyword}</strong>
                <span>{item.intent} · {item.priority} · {item.site}</span>
              </div>
              <span className={`badge ${statusTone(item.status)}`}>{item.status}</span>
              <button onClick={() => generateDraft(item)}>Draft</button>
              <button onClick={() => quickPublish(item)}>Publish</button>
            </div>
          ))}
        </div>
      </div>

      <aside className="right-stack">
        <div className="panel">
          <div className="panel-heading compact">
            <h2>Research Tools</h2>
            <Sparkles size={18} />
          </div>
          <div className="launch-grid single">
            <button onClick={generateKeywordIdeas}>Generate 5 ideas</button>
            <button onClick={() => quickPublish()}>Publish next queued</button>
          </div>
        </div>
        <PerformancePanel workspace={workspace} />
      </aside>
    </section>
  );
}

function GeneratorView({ workspace, generator, setGenerator, generateDraft }) {
  const latest = workspace.generated?.[0];
  return (
    <section className="view-grid">
      <div className="panel">
        <div className="panel-heading compact">
          <h2>Article Builder</h2>
          <WandSparkles size={18} />
        </div>
        <div className="stack-form">
          <label>Keyword<input value={generator.keyword} onChange={(event) => setGenerator({ ...generator, keyword: event.target.value })} placeholder="Hermes Agent OS tutorial" /></label>
          <label>Case study<select value={generator.caseId} onChange={(event) => setGenerator({ ...generator, caseId: event.target.value })}>
            <option value="">Use best available case study</option>
            {(workspace.caseStudies || []).map((item) => <option key={item.id} value={item.id}>{item.title}</option>)}
          </select></label>
          <label>Target site<select value={generator.site} onChange={(event) => setGenerator({ ...generator, site: event.target.value })}>
            {(workspace.sites || []).map((site) => <option key={site.id} value={site.id}>{site.name}</option>)}
          </select></label>
          <label>Angle<textarea value={generator.angle} onChange={(event) => setGenerator({ ...generator, angle: event.target.value })} placeholder="What should make this article specific to James?" /></label>
          <button className="primary-command" onClick={() => generateDraft()}><WandSparkles size={17} /> Generate draft</button>
        </div>
      </div>
      <div className="panel draft-preview">
        <div className="panel-heading compact">
          <h2>Latest Draft</h2>
          <FileText size={18} />
        </div>
        <pre>{latest?.body || "Generate a draft to see the article brief, meta, outline, FAQ, proof point, and deploy checklist here."}</pre>
      </div>
    </section>
  );
}

function DeploysView({ workspace, quickPublish, cycleDeployment, toggleSite }) {
  return (
    <section className="view-grid wide-left">
      <div className="panel">
        <div className="panel-heading compact">
          <h2>Recently Deployed URLs</h2>
          <Rocket size={18} />
        </div>
        <div className="table-list">
          {(workspace.deployments || []).map((item) => (
            <div className="table-row deploy-row" key={item.id}>
              <div>
                <strong>{item.title}</strong>
                <span>{item.keyword} · {item.site} · {formatDate(item.timestamp)}</span>
                <a href={item.url} target="_blank" rel="noreferrer">{item.url}</a>
              </div>
              <button className={`badge ${statusTone(item.status)}`} onClick={() => cycleDeployment(item.id)}>{item.status}</button>
            </div>
          ))}
        </div>
      </div>
      <aside className="right-stack">
        <div className="panel">
          <div className="panel-heading compact">
            <h2>Multi-Site Publish</h2>
            <Globe2 size={18} />
          </div>
          <div className="site-list">
            {(workspace.sites || []).map((site) => (
              <button key={site.id} className={site.enabled ? "site enabled" : "site"} onClick={() => toggleSite(site.id)}>
                <span>{site.name}</span>
                <strong>{site.enabled ? "enabled" : "paused"}</strong>
              </button>
            ))}
          </div>
          <button className="primary-command" onClick={() => quickPublish()}><Rocket size={17} /> Publish next keyword</button>
        </div>
      </aside>
    </section>
  );
}

function MemoryView({ workspace, note, setNote, saveJournal, skillDraft, setSkillDraft, saveSkill }) {
  return (
    <section className="view-grid">
      <div className="panel">
        <div className="panel-heading compact">
          <h2>Obsidian Journal</h2>
          <Brain size={18} />
        </div>
        <textarea className="big-textarea" value={note} onChange={(event) => setNote(event.target.value)} placeholder="Write today's Agent OS note. It will save to your Obsidian Agent OS journal." />
        <button className="primary-command" onClick={saveJournal}><Send size={17} /> Save to Obsidian</button>
        <div className="memory-list">
          {memoryItems.map((item) => (
            <div className="memory-item" key={item}><CheckCircle2 size={16} /><span>{item}</span></div>
          ))}
        </div>
      </div>
      <div className="panel">
        <div className="panel-heading compact">
          <h2>Hermes SEO Skill</h2>
          <FileText size={18} />
        </div>
        <textarea className="big-textarea skill-editor" value={skillDraft} onChange={(event) => setSkillDraft(event.target.value)} />
        <button className="primary-command" onClick={saveSkill}><CheckCircle2 size={17} /> Save skill</button>
        <div className="memory-list">
          {(workspace.journal || []).slice(0, 3).map((item) => (
            <div className="memory-item" key={item.id}><Clock3 size={16} /><span>{item.title} · {formatDate(item.timestamp)}</span></div>
          ))}
        </div>
      </div>
    </section>
  );
}

function CasesView({ workspace, caseForm, setCaseForm, addCaseStudy }) {
  return (
    <section className="view-grid">
      <div className="panel">
        <div className="panel-heading compact">
          <h2>Case Study Library</h2>
          <Library size={18} />
        </div>
        <div className="case-grid">
          {(workspace.caseStudies || []).map((item) => (
            <article className="mini-card" key={item.id}>
              <span>{item.topic || "Case study"}</span>
              <h3>{item.title}</h3>
              <p>{item.result}</p>
              <small>{item.proof}</small>
            </article>
          ))}
        </div>
      </div>
      <div className="panel">
        <div className="panel-heading compact">
          <h2>Add Proof Point</h2>
          <Plus size={18} />
        </div>
        <form className="stack-form" onSubmit={addCaseStudy}>
          <label>Title<input value={caseForm.title} onChange={(event) => setCaseForm({ ...caseForm, title: event.target.value })} /></label>
          <label>Topic<input value={caseForm.topic} onChange={(event) => setCaseForm({ ...caseForm, topic: event.target.value })} /></label>
          <label>Result<textarea value={caseForm.result} onChange={(event) => setCaseForm({ ...caseForm, result: event.target.value })} /></label>
          <label>Proof<textarea value={caseForm.proof} onChange={(event) => setCaseForm({ ...caseForm, proof: event.target.value })} /></label>
          <button className="primary-command" type="submit"><Plus size={17} /> Add case study</button>
        </form>
      </div>
    </section>
  );
}

function PromptsView() {
  return (
    <section className="prompt-grid">
      {promptGroups.map((group) => (
        <article className="panel prompt-panel" key={group.title}>
          <div className="panel-heading compact">
            <div>
              <h2>{group.title}</h2>
              <span className="eyeline">Prompts {group.range} · {group.owner}</span>
            </div>
            <KeyRound size={18} />
          </div>
          <div className="memory-list">
            {group.prompts.map((prompt) => (
              <div className="memory-item" key={prompt}><ChevronRight size={16} /><span>{prompt}</span></div>
            ))}
          </div>
        </article>
      ))}
    </section>
  );
}

function CalendarView({ workspace }) {
  return (
    <section className="panel">
      <div className="panel-heading compact">
        <h2>Weekly Publishing Rhythm</h2>
        <CalendarDays size={18} />
      </div>
      <div className="calendar-grid">
        {(workspace.calendar || []).map((item) => (
          <article className="mini-card" key={item.id}>
            <span>{item.day}</span>
            <h3>{item.focus}</h3>
            <p>{item.target}</p>
            <small>{item.owner}</small>
          </article>
        ))}
      </div>
    </section>
  );
}

function HistoryView({ workspace }) {
  const entries = [
    ...(workspace.history || []),
    ...(workspace.generated || []).map((item) => ({ id: item.id, type: "draft", title: item.title, detail: item.keyword, timestamp: item.timestamp })),
    ...(workspace.journal || []).map((item) => ({ id: item.id, type: "journal", title: item.title, detail: item.body, timestamp: item.timestamp }))
  ].sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
  return (
    <section className="panel">
      <div className="panel-heading compact">
        <h2>Activity History</h2>
        <History size={18} />
      </div>
      <div className="timeline">
        {entries.map((item) => (
          <div className="timeline-item" key={`${item.type}-${item.id}`}>
            <span className={`badge ${statusTone(item.type)}`}>{item.type}</span>
            <div>
              <strong>{item.title}</strong>
              <p>{item.detail}</p>
              <small>{formatDate(item.timestamp)}</small>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
}

function AgentControlPanel({ selected }) {
  return (
    <div className="control-room">
      <div className="panel-heading">
        <div>
          <span className="eyeline">Control room</span>
          <h2>{selected.name}</h2>
        </div>
        <span className={`badge ${statusTone(statusLabel(selected))}`}>{statusLabel(selected)}</span>
      </div>
      <div className="room-body">
        <div className="agent-summary">
          <div className="orb" style={{ "--accent": selected.accent }}>
            <selected.icon size={28} />
          </div>
          <div>
            <h3>{selected.role}</h3>
            <p>{selected.description}</p>
          </div>
        </div>
        <div className="meta-grid">
          <Meta label="Installed" value={selected.installed === undefined ? "checking" : selected.installed ? "yes" : "not found"} />
          <Meta label="Running" value={selected.running === undefined ? "checking" : selected.running ? "yes" : "waiting"} />
          <Meta label="Version" value={selected.version || "unknown"} />
          <Meta label="Source" value={selected.source || "not detected"} />
        </div>
      </div>
    </div>
  );
}

function AgentCard({ agent, selected, onSelect, onLaunch }) {
  const Icon = agent.icon;
  const label = statusLabel(agent);
  return (
    <article className={`agent-card ${selected ? "selected" : ""}`} style={{ "--accent": agent.accent }}>
      <button className="card-hit" onClick={onSelect} aria-label={`Open ${agent.name}`} />
      <div className="card-glow" />
      <div className="card-top">
        <div className="agent-emblem"><Icon size={20} /></div>
        <span className={`badge ${statusTone(label)}`}>{label}</span>
      </div>
      <h2>{agent.name}</h2>
      <p>{agent.role}</p>
      <div className="mini-stats">
        <span><small>Installed</small><strong>{agent.installed === undefined ? "..." : agent.installed ? "yes" : "no"}</strong></span>
        <span><small>Running</small><strong>{agent.running === undefined ? "..." : agent.running ? "yes" : "no"}</strong></span>
      </div>
      <div className="card-actions">
        <button onClick={() => onLaunch(agent.id, agent.name)}>Open <ArrowUpRight size={14} /></button>
        <button onClick={onSelect}>Control <ChevronRight size={14} /></button>
      </div>
    </article>
  );
}

function SignalCard({ icon: Icon, label, value, detail, tone }) {
  return (
    <div className={`signal-card ${tone}`}>
      <Icon size={19} />
      <div>
        <span>{label}</span>
        <strong>{value}</strong>
        <small>{detail}</small>
      </div>
    </div>
  );
}

function Meta({ label, value }) {
  return (
    <div className="meta">
      <span>{label}</span>
      <strong title={value}>{value}</strong>
    </div>
  );
}

function Metric({ icon: Icon, label, value, pct }) {
  return (
    <div className="metric">
      <Icon size={17} />
      <div>
        <span>{label}</span>
        <strong>{value}</strong>
        <i><b style={{ width: `${Math.min(Number(pct) || 0, 100)}%` }} /></i>
      </div>
    </div>
  );
}

function PerformancePanel({ workspace }) {
  const drafted = workspace.generated?.length || 0;
  const queued = workspace.keywords?.filter((item) => item.status === "queued").length || 0;
  const published = workspace.keywords?.filter((item) => item.status === "published").length || 0;
  return (
    <div className="panel">
      <div className="panel-heading compact">
        <h2>Performance</h2>
        <Cpu size={18} />
      </div>
      <Metric icon={Search} label="Queued keywords" value={queued} pct={queued * 12} />
      <Metric icon={FileText} label="Drafts generated" value={drafted} pct={drafted * 18} />
      <Metric icon={Rocket} label="Published keywords" value={published} pct={published * 22} />
    </div>
  );
}

createRoot(document.getElementById("root")).render(<App />);
