// Ajna AI right-side panel — local LLM chat, model browser, system fit, copilot agent.
// Renders inside the desktop browser viewport on the right edge.

const AI_PANEL_W = 380;

// ─────────────────────────────────────────────
// System probe — synthesized "your machine" stats
// ─────────────────────────────────────────────
const SYSTEM = {
  name: 'MacBook Pro · M3 Pro',
  ramGB: 18,
  vramGB: 18,    // unified memory
  storageFreeGB: 412,
  cpu: 'Apple M3 Pro · 12-core',
  accel: 'Metal',
  // cap (in GB) the user's machine can comfortably hold for a quantized model in memory
  comfortGB: 12,
  maxGB: 16,
};

// ─────────────────────────────────────────────
// Model catalog — Hugging Face style
// `sizeGB` is approx weight-on-disk for the chosen quant; used for fit calc.
// ─────────────────────────────────────────────
const MODELS = [
  // ── Special: Ajna Copilot
  {
    id: 'ajna-copilot-7b',
    name: 'Ajna Copilot 7B',
    org: 'ajna-inc',
    file: 'ajna-copilot-7B-Q4_K_M.gguf',
    sizeGB: 4.4,
    params: '7B',
    quant: 'Q4_K_M',
    ctx: 32768,
    tag: 'browse',
    blurb: 'Browse-aware. Reads pages, clicks, fills, summarizes — all on-device.',
    badge: 'Recommended',
    accent: '#6EE7B7',
  },
  {
    id: 'ajna-copilot-3b',
    name: 'Ajna Copilot 3B',
    org: 'ajna-inc',
    file: 'ajna-copilot-3B-Q4_K_M.gguf',
    sizeGB: 1.9,
    params: '3B',
    quant: 'Q4_K_M',
    ctx: 16384,
    tag: 'browse',
    blurb: 'Lightweight browse agent for older or low-RAM machines.',
    accent: '#60A5FA',
  },
  // ── User's local
  {
    id: 'smollm2-1.7b',
    name: 'SmolLM2 1.7B Instruct',
    org: 'HuggingFaceTB',
    file: 'SmolLM2-1.7B-Instruct-Q5_K_M.gguf',
    sizeGB: 1.0,
    params: '1.7B',
    quant: 'Q5_K_M',
    ctx: 8192,
    tag: 'chat',
    blurb: 'Tiny, fast, friendly. Runs on almost anything.',
    installed: true,
  },
  // ── Trending
  { id: 'qwen3-7b',  name: 'Qwen3 7B Instruct',     org: 'Qwen', file: 'Qwen3-7B-Instruct-Q4_K_M.gguf',     sizeGB: 4.6,  params: '7B',  quant: 'Q4_K_M', ctx: 32768, tag: 'chat',  blurb: 'Strong general-purpose chat & reasoning.' },
  { id: 'llama32-3b', name: 'Llama 3.2 3B Instruct', org: 'meta-llama', file: 'Llama-3.2-3B-Instruct-Q4_K_M.gguf', sizeGB: 2.0, params: '3B', quant: 'Q4_K_M', ctx: 128000, tag: 'chat', blurb: 'Meta\'s small Llama. Long context, fast.' },
  { id: 'mistral-7b', name: 'Mistral 7B v0.3',       org: 'mistralai', file: 'Mistral-7B-Instruct-v0.3-Q4_K_M.gguf', sizeGB: 4.4, params: '7B', quant: 'Q4_K_M', ctx: 32768, tag: 'chat', blurb: 'Classic, well-rounded 7B baseline.' },
  { id: 'phi35-mini', name: 'Phi-3.5 Mini',          org: 'microsoft', file: 'Phi-3.5-mini-instruct-Q5_K_M.gguf', sizeGB: 2.7, params: '3.8B', quant: 'Q5_K_M', ctx: 128000, tag: 'chat', blurb: 'Microsoft\'s reasoning-tuned small model.' },
  { id: 'gemma2-9b',  name: 'Gemma 2 9B',            org: 'google',  file: 'gemma-2-9b-it-Q4_K_M.gguf',         sizeGB: 5.6, params: '9B',  quant: 'Q4_K_M', ctx: 8192,  tag: 'chat',  blurb: 'Google\'s Gemma — strong instruction-follower.' },
  { id: 'qwen3-coder', name: 'Qwen3 Coder 7B',       org: 'Qwen',    file: 'Qwen3-Coder-7B-Q4_K_M.gguf',        sizeGB: 4.5, params: '7B',  quant: 'Q4_K_M', ctx: 32768, tag: 'code',  blurb: 'Code-specialized — suggestions, explain, refactor.' },
  { id: 'deepseek-r1', name: 'DeepSeek R1 Distill 7B', org: 'deepseek-ai', file: 'DeepSeek-R1-Distill-Qwen-7B-Q4_K_M.gguf', sizeGB: 4.7, params: '7B', quant: 'Q4_K_M', ctx: 32768, tag: 'reason', blurb: 'Reasoning-distilled — thinks step by step.' },
  { id: 'qwen3-14b',  name: 'Qwen3 14B Instruct',    org: 'Qwen',    file: 'Qwen3-14B-Instruct-Q4_K_M.gguf',    sizeGB: 8.8, params: '14B', quant: 'Q4_K_M', ctx: 32768, tag: 'chat',  blurb: 'Bigger Qwen — sharper, slower, fits ≥16 GB unified.' },
  { id: 'qwen3-30b',  name: 'Qwen3 30B A3B MoE',     org: 'Qwen',    file: 'Qwen3-30B-A3B-Q4_K_M.gguf',         sizeGB: 17.6, params: '30B (3B active)', quant: 'Q4_K_M', ctx: 32768, tag: 'chat', blurb: 'Mixture-of-experts — 30B knowledge, 3B active.' },
  { id: 'llama33-70b', name: 'Llama 3.3 70B Instruct', org: 'meta-llama', file: 'Llama-3.3-70B-Instruct-Q4_K_M.gguf', sizeGB: 42.5, params: '70B', quant: 'Q4_K_M', ctx: 128000, tag: 'chat', blurb: 'Workstation-class. Needs ≥48 GB.' },
];

