// assets/screen_prompts.jsx — Prompt Studio shell + Versions + Editor + Diff + Markdown
// Sections: Versions · Editor · Generate · Feedback · Skills · Ops

function ScreenPrompts({ t }) {
  const [agent, setAgent] = React.useState('landing_page');
  const [section, setSection] = React.useState('versions');
  // Live, mutable version store (so activate / save-draft feel real)
  const [versions, setVersions] = React.useState(() => JSON.parse(JSON.stringify(PROMPT_VERSIONS)));
  const [toastUi, pushToast] = usePromptToasts();

  const agentVersions = versions[agent];
  const active = agentVersions.find(v => v.status === 'active');

  const activateVersion = (id) => {
    setVersions(prev => {
      const next = JSON.parse(JSON.stringify(prev));
      next[agent] = next[agent].map(v => ({
        ...v,
        status: v.id === id ? 'active' : (v.status === 'active' ? 'archived' : v.status),
      }));
      return next;
    });
    pushToast({ kind: 'success', icon: <Icon name="check2" size={13} />, message: `Activated ${id} · Redis cache invalidated` });
  };

  const addDraft = (content, note, fromV) => {
    const maxV = Math.max(...agentVersions.map(v => v.v));
    const newV = maxV + 1;
    const draft = {
      id: `${agent}_v${newV}`, agent, v: newV, status: 'draft', content,
      author: 'huy', created_at: Date.now(), note: note || 'New draft',
      impact: { sessions: 0, projects: 0, stores: 0 },
      cost: { avg_tokens: Math.round(content.length / 4), avg_cost_cents: 0 },
      feedback: { up: 0, down: 0 }, derived_from: fromV,
    };
    setVersions(prev => {
      const next = JSON.parse(JSON.stringify(prev));
      next[agent] = [draft, ...next[agent]];
      return next;
    });
    pushToast({ kind: 'success', icon: <Icon name="check2" size={13} />, message: `Saved draft ${draft.id} (not active — needs review)` });
    return draft;
  };

  const archiveVersion = (id) => {
    setVersions(prev => {
      const next = JSON.parse(JSON.stringify(prev));
      next[agent] = next[agent].map(v => v.id === id ? { ...v, status: 'archived' } : v);
      return next;
    });
    pushToast({ kind: 'success', icon: <Icon name="check" size={13} />, message: `Archived ${id}` });
  };

  const SECTIONS = [
    { id: 'versions', label: 'Versions', icon: 'trace', badge: agentVersions.length },
    { id: 'editor',   label: 'Editor',   icon: 'edit' },
    { id: 'generate', label: 'Generate', icon: 'zap' },
    { id: 'feedback', label: 'Feedback', icon: 'message', badge: PROMPT_FEEDBACK.filter(f => f.agent === agent).length },
    { id: 'skills',   label: 'Skills',   icon: 'layers', badge: PROMPT_SKILLS[agent].length },
    { id: 'ops',      label: 'Ops',      icon: 'cpu' },
  ];

  return (
    <div className="page" style={{ maxWidth: 'none', display: 'flex', flexDirection: 'column', height: '100%', paddingBottom: 0, minHeight: 0 }}>
      {/* Header */}
      <div className="page-head" style={{ flexShrink: 0 }}>
        <h1>Prompt Studio</h1>
        <span className="page-sub" style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
          <span style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--success)' }} className="live-pulse" />
          backend-v3 connected
        </span>
        <div className="page-actions">
          <button className="btn ghost" onClick={() => setSection('ops')}><Icon name="cpu" size={12} /> Cache &amp; ops</button>
          <button className="btn primary" onClick={() => setSection('generate')}><Icon name="zap" size={12} /> Generate with AI</button>
        </div>
      </div>

      {/* Agent selector */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 12, flexShrink: 0 }}>
        {Object.values(AGENT_META).map(a => {
          const vs = versions[a.name];
          const act = vs.find(v => v.status === 'active');
          const hasDraft = vs.some(v => v.status === 'draft');
          const isSel = agent === a.name;
          return (
            <button key={a.name} onClick={() => setAgent(a.name)}
              style={{ flex: 1, textAlign: 'left', padding: '12px 16px', borderRadius: 'var(--radius-lg)', cursor: 'pointer',
                border: '1px solid', borderColor: isSel ? 'var(--accent)' : 'var(--border-subtle)',
                background: isSel ? 'var(--accent-muted)' : 'var(--bg-surface)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <div style={{ width: 30, height: 30, borderRadius: 8, background: isSel ? 'var(--accent)' : 'var(--bg-elevated)', color: isSel ? 'var(--accent-fg)' : 'var(--text-secondary)', display: 'grid', placeItems: 'center', flexShrink: 0 }}>
                  <Icon name={a.icon} size={15} />
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontWeight: 600, fontSize: 13.5, color: isSel ? 'var(--text-primary)' : 'var(--text-primary)' }}>{a.title}</div>
                  <div className="dim mono fs-11">{a.file}</div>
                </div>
                <div style={{ textAlign: 'right' }}>
                  <Badge kind="success" dot>v{act?.v} active</Badge>
                  {hasDraft && <div style={{ marginTop: 4 }}><Badge kind="warning">draft pending</Badge></div>}
                </div>
              </div>
            </button>
          );
        })}
      </div>

      {/* Section subnav */}
      <div className="tabs" style={{ flexShrink: 0, marginBottom: 12 }}>
        {SECTIONS.map(s => (
          <div key={s.id} className={`tab ${section === s.id ? 'active' : ''}`} onClick={() => setSection(s.id)}>
            <Icon name={s.icon} size={12} /> {s.label}
            {s.badge != null && <span className="count">{s.badge}</span>}
          </div>
        ))}
      </div>

      {/* Body */}
      <div style={{ flex: 1, minHeight: 0, overflow: section === 'editor' ? 'hidden' : 'auto', display: 'flex', flexDirection: 'column' }}>
        {section === 'versions' && <PromptVersions agent={agent} versions={agentVersions} onActivate={activateVersion} onArchive={archiveVersion} onRestoreAsNew={(content, note) => { addDraft(content, note); }} />}
        {section === 'editor'   && <PromptEditor agent={agent} active={active} onSaveDraft={addDraft} onGoVersions={() => setSection('versions')} />}
        {section === 'generate' && <PromptGenerate agent={agent} active={active} onSaveDraft={(c, n) => { addDraft(c, n); setSection('versions'); }} />}
        {section === 'feedback' && <PromptFeedback agent={agent} versions={agentVersions} />}
        {section === 'skills'   && <PromptSkills agent={agent} active={active} />}
        {section === 'ops'      && <PromptOps versions={versions} />}
      </div>
      {toastUi}
    </div>
  );
}