const TAG_META = {
  chat:   { label: 'Chat',   color: '#60A5FA' },
  browse: { label: 'Browse', color: '#6EE7B7' },
  code:   { label: 'Code',   color: '#FBBF24' },
  reason: { label: 'Reason', color: '#A78BFA' },
};

// Fit classification: ✓ runs / ⚠ tight / ✗ too big
function fitFor(sizeGB, sys = SYSTEM) {
  if (sizeGB <= sys.comfortGB) return { level: 'ok', label: 'Runs well', color: '#22D27A' };
  if (sizeGB <= sys.maxGB)     return { level: 'tight', label: 'Tight fit', color: '#FBBF24' };
  return { level: 'over', label: 'Too large', color: '#F87171' };
}

// ─────────────────────────────────────────────
// Header
// ─────────────────────────────────────────────
function AIHeader({ tab, setTab, onClose, onExpand, online }) {
  return (
    <div style={{
      padding: '14px 14px 10px',
      display: 'flex', flexDirection: 'column', gap: 12,
      background: 'transparent',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
        <AjnaMark size={18}/>
        <span style={{ fontSize: 13.5, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em' }}>Ajna AI</span>
        <div style={{ flex: 1 }}/>
        {onExpand && (
          <button onClick={onExpand} title="Open as app" style={{ background: 'transparent', border: 0, color: 'var(--fg-dim)', width: 26, height: 26, borderRadius: 7, cursor: 'pointer', display: 'grid', placeItems: 'center', padding: 0 }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2v-4M15 3h4a2 2 0 0 1 2 2v4"/><path d="M21 3l-8 8"/></svg>
          </button>
        )}
        <button onClick={onClose} style={{ background: 'transparent', border: 0, color: 'var(--fg-dim)', width: 26, height: 26, borderRadius: 7, cursor: 'pointer', display: 'grid', placeItems: 'center', padding: 0 }}>
          <Ic.x s={14}/>
        </button>
      </div>
      <div style={{ display: 'flex', gap: 16 }}>
        {[
          { id: 'chat',   label: 'Chat' },
          { id: 'models', label: 'Models' },
          { id: 'system', label: 'System' },
        ].map(t => (
          <button key={t.id} onClick={() => setTab(t.id)} style={{
            padding: '0 0 8px', background: 'transparent', border: 0,
            borderBottom: '1.5px solid ' + (tab === t.id ? 'var(--fg)' : 'transparent'),
            color: tab === t.id ? 'var(--fg)' : 'var(--fg-dim)',
            cursor: 'pointer', fontSize: 13, fontWeight: tab === t.id ? 600 : 500,
            fontFamily: 'inherit', letterSpacing: '-0.01em', marginBottom: -10,
          }}>{t.label}</button>
        ))}
        <div style={{ flex: 1, borderBottom: '1px solid var(--border-soft)', marginBottom: -10 }}/>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────
// Active model card (top of every tab)
// ─────────────────────────────────────────────
function ActiveModelCard({ model, onUnload, onSwitch }) {
  if (!model) {
    return (
      <div style={{
        margin: '12px 14px 0', padding: '14px',
        background: 'var(--bg-elev)', border: '1px dashed var(--border)',
        borderRadius: 12, display: 'flex', alignItems: 'center', gap: 10,
      }}>
        <div style={{ width: 32, height: 32, borderRadius: 8, background: 'var(--bg-elev-2)', display: 'grid', placeItems: 'center', color: 'var(--fg-dim)' }}><Ic.cloud s={16}/></div>
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 12.5, fontWeight: 500 }}>No model loaded</div>
          <div style={{ fontSize: 10.5, color: 'var(--fg-dim)' }}>Pick one from the Models tab</div>
        </div>
        <button onClick={onSwitch} style={pillBtn(true)}>Browse</button>
      </div>
    );
  }
  return (
    <div style={{
      margin: '12px 14px 0', padding: '12px 14px',
      background: 'linear-gradient(180deg, color-mix(in oklch, ' + (model.accent || 'var(--accent-a)') + ' 14%, var(--bg-elev)), var(--bg-elev))',
      border: '1px solid var(--border)', borderRadius: 12,
      display: 'flex', flexDirection: 'column', gap: 10,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{
          width: 32, height: 32, borderRadius: 8,
          background: model.accent || 'var(--accent-a)', color: '#0B0C0F',
          display: 'grid', placeItems: 'center', flexShrink: 0,
          boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.15)',
        }}>
          <span style={{ width: 8, height: 8, borderRadius: 4, background: '#0B0C0F', boxShadow: '0 0 8px rgba(0,0,0,0.4)' }}/>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{model.name}</div>
          <div style={{ fontSize: 10, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', marginTop: 1 }}>
            {model.params} · {model.quant} · ctx {Math.round(model.ctx/1024)}K
          </div>
        </div>
        <button onClick={onUnload} style={pillBtn(false)}>Unload</button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 6, fontSize: 10, fontFamily: 'JetBrains Mono, monospace' }}>
        <Stat k="Speed" v="42 t/s"/>
        <Stat k="RAM" v={model.sizeGB.toFixed(1) + ' GB'}/>
        <Stat k="Engine" v={SYSTEM.accel}/>
      </div>
    </div>
  );
}

function Stat({ k, v }) {
  return (
    <div style={{ background: 'var(--bg)', border: '1px solid var(--border-soft)', borderRadius: 6, padding: '6px 8px' }}>
      <div style={{ color: 'var(--fg-dim)', fontSize: 9, letterSpacing: '0.08em', textTransform: 'uppercase' }}>{k}</div>
      <div style={{ color: 'var(--fg)', fontSize: 11, marginTop: 1 }}>{v}</div>
    </div>
  );
}

const pillBtn = (primary) => ({
  padding: '5px 12px', borderRadius: 999,
  background: primary ? 'var(--accent-b)' : 'var(--bg)',
  color: primary ? '#0B0C0F' : 'var(--fg)',
  border: primary ? 0 : '1px solid var(--border-soft)',
  fontSize: 11, fontWeight: 600, fontFamily: 'inherit', cursor: 'pointer', flexShrink: 0,
});

// ─────────────────────────────────────────────
// Chat tab
// ─────────────────────────────────────────────
function AIChatTab({ model }) {
  const [input, setInput] = React.useState('');
  const [messages, setMessages] = React.useState([
    { role: 'assistant', text: 'I\'m running locally on your machine — no data leaves this device. Ask me about the page, or pick an action below.', browse: false },
  ]);

  const send = (text) => {
    const t = (text || input).trim();
    if (!t) return;
    setInput('');
    const userMsg = { role: 'user', text: t };
    const nextMessages = [...messages, userMsg];
    setMessages(nextMessages);
    // Simulated assistant reply
    setTimeout(() => {
      setMessages(m => [...m, {
        role: 'assistant',
        text: model && model.tag === 'browse'
          ? 'I can read this page and act on it. Try: “summarize”, “extract emails”, “fill the form with my profile”.'
          : 'Here\'s a thought on that. (Local model · ' + (model ? model.params : '—') + ')',
        cite: model && model.tag === 'browse' ? { url: 'huggingface.co/models', label: 'huggingface.co' } : null,
      }]);
    }, 280);
  };

  const actions = model && model.tag === 'browse' ? [
    { label: 'Summarize page', icon: Ic.bookmark },
    { label: 'Extract links',  icon: Ic.arrowRight },
    { label: 'Fill this form', icon: Ic.search },
  ] : [
    { label: 'Summarize page', icon: Ic.bookmark },
    { label: 'Translate',      icon: Ic.cloud },
    { label: 'Explain',        icon: Ic.search },
  ];

  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
      {/* tiny model line — no box, just a quiet status row */}
      <div style={{ padding: '2px 16px 0', display: 'flex', alignItems: 'center', gap: 7, fontSize: 10.5, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace' }}>
        {model ? (
          <>
            <span style={{ width: 6, height: 6, borderRadius: 3, background: model.accent || 'var(--accent-a)', boxShadow: '0 0 6px ' + (model.accent || 'var(--accent-a)'), flexShrink: 0 }}/>
            <span style={{ color: 'var(--fg-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{model.name}</span>
            <span style={{ flex: 1 }}/>
            <span>on-device</span>
          </>
        ) : (
          <>
            <span style={{ flex: 1 }}>No model loaded</span>
            <span>pick one in Models →</span>
          </>
        )}
      </div>

      <div style={{ flex: 1, padding: '14px 14px 12px', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 10, minHeight: 0 }}>
        {messages.length === 0 ? (
          // Minimal empty state — centered prompt + a few quiet suggestions
          <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center', textAlign: 'center', gap: 18, padding: '0 16px' }}>
            <div>
              <div style={{ fontSize: 16, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.02em', color: 'var(--fg)' }}>Ask anything</div>
              <div style={{ fontSize: 12.5, color: 'var(--fg-muted)', marginTop: 6, lineHeight: 1.5, maxWidth: 240 }}>Runs entirely on your device. Nothing leaves the browser.</div>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6, width: '100%', maxWidth: 240 }}>
              {actions.map(a => (
                <button key={a.label} onClick={() => send(a.label)} style={{
                  padding: '9px 12px', borderRadius: 9, textAlign: 'left',
                  background: 'transparent', border: '1px solid var(--border-soft)',
                  color: 'var(--fg)', fontSize: 12.5, fontFamily: 'inherit', cursor: 'pointer',
                }}
                  onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                  {a.label}
                </button>
              ))}
            </div>
          </div>
        ) : messages.map((m, i) => (
          <div key={i} style={{
            alignSelf: m.role === 'user' ? 'flex-end' : 'flex-start',
            maxWidth: '88%', padding: '8px 11px', borderRadius: 12,
            background: m.role === 'user' ? 'linear-gradient(135deg, var(--accent-a), var(--accent-b))' : 'var(--bg-elev)',
            color: m.role === 'user' ? '#0B0C0F' : 'var(--fg)',
            fontSize: 12.5, lineHeight: 1.45,
            border: m.role === 'user' ? 0 : '1px solid var(--border-soft)',
            fontWeight: m.role === 'user' ? 500 : 400,
          }}>
            {m.text}
            {m.cite && (
              <div style={{ marginTop: 6, paddingTop: 6, borderTop: '1px solid var(--border-soft)', fontSize: 10, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', display: 'flex', alignItems: 'center', gap: 4 }}>
                <Ic.bookmark s={9}/> {m.cite.label}
              </div>
            )}
          </div>
        ))}
      </div>
      <div style={{ padding: '8px 14px 14px', background: 'transparent' }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 8,
          padding: '8px 10px 8px 14px', background: 'var(--bg)',
          border: '1px solid var(--border-soft)', borderRadius: 14,
        }}>
          <input
            value={input}
            onChange={e => setInput(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && send()}
            placeholder={model ? 'Ask ' + model.name.split(' ')[0] + '…' : 'Pick a model first…'}
            disabled={!model}
            style={{
              flex: 1, background: 'transparent', border: 0, outline: 0,
              color: 'var(--fg)', fontSize: 12.5, fontFamily: 'inherit',
            }}
          />
          <button onClick={() => send()} disabled={!model || !input.trim()} style={{
            width: 28, height: 28, borderRadius: 8,
            background: model && input.trim() ? 'var(--accent-b)' : 'var(--bg-elev-2)',
            color: model && input.trim() ? '#0B0C0F' : 'var(--fg-dim)',
            border: 0, cursor: model && input.trim() ? 'pointer' : 'default',
            display: 'grid', placeItems: 'center', flexShrink: 0,
          }}><Ic.arrowRight s={13}/></button>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────
// Models tab — system fit, search/filters, list
// ─────────────────────────────────────────────
function AIModelsTab({ active, setActive, downloads, setDownloads, wide }) {
  const [query, setQuery] = React.useState('');
  const [filter, setFilter] = React.useState('all'); // all | fit | browse | code | reason
  const [source, setSource] = React.useState('hf');  // hf | local

  const list = MODELS.filter(m => {
    if (source === 'local' && !(m.installed || downloads[m.id] === 'done')) return false;
    if (filter === 'fit') {
      const f = fitFor(m.sizeGB);
      if (f.level === 'over') return false;
    } else if (filter !== 'all' && m.tag !== filter) return false;
    if (query && !(m.name + ' ' + m.org + ' ' + m.file).toLowerCase().includes(query.toLowerCase())) return false;
    return true;
  });

  return (
    <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
      <ActiveModelCard model={active} onUnload={() => setActive(null)}/>

      {/* System-fit banner */}
      <div style={{
        margin: '12px 14px 0', padding: '10px 12px',
        background: 'var(--bg-elev)', border: '1px solid var(--border-soft)',
        borderRadius: 10, display: 'flex', alignItems: 'center', gap: 10,
        fontSize: 11,
      }}>
        <div style={{ color: 'var(--accent-a)' }}><Ic.bolt s={14}/></div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ color: 'var(--fg)', fontWeight: 500 }}>{SYSTEM.name}</div>
          <div style={{ color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', fontSize: 10, marginTop: 1 }}>
            {SYSTEM.ramGB} GB · {SYSTEM.accel} · comfort up to ~{SYSTEM.comfortGB} GB
          </div>
        </div>
        <button onClick={() => setFilter(filter === 'fit' ? 'all' : 'fit')} style={{
          padding: '4px 9px', borderRadius: 999,
          background: filter === 'fit' ? 'var(--accent-b)' : 'var(--bg)',
          color: filter === 'fit' ? '#0B0C0F' : 'var(--fg-muted)',
          border: filter === 'fit' ? 0 : '1px solid var(--border-soft)',
          fontSize: 10, fontWeight: 600, fontFamily: 'inherit', cursor: 'pointer',
        }}>{filter === 'fit' ? 'Showing fit ✓' : 'Fits my system'}</button>
      </div>

      {/* search + source + filters */}
      <div style={{ padding: '10px 14px 0', display: 'flex', flexDirection: 'column', gap: 8 }}>
        <div style={{ display: 'flex', gap: 6 }}>
          <div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 6, padding: '6px 10px', background: 'var(--bg-elev)', border: '1px solid var(--border-soft)', borderRadius: 8 }}>
            <Ic.search s={13}/>
            <input value={query} onChange={e => setQuery(e.target.value)} placeholder="Search Hugging Face…" style={{ flex: 1, background: 'transparent', border: 0, outline: 0, color: 'var(--fg)', fontSize: 12, fontFamily: 'inherit' }}/>
            <span style={{ fontSize: 9, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace' }}>HF</span>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 4, alignItems: 'center', overflowX: 'auto', paddingBottom: 2 }}>
          {[
            { id: 'all',    label: 'All' },
            { id: 'browse', label: 'Browse' },
            { id: 'chat',   label: 'Chat' },
            { id: 'code',   label: 'Code' },
            { id: 'reason', label: 'Reason' },
          ].map(f => (
            <button key={f.id} onClick={() => setFilter(f.id)} style={{
              padding: '4px 10px', borderRadius: 999, fontSize: 11, fontFamily: 'inherit', cursor: 'pointer',
              background: filter === f.id ? 'var(--bg-elev)' : 'transparent',
              color: filter === f.id ? 'var(--fg)' : 'var(--fg-muted)',
              border: '1px solid ' + (filter === f.id ? 'var(--border)' : 'var(--border-soft)'),
            }}>{f.label}</button>
          ))}
          <div style={{ flex: 1 }}/>
          <div style={{ display: 'inline-flex', padding: 2, background: 'var(--bg-elev)', borderRadius: 7, border: '1px solid var(--border-soft)' }}>
            {[{id:'hf', label:'Hugging Face'}, {id:'local', label:'Installed'}].map(s => (
              <button key={s.id} onClick={() => setSource(s.id)} style={{
                padding: '3px 8px', borderRadius: 5, fontSize: 10.5, fontFamily: 'inherit', cursor: 'pointer',
                background: source === s.id ? 'var(--bg)' : 'transparent',
                color: source === s.id ? 'var(--fg)' : 'var(--fg-muted)',
                border: 0,
              }}>{s.label}</button>
            ))}
          </div>
        </div>
      </div>

      <div style={{ flex: 1, padding: '10px 14px 14px', overflowY: 'auto', minHeight: 0, ...(wide
        ? { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(320px, 1fr))', gap: 10, alignContent: 'start' }
        : { display: 'flex', flexDirection: 'column', gap: 8 }) }}>
        {list.map(m => (
          <ModelCard
            key={m.id}
            model={m}
            isActive={active && active.id === m.id}
            installed={m.installed || downloads[m.id] === 'done'}
            progress={typeof downloads[m.id] === 'number' ? downloads[m.id] : null}
            onLoad={() => setActive(m)}
            onDownload={() => startDownload(m, downloads, setDownloads)}
          />
        ))}
        {list.length === 0 && (
          <div style={{ textAlign: 'center', padding: 30, color: 'var(--fg-dim)', fontSize: 12 }}>
            No models match. Try clearing filters.
          </div>
        )}
      </div>
    </div>
  );
}

function startDownload(model, downloads, setDownloads) {
  if (downloads[model.id] === 'done' || typeof downloads[model.id] === 'number') return;
  setDownloads(d => ({ ...d, [model.id]: 0 }));
  let pct = 0;
  const tick = () => {
    pct += 4 + Math.random() * 9;
    if (pct >= 100) {
      setDownloads(d => ({ ...d, [model.id]: 'done' }));
      return;
    }
    setDownloads(d => ({ ...d, [model.id]: pct }));
    setTimeout(tick, 220);
  };
  setTimeout(tick, 180);
}

function ModelCard({ model, isActive, installed, progress, onLoad, onDownload }) {
  const fit = fitFor(model.sizeGB);
  const tag = TAG_META[model.tag] || TAG_META.chat;
  const downloading = typeof progress === 'number';

  return (
    <div style={{
      padding: '11px 12px', borderRadius: 10,
      background: isActive ? 'color-mix(in oklch, var(--accent-b) 12%, var(--bg-elev))' : 'var(--bg-elev)',
      border: '1px solid ' + (isActive ? 'color-mix(in oklch, var(--accent-b) 35%, var(--border))' : 'var(--border-soft)'),
      display: 'flex', flexDirection: 'column', gap: 8,
    }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 8 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>
            <span style={{ fontSize: 12.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{model.name}</span>
            {model.badge && <span style={{ fontSize: 9, fontWeight: 700, color: '#0B0C0F', background: 'var(--accent-a)', padding: '1px 5px', borderRadius: 3, letterSpacing: '0.05em', textTransform: 'uppercase' }}>{model.badge}</span>}
          </div>
          <div style={{ fontSize: 10.5, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
            {model.org}/{model.file}
          </div>
        </div>
        <span style={{
          fontSize: 9.5, fontWeight: 600, padding: '2px 6px', borderRadius: 4,
          color: tag.color, background: tag.color + '1F', textTransform: 'uppercase', letterSpacing: '0.06em',
          flexShrink: 0,
        }}>{tag.label}</span>
      </div>

      <div style={{ fontSize: 11.5, color: 'var(--fg-muted)', lineHeight: 1.4 }}>{model.blurb}</div>

      <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 10, fontFamily: 'JetBrains Mono, monospace', color: 'var(--fg-dim)', flexWrap: 'wrap' }}>
        <span>{model.params}</span>
        <span>·</span>
        <span>{model.quant}</span>
        <span>·</span>
        <span>{model.sizeGB.toFixed(1)} GB</span>
        <span>·</span>
        <span>ctx {Math.round(model.ctx/1024)}K</span>
        <span style={{ flex: 1 }}/>
        <span style={{
          display: 'inline-flex', alignItems: 'center', gap: 4,
          color: fit.color, background: fit.color + '1A',
          padding: '1px 6px', borderRadius: 4, fontWeight: 600,
        }}>
          <span style={{ width: 4, height: 4, borderRadius: 2, background: fit.color }}/>
          {fit.label}
        </span>
      </div>

      {downloading && (
        <div>
          <div style={{ height: 4, borderRadius: 2, background: 'var(--bg)', overflow: 'hidden' }}>
            <div style={{ width: progress + '%', height: '100%', background: 'linear-gradient(90deg, var(--accent-a), var(--accent-b))', transition: 'width 200ms linear' }}/>
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 9.5, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', marginTop: 3 }}>
            <span>Downloading from huggingface.co</span>
            <span>{Math.round(progress)}% · {(model.sizeGB * progress / 100).toFixed(1)} / {model.sizeGB.toFixed(1)} GB</span>
          </div>
        </div>
      )}

      <div style={{ display: 'flex', gap: 6, alignItems: 'center' }}>
        {installed ? (
          isActive ? (
            <span style={{ fontSize: 10.5, color: 'var(--accent-a)', fontFamily: 'JetBrains Mono, monospace', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
              <span style={{ width: 6, height: 6, borderRadius: 3, background: 'var(--accent-a)', boxShadow: '0 0 6px var(--accent-a)' }}/> Loaded · ready
            </span>
          ) : (
            <button onClick={onLoad} style={pillBtn(true)}>Load</button>
          )
        ) : downloading ? (
          <button disabled style={{ ...pillBtn(false), opacity: 0.7, cursor: 'default' }}>Downloading…</button>
        ) : fit.level === 'over' ? (
          <button onClick={onDownload} style={{ ...pillBtn(false), color: 'var(--fg-dim)' }}>Force download</button>
        ) : (
          <button onClick={onDownload} style={pillBtn(true)}>Download · {model.sizeGB.toFixed(1)} GB</button>
        )}
        <button style={{ ...pillBtn(false), padding: '5px 9px' }} title="View on Hugging Face">↗</button>
        <div style={{ flex: 1 }}/>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────
// System tab — device probe, runtime, privacy
// ─────────────────────────────────────────────
function AISystemTab({ runtime, setRuntime }) {
  return (
    <div style={{ flex: 1, padding: '14px', overflowY: 'auto', display: 'flex', flexDirection: 'column', gap: 14 }}>
      <Section title="Your Device">
        <Row k="Machine" v={SYSTEM.name}/>
        <Row k="CPU"     v={SYSTEM.cpu}/>
        <Row k="Memory"  v={SYSTEM.ramGB + ' GB unified'}/>
        <Row k="Acceleration" v={SYSTEM.accel + ' · GPU offload on'}/>
        <Row k="Free disk" v={SYSTEM.storageFreeGB + ' GB'}/>
      </Section>

      <Section title="What you can run">
        <FitMeter/>
        <div style={{ fontSize: 11, color: 'var(--fg-muted)', marginTop: 8, lineHeight: 1.5 }}>
          Up to ~{SYSTEM.comfortGB} GB models run smoothly. {SYSTEM.maxGB} GB is tight.
          Bigger models still load but may swap to disk.
        </div>
      </Section>

      <Section title="Runtime">
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>
          {[
            { id: 'metal', label: 'Metal (GPU)', sub: 'Recommended' },
            { id: 'cpu',   label: 'CPU only',    sub: 'Slower, no GPU' },
          ].map(r => (
            <button key={r.id} onClick={() => setRuntime(r.id)} style={{
              padding: '10px 12px', borderRadius: 10, textAlign: 'left',
              background: runtime === r.id ? 'color-mix(in oklch, var(--accent-b) 14%, var(--bg-elev))' : 'var(--bg-elev)',
              border: '1px solid ' + (runtime === r.id ? 'color-mix(in oklch, var(--accent-b) 40%, var(--border))' : 'var(--border-soft)'),
              color: 'var(--fg)', cursor: 'pointer', fontFamily: 'inherit',
            }}>
              <div style={{ fontSize: 12, fontWeight: 600 }}>{r.label}</div>
              <div style={{ fontSize: 10, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', marginTop: 2 }}>{r.sub}</div>
            </button>
          ))}
        </div>
      </Section>

      <Section title="Privacy">
        <ToggleRow label="Stay local" sub="Never send prompts to a remote API." on/>
        <ToggleRow label="Allow page reading" sub="Let Ajna Copilot see the active tab." on/>
        <ToggleRow label="Allow page acting" sub="Click, fill, navigate on your behalf." on={false}/>
        <ToggleRow label="Telemetry" sub="Anonymous model-usage stats (off by default)." on={false}/>
      </Section>

      <Section title="Storage">
        <div style={{ fontSize: 11, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', marginBottom: 6 }}>
          ~/Library/Ajna/models
        </div>
        <Row k="Models on disk" v="2 · 5.4 GB"/>
        <Row k="Cache" v="612 MB"/>
        <button style={{ ...pillBtn(false), marginTop: 8, alignSelf: 'flex-start' }}>Manage…</button>
      </Section>
    </div>
  );
}

function Section({ title, children }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <div style={{ fontSize: 10, fontWeight: 600, color: 'var(--fg-dim)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 8, paddingLeft: 2 }}>{title}</div>
      <div style={{ background: 'var(--bg-elev)', border: '1px solid var(--border-soft)', borderRadius: 10, padding: '10px 12px', display: 'flex', flexDirection: 'column', gap: 6 }}>
        {children}
      </div>
    </div>
  );
}

function Row({ k, v }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '4px 0' }}>
      <span style={{ fontSize: 11.5, color: 'var(--fg-muted)' }}>{k}</span>
      <span style={{ flex: 1, height: 1, background: 'var(--border-soft)' }}/>
      <span style={{ fontSize: 11.5, color: 'var(--fg)', fontFamily: 'JetBrains Mono, monospace' }}>{v}</span>
    </div>
  );
}

function ToggleRow({ label, sub, on: defaultOn }) {
  const [on, setOn] = React.useState(!!defaultOn);
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '6px 0' }}>
      <div style={{ flex: 1 }}>
        <div style={{ fontSize: 12, fontWeight: 500 }}>{label}</div>
        {sub && <div style={{ fontSize: 10.5, color: 'var(--fg-dim)', marginTop: 1 }}>{sub}</div>}
      </div>
      <button onClick={() => setOn(!on)} style={{
        width: 32, height: 18, borderRadius: 999, position: 'relative', flexShrink: 0,
        background: on ? 'linear-gradient(135deg, var(--accent-a), var(--accent-b))' : 'var(--bg-elev-2)',
        border: 0, cursor: 'pointer', padding: 0,
      }}>
        <div style={{ position: 'absolute', top: 2, left: on ? 16 : 2, width: 14, height: 14, borderRadius: '50%', background: '#fff', transition: 'left 160ms' }}/>
      </button>
    </div>
  );
}

function FitMeter() {
  // visual showing your machine vs model sizes
  const items = [
    { label: '1B–3B',  sizeGB: 2,   sub: 'instant' },
    { label: '7B',     sizeGB: 4.5, sub: 'fast' },
    { label: '13B',    sizeGB: 8,   sub: 'good' },
    { label: '30B MoE', sizeGB: 17, sub: 'tight' },
    { label: '70B',    sizeGB: 42,  sub: 'too big' },
  ];
  const max = 48;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
      {items.map(i => {
        const f = fitFor(i.sizeGB);
        const w = Math.min(100, (i.sizeGB / max) * 100);
        return (
          <div key={i.label} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11 }}>
            <span style={{ width: 50, color: 'var(--fg-muted)', fontFamily: 'JetBrains Mono, monospace', fontSize: 10.5 }}>{i.label}</span>
            <div style={{ flex: 1, height: 8, borderRadius: 4, background: 'var(--bg)', position: 'relative', overflow: 'hidden' }}>
              <div style={{
                position: 'absolute', left: 0, top: 0, bottom: 0,
                width: w + '%',
                background: f.level === 'ok' ? 'linear-gradient(90deg, #22D27A, #6EE7B7)'
                          : f.level === 'tight' ? 'linear-gradient(90deg, #FBBF24, #F59E0B)'
                          : 'linear-gradient(90deg, #F87171, #DC2626)',
              }}/>
              <div style={{
                position: 'absolute', left: ((SYSTEM.comfortGB / max) * 100) + '%', top: -2, bottom: -2,
                width: 1, background: 'var(--fg)', opacity: 0.3,
              }}/>
            </div>
            <span style={{ width: 56, textAlign: 'right', fontFamily: 'JetBrains Mono, monospace', fontSize: 10, color: f.color }}>{f.label}</span>
          </div>
        );
      })}
      <div style={{ fontSize: 9.5, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', textAlign: 'center', marginTop: 4 }}>
        The vertical line marks your comfort threshold.
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────
// Root
// ─────────────────────────────────────────────
function AIPanel({ open, onClose, onExpand }) {
  const [tab, setTab] = React.useState('models');
  const [activeModel, setActiveModel] = React.useState(MODELS.find(m => m.installed) || null);
  const [downloads, setDownloads] = React.useState({});
  const [runtime, setRuntime] = React.useState('metal');

  if (!open) return null;

  return (
    <aside className="glass" style={{
      width: AI_PANEL_W, height: '100%', flexShrink: 0,
      borderRadius: 14, overflow: 'hidden',
      display: 'flex', flexDirection: 'column',
      fontFamily: 'Inter, system-ui, sans-serif',
      animation: 'aiSlide 220ms cubic-bezier(0.2,0.8,0.2,1)',
    }}>
      <style>{`@keyframes aiSlide { from { transform: translateX(20px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }`}</style>
      <AIHeader tab={tab} setTab={setTab} onClose={onClose} onExpand={onExpand} online={true}/>
      {tab === 'chat'   && <AIChatTab model={activeModel}/>}
      {tab === 'models' && <AIModelsTab active={activeModel} setActive={setActiveModel} downloads={downloads} setDownloads={setDownloads}/>}
      {tab === 'system' && <AISystemTab runtime={runtime} setRuntime={setRuntime}/>}
    </aside>
  );
}

// Full-page app — ajna://ai. Sidebar is the user's chat history; models and
// system live behind the header picker, not as top-level tabs.
const AI_THREADS = [
  { id: 'h1', title: 'Summarize the Chromium docs page', model: 'Ajna Copilot 7B', when: 'Today', preview: 'Three takeaways: sandboxing model, site isolation…' },
  { id: 'h2', title: 'Extract emails from this invoice', model: 'Ajna Copilot 7B', when: 'Today', preview: 'Found 4 addresses, copied to clipboard.' },
  { id: 'h3', title: 'Rewrite the release note', model: 'SmolLM2 1.7B', when: 'Yesterday', preview: 'Shorter, active voice, no marketing adjectives.' },
  { id: 'h4', title: 'Explain this stack trace', model: 'Qwen3 Coder 7B', when: 'Yesterday', preview: 'The null came from the memoized selector…' },
  { id: 'h5', title: 'Translate the Figma handoff notes', model: 'SmolLM2 1.7B', when: 'Mon', preview: 'German → English, kept the token names.' },
  { id: 'h6', title: 'Compare two pricing pages', model: 'Ajna Copilot 7B', when: 'Apr 21', preview: 'Per-seat vs usage; break-even at ~38 seats.' },
];

function AIPage({ sidebarPinned, onToggleSidebar }) {
  const [activeModel, setActiveModel] = React.useState(MODELS.find(m => m.installed) || null);
  const [downloads, setDownloads] = React.useState({});
  const [runtime, setRuntime] = React.useState('metal');
  const [threadId, setThreadId] = React.useState(AI_THREADS[0].id);
  const [overlay, setOverlay] = React.useState(null); // 'models' | 'system'
  const [picker, setPicker] = React.useState(false);
  const selectThread = (id) => { setThreadId(id); setOverlay(null); };

  const installed = MODELS.filter(m => m.installed || downloads[m.id] === 'done');
  const thread = AI_THREADS.find(t => t.id === threadId);
  const groups = AI_THREADS.reduce((acc, t) => {
    (acc[t.when] = acc[t.when] || []).push(t);
    return acc;
  }, {});

  return (
    <div style={{ height: '100%', display: 'flex', fontFamily: 'Inter, system-ui, sans-serif', color: 'var(--fg)' }}>
      {/* Chat history */}
      <div style={{
        width: 264, flexShrink: 0, borderRight: '1px solid var(--border-soft)',
        display: 'flex', flexDirection: 'column', background: 'var(--bg-elev)', minHeight: 0,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '16px 12px 12px' }}>
          <button onClick={onToggleSidebar} title={sidebarPinned ? 'Hide sidebar' : 'Show sidebar'} style={{
            width: 26, height: 26, borderRadius: 7, border: 0, cursor: 'pointer', padding: 0, flexShrink: 0,
            background: sidebarPinned ? 'oklch(from var(--accent-b) l c h / 0.16)' : 'transparent',
            color: sidebarPinned ? 'var(--accent-b)' : 'var(--fg-dim)', display: 'grid', placeItems: 'center',
          }}>
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="16" rx="2.5"/><path d="M9 4v16"/></svg>
          </button>
          <AjnaMark size={18}/>
          <span style={{ fontSize: 13.5, fontWeight: 600, fontFamily: 'Geist, Inter, sans-serif', letterSpacing: '-0.01em', flex: 1 }}>Ajna AI</span>
        </div>
        <div style={{ padding: '0 12px 10px' }}>
          <button onClick={() => selectThread(null)} style={{
            width: '100%', display: 'flex', alignItems: 'center', gap: 8,
            padding: '8px 10px', borderRadius: 9, border: 0, cursor: 'pointer',
            background: 'var(--bg-elev-2)', color: 'var(--fg)', fontFamily: 'inherit',
            fontSize: 12.5, fontWeight: 600, textAlign: 'left',
          }}><Ic.plus s={14}/> New chat</button>
        </div>
        <div style={{ flex: 1, overflowY: 'auto', minHeight: 0, padding: '0 8px 12px' }}>
          {Object.entries(groups).map(([when, items]) => (
            <div key={when}>
              <div style={{
                fontSize: 9.5, fontWeight: 600, letterSpacing: '0.12em', textTransform: 'uppercase',
                color: 'var(--fg-dim)', padding: '10px 6px 5px',
              }}>{when}</div>
              {items.map(t => (
                <button key={t.id} onClick={() => selectThread(t.id)} style={{
                  width: '100%', textAlign: 'left', padding: '8px 8px', borderRadius: 9,
                  border: 0, cursor: 'pointer', fontFamily: 'inherit', marginBottom: 1,
                  background: threadId === t.id ? 'oklch(from var(--accent-b) l c h / 0.14)' : 'transparent',
                  color: 'var(--fg)',
                }}
                onMouseEnter={e => { if (threadId !== t.id) e.currentTarget.style.background = 'var(--hover)'; }}
                onMouseLeave={e => { if (threadId !== t.id) e.currentTarget.style.background = 'transparent'; }}>
                  <div style={{ fontSize: 12.5, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{t.title}</div>
                  <div style={{ fontSize: 10, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', marginTop: 3, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{t.model}</div>
                </button>
              ))}
            </div>
          ))}
        </div>
      </div>

      {/* Conversation */}
      <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', minHeight: 0, position: 'relative' }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10, padding: '12px 16px',
          borderBottom: '1px solid var(--border-soft)',
        }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
              {thread ? thread.title : 'New chat'}
            </div>
            <div style={{ fontSize: 10, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace', marginTop: 2 }}>
              on-device · nothing leaves this machine
            </div>
          </div>
          {/* Model picker */}
          <div style={{ position: 'relative' }}>
            <button onClick={() => setPicker(p => !p)} style={{
              display: 'flex', alignItems: 'center', gap: 8, padding: '6px 10px',
              borderRadius: 9, background: 'var(--bg-elev)', border: '1px solid var(--border-soft)',
              color: 'var(--fg)', fontFamily: 'inherit', fontSize: 12, cursor: 'pointer',
            }}>
              <span style={{ width: 7, height: 7, borderRadius: 4, background: activeModel ? (activeModel.accent || 'var(--accent-a)') : 'var(--fg-dim)' }}/>
              <span style={{ fontWeight: 600 }}>{activeModel ? activeModel.name : 'No model'}</span>
              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6"/></svg>
            </button>
            {picker && (
              <>
                <div onClick={() => setPicker(false)} style={{ position: 'fixed', inset: 0, zIndex: 40 }}/>
                <div className="glass" style={{
                  position: 'absolute', top: 38, right: 0, width: 280, zIndex: 41,
                  borderRadius: 12, padding: 6, border: '1px solid var(--border-soft)',
                }}>
                  <div style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--fg-dim)', padding: '6px 8px' }}>Installed</div>
                  {installed.map(m => (
                    <button key={m.id} onClick={() => { setActiveModel(m); setPicker(false); }} style={{
                      width: '100%', textAlign: 'left', display: 'flex', alignItems: 'center', gap: 9,
                      padding: '8px 8px', borderRadius: 8, border: 0, cursor: 'pointer',
                      background: activeModel && activeModel.id === m.id ? 'var(--hover)' : 'transparent',
                      color: 'var(--fg)', fontFamily: 'inherit',
                    }}
                    onMouseEnter={e => e.currentTarget.style.background = 'var(--hover)'}
                    onMouseLeave={e => { if (!(activeModel && activeModel.id === m.id)) e.currentTarget.style.background = 'transparent'; }}>
                      <span style={{ width: 7, height: 7, borderRadius: 4, background: m.accent || 'var(--accent-a)', flexShrink: 0 }}/>
                      <span style={{ flex: 1, minWidth: 0 }}>
                        <span style={{ display: 'block', fontSize: 12.5, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{m.name}</span>
                        <span style={{ display: 'block', fontSize: 10, color: 'var(--fg-dim)', fontFamily: 'JetBrains Mono, monospace' }}>{m.params} · {m.quant} · {m.sizeGB.toFixed(1)} GB</span>
                      </span>
                    </button>
                  ))}
                  <div style={{ height: 1, background: 'var(--border-soft)', margin: '6px 8px' }}/>
                  <button onClick={() => { setPicker(false); setOverlay('models'); }} style={pickerAction()}>Browse models…</button>
                  <button onClick={() => { setPicker(false); setOverlay('system'); }} style={pickerAction()}>System & privacy…</button>
                </div>
              </>
            )}
          </div>
        </div>

        <div style={{ flex: 1, minHeight: 0, display: 'flex', justifyContent: 'center' }}>
          <div style={{ width: '100%', maxWidth: 760, display: 'flex', flexDirection: 'column', minHeight: 0, padding: '8px 0' }}>
            <AIChatTab key={threadId || 'new'} model={activeModel}/>
          </div>
        </div>

        {overlay && (
          <div style={{
            position: 'absolute', inset: 0, background: 'var(--stage)', zIndex: 50,
            display: 'flex', flexDirection: 'column', minHeight: 0,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 16px', borderBottom: '1px solid var(--border-soft)' }}>
              <span style={{ fontSize: 13, fontWeight: 600 }}>{overlay === 'models' ? 'Models' : 'System & privacy'}</span>
              <div style={{ flex: 1 }}/>
              <button onClick={() => setOverlay(null)} style={{
                width: 26, height: 26, borderRadius: 7, border: 0, cursor: 'pointer', padding: 0,
                background: 'transparent', color: 'var(--fg-dim)', display: 'grid', placeItems: 'center',
              }}><Ic.x s={14}/></button>
            </div>
            {overlay === 'models'
              ? <AIModelsTab wide active={activeModel} setActive={setActiveModel} downloads={downloads} setDownloads={setDownloads}/>
              : (
                <div style={{ flex: 1, minHeight: 0, display: 'flex', justifyContent: 'center', overflow: 'hidden' }}>
                  <div style={{ width: '100%', maxWidth: 720, display: 'flex', flexDirection: 'column', minHeight: 0 }}>
                    <AISystemTab runtime={runtime} setRuntime={setRuntime}/>
                  </div>
                </div>
              )}
          </div>
        )}
      </div>
    </div>
  );
}

function pickerAction() {
  return {
    width: '100%', textAlign: 'left', padding: '8px 8px', borderRadius: 8,
    border: 0, cursor: 'pointer', background: 'transparent',
    color: 'var(--fg-muted)', fontFamily: 'inherit', fontSize: 12,
  };
}

Object.assign(window, { AIPanel, AIPage, AI_PANEL_W });