function usePromptToasts() {
  const [items, setItems] = React.useState([]);
  const push = React.useCallback((t) => {
    const id = Math.random().toString(36).slice(2);
    setItems(p => [...p, { ...t, id }]);
    setTimeout(() => setItems(p => p.filter(x => x.id !== id)), 3200);
  }, []);
  const ui = <div className="toast-stack">{items.map(t => <div key={t.id} className={`toast ${t.kind || ''}`}>{t.icon}{t.message}</div>)}</div>;
  return [ui, push];
}

// ─── A. VERSIONS ────────────────────────────────────────────────────────────
function PromptVersions({ agent, versions, onActivate, onArchive, onRestoreAsNew }) {
  const [selected, setSelected] = React.useState(versions.find(v => v.status === 'active')?.id || versions[0].id);
  const [compareMode, setCompareMode] = React.useState(false);
  const [cmpA, setCmpA] = React.useState(null);
  const [cmpB, setCmpB] = React.useState(null);

  const sel = versions.find(v => v.id === selected) || versions[0];

  // Default compare: selected vs the version right after it (previous)
  React.useEffect(() => {
    if (compareMode && (!cmpA || !cmpB)) {
      const idx = versions.findIndex(v => v.id === selected);
      setCmpA(versions[idx + 1]?.id || versions[idx]?.id);
      setCmpB(versions[idx]?.id);
    }
  }, [compareMode]);

  const statusBadge = (v) => v.status === 'active'
    ? <Badge kind="success" dot>active</Badge>
    : v.status === 'draft' ? <Badge kind="warning" dot>draft</Badge>
    : <Badge kind="neutral">archived</Badge>;

  const verA = versions.find(v => v.id === cmpA);
  const verB = versions.find(v => v.id === cmpB);

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '300px 1fr', gap: 12, flex: 1, minHeight: 0 }}>
      {/* Version timeline */}
      <div className="card" style={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>
        <div className="card-head">
          <h3>Version history</h3>
          <div className="actions">
            <button className={`btn xs ${compareMode ? 'primary' : 'ghost'}`} onClick={() => setCompareMode(c => !c)}>
              <Icon name="layers" size={11} /> Compare
            </button>
          </div>
        </div>
        <div style={{ flex: 1, overflowY: 'auto', padding: 8 }}>
          {versions.map((v, i) => {
            const isSel = !compareMode && selected === v.id;
            const inCompare = compareMode && (cmpA === v.id || cmpB === v.id);
            return (
              <div key={v.id}
                onClick={() => {
                  if (compareMode) {
                    // toggle into A/B slots
                    if (cmpA === v.id) setCmpA(null);
                    else if (cmpB === v.id) setCmpB(null);
                    else if (!cmpB) setCmpB(v.id);
                    else setCmpA(v.id);
                  } else setSelected(v.id);
                }}
                style={{ padding: '10px 12px', borderRadius: 'var(--radius)', cursor: 'pointer', marginBottom: 4, position: 'relative',
                  background: isSel || inCompare ? 'var(--bg-active)' : 'transparent',
                  border: '1px solid', borderColor: inCompare ? 'var(--accent)' : 'transparent' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 600, fontSize: 13 }}>v{v.v}</span>
                  {statusBadge(v)}
                  {compareMode && (cmpA === v.id || cmpB === v.id) && (
                    <Badge kind="accent">{cmpA === v.id ? 'A' : 'B'}</Badge>
                  )}
                  <span style={{ marginLeft: 'auto', fontSize: 10.5, color: 'var(--text-tertiary)', fontFamily: 'var(--font-mono)' }}>{formatRel(v.created_at)}</span>
                </div>
                <div style={{ fontSize: 11.5, color: 'var(--text-secondary)', marginTop: 5, lineHeight: 1.4, textWrap: 'pretty' }}>{v.note}</div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 6, fontSize: 10.5, color: 'var(--text-tertiary)', fontFamily: 'var(--font-mono)' }}>
                  <span><Icon name="user" size={9} style={{ verticalAlign: 'middle' }} /> {v.author}</span>
                  {v.feedback.up + v.feedback.down > 0 && (
                    <span style={{ marginLeft: 'auto' }}>
                      <span className="text-success">▲{v.feedback.up}</span> <span className="text-danger">▼{v.feedback.down}</span>
                    </span>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {/* Detail / diff */}
      {!compareMode ? (
        <div className="card" style={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>
          <div className="card-head">
            <h3>{agent} · v{sel.v}</h3>
            {statusBadge(sel)}
            <span className="sub">{sel.author} · {fmtDate(sel.created_at)}</span>
            <div className="actions" style={{ display: 'flex', gap: 6 }}>
              {sel.status !== 'active' && <button className="btn sm primary" onClick={() => onActivate(sel.id)}><Icon name="check2" size={11} /> {sel.status === 'draft' ? 'Activate draft' : 'Rollback to this'}</button>}
              <button className="btn sm" onClick={() => onRestoreAsNew(sel.content, `Restore v${sel.v} as new version`)}><Icon name="copy" size={11} /> Restore as new</button>
              <CopyButton text={sel.content} />
              {sel.status === 'archived' && <button className="btn sm ghost"><Icon name="trash" size={11} /></button>}
            </div>
          </div>

          {/* Blast radius */}
          <div style={{ display: 'flex', gap: 0, borderBottom: '1px solid var(--border-subtle)' }}>
            <BlastCell icon="sessions" label="sessions ran" value={sel.impact.sessions.toLocaleString()} />
            <BlastCell icon="layers" label="projects" value={sel.impact.projects.toLocaleString()} />
            <BlastCell icon="package" label="stores" value={sel.impact.stores.toLocaleString()} />
            <BlastCell icon="zap" label="avg tokens" value={'~' + sel.cost.avg_tokens.toLocaleString()} />
            <BlastCell icon="cost" label="avg cost/session" value={'$' + (sel.cost.avg_cost_cents / 100).toFixed(2)} last />
          </div>

          {/* Commit note */}
          <div style={{ padding: '10px 14px', borderBottom: '1px solid var(--border-subtle)', background: 'var(--bg-base)', display: 'flex', gap: 8, alignItems: 'flex-start' }}>
            <Icon name="message" size={13} style={{ color: 'var(--text-tertiary)', marginTop: 2, flexShrink: 0 }} />
            <div>
              <div style={{ fontSize: 12, color: 'var(--text-primary)' }}>{sel.note}</div>
              <div className="dim mono fs-11" style={{ marginTop: 2 }}>{sel.id} · {sel.derived_from ? `derived from v${sel.derived_from}` : 'immutable'}</div>
            </div>
          </div>

          <div style={{ flex: 1, overflow: 'auto', padding: '14px 20px' }}>
            <MarkdownPreview text={sel.content} />
          </div>
        </div>
      ) : (
        <div className="card" style={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>
          <div className="card-head" style={{ gap: 8 }}>
            <h3>Diff</h3>
            <select className="select" style={{ width: 'auto' }} value={cmpA || ''} onChange={e => setCmpA(e.target.value)}>
              <option value="">— base (A) —</option>
              {versions.map(v => <option key={v.id} value={v.id}>v{v.v} ({v.status})</option>)}
            </select>
            <Icon name="arrowR" size={13} className="dim" />
            <select className="select" style={{ width: 'auto' }} value={cmpB || ''} onChange={e => setCmpB(e.target.value)}>
              <option value="">— compare (B) —</option>
              {versions.map(v => <option key={v.id} value={v.id}>v{v.v} ({v.status})</option>)}
            </select>
            {verA && verB && <DiffStat a={verA.content} b={verB.content} />}
          </div>
          <div style={{ flex: 1, overflow: 'auto' }}>
            {verA && verB ? <DiffView a={verA.content} b={verB.content} />
              : <div className="empty-state" style={{ padding: 60 }}>Pick two versions in the timeline (or the dropdowns) to diff. <br/>Click A then B.</div>}
          </div>
        </div>
      )}
    </div>
  );
}

function BlastCell({ icon, label, value, last }) {
  return (
    <div style={{ flex: 1, padding: '10px 14px', borderRight: last ? 0 : '1px solid var(--border-subtle)' }}>
      <div style={{ fontSize: 10, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '.05em', display: 'flex', alignItems: 'center', gap: 5 }}>
        <Icon name={icon} size={11} /> {label}
      </div>
      <div style={{ fontSize: 18, fontWeight: 600, fontFamily: 'var(--font-mono)', marginTop: 3, fontVariantNumeric: 'tabular-nums' }}>{value}</div>
    </div>
  );
}

function DiffStat({ a, b }) {
  const d = lineDiff(a, b);
  const add = d.filter(x => x.type === 'add').length;
  const del = d.filter(x => x.type === 'del').length;
  return (
    <div className="actions" style={{ display: 'flex', gap: 8, fontFamily: 'var(--font-mono)', fontSize: 12 }}>
      <span className="text-success">+{add}</span>
      <span className="text-danger">−{del}</span>
    </div>
  );
}

function DiffView({ a, b }) {
  const rows = lineDiff(a, b);
  const bg = { add: 'var(--success-muted)', del: 'var(--danger-muted)', eq: 'transparent' };
  const mark = { add: '+', del: '−', eq: ' ' };
  const col = { add: 'var(--success)', del: 'var(--danger)', eq: 'var(--text-secondary)' };
  return (
    <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11.5, lineHeight: 1.55 }}>
      {rows.map((r, i) => (
        <div key={i} style={{ display: 'grid', gridTemplateColumns: '38px 38px 18px 1fr', background: bg[r.type], borderLeft: `2px solid ${r.type === 'eq' ? 'transparent' : col[r.type]}` }}>
          <span style={{ textAlign: 'right', padding: '0 6px', color: 'var(--text-tertiary)', userSelect: 'none' }}>{r.la || ''}</span>
          <span style={{ textAlign: 'right', padding: '0 6px', color: 'var(--text-tertiary)', userSelect: 'none' }}>{r.lb || ''}</span>
          <span style={{ textAlign: 'center', color: col[r.type], userSelect: 'none' }}>{mark[r.type]}</span>
          <span style={{ color: r.type === 'eq' ? 'var(--text-secondary)' : col[r.type], whiteSpace: 'pre-wrap', paddingRight: 12 }}>{r.text || ' '}</span>
        </div>
      ))}
    </div>
  );
}

// ─── Editor (edits create an immutable draft) ───────────────────────────────
function PromptEditor({ agent, active, onSaveDraft, onGoVersions }) {
  const [view, setView] = React.useState('split');
  const [text, setText] = React.useState(active.content);
  const [showSave, setShowSave] = React.useState(false);
  const [note, setNote] = React.useState('');

  React.useEffect(() => { setText(active.content); }, [active.id]);

  const dirty = text !== active.content;
  const lines = text.split('\n').length;
  const tokens = Math.round(text.length / 4);
  const bytes = new TextEncoder().encode(text).length;

  return (
    <div className="card" style={{ flex: 1, display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}>
      <div className="card-head">
        <h3>Editing from v{active.v}</h3>
        <Badge kind="success" dot>active</Badge>
        <span className="sub">edits create a new immutable draft — active stays live</span>
        <div className="actions" style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <span style={{ fontSize: 11, color: 'var(--text-tertiary)', fontFamily: 'var(--font-mono)' }}>
            {lines} lines · ~{tokens.toLocaleString()} tok · {bytes.toLocaleString()} B
          </span>
          <div className="segmented">
            <button className={view === 'edit' ? 'active' : ''} onClick={() => setView('edit')}>Edit</button>
            <button className={view === 'split' ? 'active' : ''} onClick={() => setView('split')}>Split</button>
            <button className={view === 'preview' ? 'active' : ''} onClick={() => setView('preview')}>Preview</button>
          </div>
          <CopyButton text={text} />
          <button className="btn primary" disabled={!dirty} onClick={() => setShowSave(true)}>
            <Icon name="plus" size={12} /> Save as draft v{active.v + 1}
          </button>
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: view === 'split' ? '1fr 1fr' : '1fr', flex: 1, minHeight: 0 }}>
        {(view === 'edit' || view === 'split') && (
          <textarea value={text} onChange={e => setText(e.target.value)} spellCheck={false}
            style={{ border: 0, borderRight: view === 'split' ? '1px solid var(--border-subtle)' : 0, padding: 16, background: 'var(--bg-base)', color: 'var(--text-primary)', fontFamily: 'var(--font-mono)', fontSize: 12.5, lineHeight: 1.6, resize: 'none', outline: 'none' }} />
        )}
        {(view === 'preview' || view === 'split') && (
          <div style={{ overflow: 'auto', padding: '16px 24px', background: 'var(--bg-surface)' }}>
            {view === 'split' && dirty
              ? <DiffView a={active.content} b={text} />
              : <MarkdownPreview text={text} />}
          </div>
        )}
      </div>

      {showSave && (
        <div className="modal-backdrop" onClick={() => setShowSave(false)}>
          <div className="modal" style={{ maxWidth: 480 }} onClick={e => e.stopPropagation()}>
            <div className="modal-head"><h3>Save as draft v{active.v + 1}</h3><button className="btn icon-only ghost" onClick={() => setShowSave(false)}><Icon name="x" size={14} /></button></div>
            <div className="modal-body">
              <p className="dim2 fs-12" style={{ marginTop: 0 }}>Versions are immutable. This creates <Mono>v{active.v + 1}</Mono> as a <Badge kind="warning">draft</Badge> — it won't go live until you activate it.</p>
              <label className="fs-11 dim2" style={{ display: 'block', margin: '12px 0 5px', fontWeight: 500 }}>Change note <span className="text-danger">*</span> <span className="dim">· why are you changing this?</span></label>
              <textarea className="input" rows={3} value={note} onChange={e => setNote(e.target.value)} placeholder="e.g. Tighten token rule after FP loop spike on ProductGrid" style={{ resize: 'vertical', fontFamily: 'var(--font-sans)' }} autoFocus />
              <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 16 }}>
                <button className="btn ghost" onClick={() => setShowSave(false)}>Cancel</button>
                <button className="btn primary" disabled={!note.trim()} onClick={() => { onSaveDraft(text, note.trim(), active.v); setShowSave(false); setNote(''); onGoVersions(); }}>
                  <Icon name="check" size={12} /> Create draft
                </button>
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Markdown preview (kept from v1) ────────────────────────────────────────
function MarkdownPreview({ text }) {
  const lines = (text || '').split('\n');
  const out = [];
  let i = 0;
  while (i < lines.length) {
    const l = lines[i];
    if (l.startsWith('```')) {
      const buf = [];
      i++;
      while (i < lines.length && !lines[i].startsWith('```')) { buf.push(lines[i]); i++; }
      i++;
      out.push(<pre key={out.length} className="code-block" style={{ marginBottom: 10 }}>{buf.join('\n')}</pre>);
      continue;
    }
    const h = l.match(/^(#{1,4})\s+(.+)$/);
    if (h) {
      const lvl = h[1].length;
      const sizes = { 1: 22, 2: 17, 3: 14, 4: 13 };
      out.push(React.createElement(`h${lvl}`, { key: out.length, style: { fontSize: sizes[lvl], margin: lvl === 1 ? '4px 0 12px' : '14px 0 6px', fontWeight: 600, letterSpacing: '-.01em' } }, mdInline(h[2])));
      i++; continue;
    }
    if (l.match(/^\s*[-*]\s+/)) {
      const items = [];
      while (i < lines.length && lines[i].match(/^\s*[-*]\s+/)) { items.push(lines[i].replace(/^\s*[-*]\s+/, '')); i++; }
      out.push(<ul key={out.length} style={{ margin: '0 0 10px', paddingLeft: 20 }}>{items.map((it, j) => <li key={j} style={{ fontSize: 13, lineHeight: 1.6, color: 'var(--text-secondary)' }}>{mdInline(it)}</li>)}</ul>);
      continue;
    }
    if (l.match(/^\s*\d+\.\s+/)) {
      const items = [];
      while (i < lines.length && lines[i].match(/^\s*\d+\.\s+/)) { items.push(lines[i].replace(/^\s*\d+\.\s+/, '')); i++; }
      out.push(<ol key={out.length} style={{ margin: '0 0 10px', paddingLeft: 20 }}>{items.map((it, j) => <li key={j} style={{ fontSize: 13, lineHeight: 1.6, color: 'var(--text-secondary)' }}>{mdInline(it)}</li>)}</ol>);
      continue;
    }
    if (l.trim() === '') { i++; continue; }
    out.push(<p key={out.length} style={{ fontSize: 13, lineHeight: 1.6, color: 'var(--text-secondary)', margin: '0 0 8px' }}>{mdInline(l)}</p>);
    i++;
  }
  return <div>{out}</div>;
}

function mdInline(s) {
  const parts = []; let rest = s; let key = 0;
  while (rest.length) {
    const codeM = rest.match(/^`([^`]+)`/);
    const boldM = rest.match(/^\*\*([^*]+)\*\*/);
    const italM = rest.match(/^\*([^*]+)\*/);
    if (codeM) { parts.push(<code key={key++} style={{ background: 'var(--bg-elevated)', padding: '1px 5px', borderRadius: 3, fontFamily: 'var(--font-mono)', fontSize: 11.5, color: 'var(--accent)' }}>{codeM[1]}</code>); rest = rest.slice(codeM[0].length); }
    else if (boldM) { parts.push(<strong key={key++} style={{ color: 'var(--text-primary)', fontWeight: 600 }}>{boldM[1]}</strong>); rest = rest.slice(boldM[0].length); }
    else if (italM) { parts.push(<em key={key++}>{italM[1]}</em>); rest = rest.slice(italM[0].length); }
    else { const m = rest.match(/^[^`*]+/); const chunk = m ? m[0] : rest[0]; parts.push(chunk); rest = rest.slice(chunk.length); }
  }
  return parts;
}

Object.assign(window, { ScreenPrompts, MarkdownPreview, mdInline, DiffView });
