// kova/journey.jsx — CEO journey · Wave D
// HOME → APPROVALS inbox → APPROVALS detail
// Composes Wave B atoms/molecules + Wave C organisms.

const {
  Btn, Chip, Kbd, Icon, Card, PageHead, KPITile, Tabs, StatusBadge, RunBadge,
  VerificationStamp, ConfidenceMeter, ApprovalChain, NotificationRow,
  EmptyState, Avatar, Textarea,
  DecisionCard, RunObject, EvidencePanel, WorkflowTimeline, ExceptionCard,
  ApprovalSurface, ActivityStream,
  ModuleOverview, DetailObject, ListTable,
} = window.K;

const { useState, useMemo, useEffect } = React;


/* ============================================================
   KraftApprovalDesignStrip — read-only view of the launch-pack
   designs the designer attached. CEO can't refine or convert; this
   is for sign-off only. SVG inlined to avoid load-order coupling
   with kova/kraft.jsx (which is loaded later than journey.jsx).
   ============================================================ */
const KraftTileSvg = ({ hue }) => {
  const gid = `gj${Math.round(hue)}`;
  const c1 = `hsl(${hue}, 30%, 92%)`;
  const c2 = `hsl(${hue}, 32%, 78%)`;
  const c3 = `hsl(${hue}, 24%, 56%)`;
  return (
    <svg viewBox="0 0 200 200" preserveAspectRatio="xMidYMid slice" className="kr-tile-canvas" aria-hidden="true">
      <defs>
        <radialGradient id={gid} cx="50%" cy="42%" r="65%">
          <stop offset="0%" stopColor={c1} />
          <stop offset="100%" stopColor={c2} />
        </radialGradient>
      </defs>
      <rect width="200" height="200" fill={`url(#${gid})`} />
      <circle cx="100" cy="104" r="46" fill="none" stroke={c3} strokeOpacity="0.55" strokeWidth="2.5" />
      <circle cx="100" cy="104" r="34" fill="none" stroke={c3} strokeOpacity="0.35" strokeWidth="1" />
      <polygon points="100,72 122,98 100,136 78,98" fill="#FFFFFF" fillOpacity="0.92" />
      <polygon points="100,72 122,98 100,98 78,98" fill="#FFFFFF" fillOpacity="0.55" />
      <line x1="100" y1="72" x2="100" y2="136" stroke={c3} strokeOpacity="0.4" strokeWidth="0.5" />
      <line x1="78" y1="98"  x2="122" y2="98"  stroke={c3} strokeOpacity="0.4" strokeWidth="0.5" />
      {[78,122,100,100].map((cx, i) => {
        const cy = [98,98,72,136][i];
        return <circle key={i} cx={cx} cy={cy} r="3" fill={c3} fillOpacity="0.7" />;
      })}
    </svg>
  );
};

const KraftApprovalDesignStrip = ({ designs, designerName, sessionId, selectedId, onSelect }) => (
  <Card>
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
      <div className="t-eyebrow">
        Launch pack · {designs.length} starred design{designs.length === 1 ? '' : 's'}
      </div>
      <Chip variant="mute" dot>
        Session: <span className="t-mono" style={{ marginLeft: 4 }}>{sessionId}</span> · {designerName}
      </Chip>
    </div>
    <div className="kr-strip">
      {designs.map(d => (
        <button key={d.id}
                className={`kr-strip-tile${selectedId === d.id ? ' is-selected' : ''}`}
                onClick={() => onSelect?.(selectedId === d.id ? null : d.id)}
                aria-pressed={selectedId === d.id}>
          <KraftTileSvg hue={d.hue} />
          <span className="kr-tile-id t-mono">{d.id}</span>
          {d.starred && <span className="kr-tile-star" title="Starred">★</span>}
          {(d.parentDesignId || d.version > 1) && (
            <span className="kr-strip-version">
              v{d.version} of <span className="t-mono">{d.parentDesignId || '—'}</span>
            </span>
          )}
          <span className="kr-tile-tag">{d.tag}</span>
        </button>
      ))}
    </div>
    <p className="t-body-sm" style={{ color: 'var(--mute)', marginTop: 12, marginBottom: 0 }}>
      {selectedId
        ? <>Inspecting <span className="t-mono">{selectedId}</span> · click the same tile again to clear · or pick another to switch.</>
        : <>Approving signs all {designs.length} as the launch pack. Click a tile to inspect material, stones, lineage, and per-design comments.</>}
    </p>
  </Card>
);


/* ============================================================
   KraftDesignDetail — inline per-design inspection panel.
   Renders when a tile is selected on the KRAFT approval detail.
   Pulls from the design fixture fields added in data.jsx.
   ============================================================ */
const MFG_VARIANT = { green: 'success', amber: 'warn', red: 'danger' };
const MFG_LABEL   = { green: 'Manufacturable', amber: 'Needs review', red: 'Blocked' };

const KraftDesignDetail = ({ design, onRefineThis, onClose }) => {
  if (!design) return null;
  const m = design.material || {};
  const s = design.stones;
  const fg = design.mfg || { status: 'green', note: '' };
  return (
    <Card>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12, flexWrap: 'wrap' }}>
        <Chip variant="accent" dot>Inspecting</Chip>
        <span className="t-mono" style={{ color: 'var(--ink)', fontWeight: 600 }}>{design.id}</span>
        {(design.parentDesignId || design.version > 1) && (
          <Chip variant="mute">
            v{design.version} of <span className="t-mono" style={{ marginLeft: 4 }}>{design.parentDesignId || '—'}</span>
          </Chip>
        )}
        <Chip variant={MFG_VARIANT[fg.status] || 'mute'} dot>{MFG_LABEL[fg.status] || fg.status}</Chip>
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 6 }}>
          <Btn size="sm" onClick={onRefineThis}>✏ Refine this one</Btn>
          <Btn size="sm" variant="ghost" onClick={onClose}>Close</Btn>
        </div>
      </div>

      <div className="kr-detail-grid">
        <div>
          <div className="t-eyebrow" style={{ color: 'var(--mute)' }}>Material</div>
          <div className="kr-detail-val">{m.metal || '—'}</div>
          <div className="kr-detail-sub">{m.finish || '—'} · {m.weightG ? m.weightG + ' g' : '—'}</div>
        </div>
        <div>
          <div className="t-eyebrow" style={{ color: 'var(--mute)' }}>Stones</div>
          {s ? (
            <>
              <div className="kr-detail-val">{s.count} × {s.primary}</div>
              <div className="kr-detail-sub">{s.totalCarat} ct total · {s.setting}</div>
            </>
          ) : (
            <>
              <div className="kr-detail-val">None</div>
              <div className="kr-detail-sub">Metal-only piece</div>
            </>
          )}
        </div>
        <div>
          <div className="t-eyebrow" style={{ color: 'var(--mute)' }}>BOM share</div>
          <div className="kr-detail-val">{design.bomShare || '—'}</div>
          <div className="kr-detail-sub">Lead time {design.leadTimeDays || '—'} d</div>
        </div>
      </div>

      <div className="kr-detail-row">
        <div className="t-eyebrow" style={{ color: 'var(--mute)', marginBottom: 4 }}>Manufacturability</div>
        <div className="kr-detail-sub" style={{ color: 'var(--ink-2)' }}>{fg.note || '—'}</div>
      </div>
      <div className="kr-detail-row">
        <div className="t-eyebrow" style={{ color: 'var(--mute)', marginBottom: 4 }}>Brief lineage</div>
        <div className="kr-detail-sub" style={{ color: 'var(--ink-2)' }}>{design.promptSummary || '—'}</div>
      </div>
    </Card>
  );
};


/* ============================================================
   CommentThread — CEO ↔ designer notes on a launch pack.
   K1.5 demo uses component-local state (resets on page nav).
   Backend wires in K6 via POST /api/kraft/messages/:id/comments.
   ============================================================ */
const CommentThread = ({ initial = [], onAdd, ceoInitials = 'RP',
                         selectedDesignId, onClearScope }) => {
  const [comments, setComments] = useState(initial);
  const [draft, setDraft] = useState('');

  // Filter rule: when a tile is selected, show comments scoped to that
  // designId PLUS general (designId == null) comments — so the CEO always
  // sees the launch-pack-level discussion even while inspecting one tile.
  const visible = useMemo(() => {
    if (!selectedDesignId) return comments;
    return comments.filter(c => !c.designId || c.designId === selectedDesignId);
  }, [comments, selectedDesignId]);

  const submit = () => {
    const text = draft.trim();
    if (!text) return;
    const c = { id: 'c-' + Math.random().toString(36).slice(2, 7),
                who: 'You · CEO', at: 'now', text,
                designId: selectedDesignId || null };
    setComments([...comments, c]);
    setDraft('');
    onAdd?.(c);
  };

  const onKey = (e) => {
    if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
      e.preventDefault();
      submit();
    }
  };

  return (
    <Card>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
        <div className="t-eyebrow">
          Comments · {visible.length}{selectedDesignId && comments.length !== visible.length
            ? <> <span style={{ color: 'var(--mute)' }}>of {comments.length}</span></>
            : null}
        </div>
        {selectedDesignId
          ? <Chip variant="accent" dot onClick={onClearScope}>
              Scoped to <span className="t-mono" style={{ marginLeft: 4 }}>{selectedDesignId}</span> · clear
            </Chip>
          : <Chip variant="mute">All · whole launch pack</Chip>}
      </div>
      <div className="k-comments-list">
        {visible.length === 0 && (
          <div className="t-body-sm" style={{ color: 'var(--mute)' }}>
            {selectedDesignId
              ? 'No comments on this design yet. Your note will be tagged @' + selectedDesignId + '.'
              : 'No comments yet. Add a note for the designer below.'}
          </div>
        )}
        {visible.map(c => {
          const isCeo = c.who.includes('CEO') || c.who.includes('You');
          const initials = isCeo ? ceoInitials : c.who.slice(0, 1).toUpperCase();
          return (
            <div className={`k-comment${isCeo ? ' is-ceo' : ''}`} key={c.id}>
              <Avatar initials={initials} size={24} />
              <div className="k-comment-body">
                <div className="k-comment-meta">
                  <strong>{c.who}</strong>
                  <span> · </span>
                  <span style={{ color: 'var(--mute)' }}>{c.at}</span>
                  {c.designId && (
                    <Chip variant="mute" style={{ marginLeft: 6, fontSize: 10, padding: '0 6px' }}>
                      @<span className="t-mono">{c.designId}</span>
                    </Chip>
                  )}
                </div>
                <div className="k-comment-text">{c.text}</div>
              </div>
            </div>
          );
        })}
      </div>
      <div className="k-comments-composer">
        <textarea
          className="kr-composer-input"
          rows={3}
          value={draft}
          onChange={(e) => setDraft(e.target.value)}
          onKeyDown={onKey}
          placeholder={selectedDesignId
            ? 'Note about ' + selectedDesignId + ' — e.g. "Tighten the medallion 2mm before sign-off."'
            : "Note to designer — e.g. 'Take the peacock direction forward, drop the bar-set trio.'"
          }
        />
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 8 }}>
          <span className="t-meta" style={{ color: 'var(--mute)' }}>
            <Kbd>⌘⏎</Kbd> to send · {selectedDesignId
              ? <>tagged <span className="t-mono">@{selectedDesignId}</span></>
              : 'visible to the designer in their session thread'}
          </span>
          <Btn variant="primary" size="sm" onClick={submit} disabled={!draft.trim()}>Send to designer</Btn>
        </div>
      </div>
    </Card>
  );
};

const MOD_LABEL = {
  orbit: 'ORBIT', vault: 'VAULT', price: 'PRICE', kraft: 'KRAFT',
  approvals: 'APPROVALS', monitor: 'MONITOR',
};


/* ============================================================
   ApprovalRow — compact decision row used in the inbox
   ============================================================ */
const ApprovalRow = ({ decision, onOpen, onApprove, onReject }) => (
  <div className="k-approval-row" style={{ '--m-mod': `var(--m-${decision.mod})` }} onClick={() => onOpen?.(decision.id)}>
    <div className="k-approval-stripe" />
    <div className="k-approval-body">
      <div className="k-approval-head">
        <Chip variant="mute" dot>{MOD_LABEL[decision.mod] || decision.mod.toUpperCase()}</Chip>
        <StatusBadge kind={
          decision.status === 'approved'  ? 'verified' :
          decision.status === 'rejected'  ? 'failed' :
          decision.status === 'executing' ? 'pending' : 'pending'
        }>{decision.statusLabel}</StatusBadge>
        <RunBadge id={decision.runId} version={decision.runVersion} when={decision.runWhen} />
        {decision.cosign && <span className="t-meta" style={{ marginLeft: 'auto' }}>co-sign · {decision.cosign}</span>}
      </div>
      <div className="k-approval-title">{decision.title}</div>
      <div className="k-approval-stats">
        {decision.stats.slice(0, 4).map((s, i) => (
          <div className="k-approval-stat" key={i}>
            <span className="l">{s.label}</span>
            <span className={`v${s.color === 'success' ? ' is-success' : s.color === 'danger' ? ' is-danger' : ''}`}>{s.value}</span>
          </div>
        ))}
      </div>
    </div>
    {decision.status === 'pending' && (onApprove || onReject) && (
      <div className="k-approval-actions" onClick={(e) => e.stopPropagation()}>
        <Btn size="sm" variant="primary" onClick={() => onApprove?.(decision.id)} kbd="⌘⏎">Approve</Btn>
        <Btn size="sm" variant="reject" onClick={() => onReject?.(decision.id)}>Reject</Btn>
      </div>
    )}
  </div>
);


/* ============================================================
   HOME PAGE — decision-first · composed via ModuleOverview template
   ============================================================ */
const HomePage = ({
  user = 'Rohan', decisions, activity,
  onOpenDecision, onApprove, onReject, onRevise, onOpenDrawer, onOpenCmdK, onAskKova,
}) => {
  const pending = decisions.filter(d => d.status === 'pending' || d.status === 'executing');
  const primary = pending[0];
  const moneyMoves = pending.filter(d => d.impact === 'money').length;

  const pageHead = (
    <PageHead
      crumb={['HOME', 'today', '09:42 IST']}
      title={`Good morning, ${user}.`}
      subtitle={pending.length === 0
        ? 'Inbox zero. Nothing waits on you right now.'
        : `${pending.length} decisions wait on you. ${moneyMoves > 0 ? `${moneyMoves} move money.` : ''}`}
      actions={
        <>
          <Btn size="sm" onClick={onAskKova}>Ask KOVA</Btn>
          <Btn size="sm" onClick={() => location.hash = 'approvals'}>Review approvals</Btn>
          <Btn size="sm" onClick={() => location.hash = 'monitor'}>View runs</Btn>
          {primary && (
            <Btn size="sm" variant="primary"
                 onClick={() => onOpenDecision?.(primary.id)}
                 kbd="⌘⏎">Open next decision</Btn>
          )}
        </>
      }
    />
  );

  const kpis = [
    <KPITile key="a" mod="home"      label="Approvals" value={String(pending.length)} foot="awaiting you" trend={pending.length > 2 ? { dir: 'up', label: '+2' } : undefined} />,
    <KPITile key="b" mod="vault"     label="Unlock identified" value="₹14.2 L" foot="38 SKUs · VAULT" />,
    <KPITile key="c" mod="price"     label="Margin Δ · 7 d" value="+ 6.4 %" valueColor="var(--success)" foot="vs. previous 7 days" />,
    <KPITile key="d" mod="orbit"     label="Briefs · 24 h"  value="7" foot="all verified" />,
  ];

  const empty = (
    <Card>
      <EmptyState
        mark="K"
        title="Inbox zero."
        body="Orbit will run again in ~6 h. You're done here."
        cta={<Btn size="sm" onClick={() => location.hash = 'library'}>Open design library</Btn>}
      />
    </Card>
  );

  const primaryNode = primary && (
    <DecisionCard
      {...primary}
      onEvidence={() => onOpenDrawer?.(primary.id)}
      onRunHistory={() => onOpenDecision?.(primary.id)}
      onReject={() => onReject?.(primary.id)}
      onRevise={() => onRevise?.(primary.id)}
      onApprove={() => onApprove?.(primary.id)}
    />
  );

  const secondary = pending.length > 1 && (
    <Card>
      <div className="t-eyebrow" style={{ marginBottom: 12 }}>Up next · {pending.length - 1} more</div>
      {pending.slice(1).map(d => (
        <ApprovalRow key={d.id} decision={d}
          onOpen={onOpenDecision}
          onApprove={onApprove}
          onReject={onReject} />
      ))}
    </Card>
  );

  const activityNode = (
    <ActivityStream
      title="Today’s activity"
      onSeeAll={() => location.hash = 'monitor'}
      items={activity}
    />
  );

  const side = [
    <Card key="glance">
      <div className="t-eyebrow" style={{ marginBottom: 10 }}>Today · at a glance</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {[
          ['Workflows run',     '7',       'var(--ink)'],
          ['Verified outputs',  '7 / 7',   'var(--success)'],
          ['Tool calls',        '184',     'var(--ink)'],
          ['Cost · 24 h',       '$3.18',   'var(--ink)'],
          ['Connector health',  '4 / 4 green', 'var(--success)'],
        ].map(([l, v, c]) => (
          <div key={l} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
            <span className="t-meta">{l}</span>
            <span className="t-mono" style={{ color: c }}>{v}</span>
          </div>
        ))}
      </div>
    </Card>,
    <Card key="quick">
      <div className="t-eyebrow" style={{ marginBottom: 10 }}>Quick</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <Btn size="sm" variant="ghost" onClick={() => location.hash = 'approvals'}>Open approvals inbox →</Btn>
        <Btn size="sm" variant="ghost" onClick={onOpenCmdK} kbd="⌘K">Jump to…</Btn>
        <Btn size="sm" variant="ghost" onClick={onAskKova}>Ask KOVA a question</Btn>
      </div>
    </Card>,
  ];

  return (
    <ModuleOverview
      pageHead={pageHead}
      kpis={kpis}
      primary={primaryNode}
      secondary={secondary}
      activity={activityNode}
      side={side}
      empty={pending.length === 0 ? empty : null}
    />
  );
};


/* ============================================================
   APPROVALS INBOX — composed via ListTable template
   ============================================================ */
const ApprovalsInbox = ({ decisions, onOpenDecision, onApprove, onReject, onOpenCmdK }) => {
  const [tab, setTab] = useState('pending');
  const [modFilter, setModFilter] = useState('all');

  const filtered = useMemo(() => {
    let xs = decisions;
    if (tab === 'pending')  xs = xs.filter(d => d.status === 'pending' || d.status === 'executing');
    if (tab === 'approved') xs = xs.filter(d => d.status === 'approved');
    if (tab === 'rejected') xs = xs.filter(d => d.status === 'rejected');
    if (modFilter !== 'all') xs = xs.filter(d => d.mod === modFilter);
    return xs;
  }, [decisions, tab, modFilter]);

  const counts = {
    pending:  decisions.filter(d => d.status === 'pending' || d.status === 'executing').length,
    approved: decisions.filter(d => d.status === 'approved').length,
    rejected: decisions.filter(d => d.status === 'rejected').length,
    all:      decisions.length,
  };

  const modules = [...new Set(decisions.map(d => d.mod))];

  return (
    <ListTable
      pageHead={
        <PageHead
          crumb={['APPROVALS', 'inbox']}
          title="Approvals · the trust inbox"
          subtitle="Every external write passes through here. Each item carries its evidence, its chain, and its impact."
          actions={
            <>
              <Btn size="sm" onClick={onOpenCmdK} kbd="⌘K">Jump to…</Btn>
              <Btn size="sm" variant="primary"
                   onClick={() => filtered[0] && onOpenDecision?.(filtered[0].id)}
                   kbd="⌘⏎"
                   disabled={!filtered[0]}>Open next</Btn>
            </>
          }
        />
      }
      tabs={
        <Tabs value={tab} onChange={setTab} mod="approvals" items={[
          { id: 'pending',  label: 'Pending',  count: counts.pending },
          { id: 'approved', label: 'Approved', count: counts.approved },
          { id: 'rejected', label: 'Rejected', count: counts.rejected },
          { id: 'all',      label: 'All',      count: counts.all },
        ]} />
      }
      filterBar={
        <div className="k-inbox-filter">
          <span className="k-inbox-filter-label">Module</span>
          <div className="k-inbox-filter-chips">
            <Chip variant={modFilter === 'all' ? 'solid' : 'mute'} onClick={() => setModFilter('all')}>All</Chip>
            {modules.map(m => (
              <Chip key={m}
                    variant={modFilter === m ? 'solid' : 'mute'}
                    onClick={() => setModFilter(m)}>{MOD_LABEL[m] || m.toUpperCase()}</Chip>
            ))}
          </div>
        </div>
      }
      empty={filtered.length === 0 ? (
        <Card>
          <EmptyState
            mark="✓"
            title={tab === 'pending' ? 'Inbox zero.' : `No ${tab} items.`}
            body={tab === 'pending' ? 'Nothing waits on you. Orbit will scan again in ~6 h.' : 'Switch tabs above.'}
          />
        </Card>
      ) : null}
      body={filtered.map(d => (
        <ApprovalRow key={d.id} decision={d}
                     onOpen={onOpenDecision}
                     onApprove={onApprove}
                     onReject={onReject} />
      ))}
    />
  );
};


/* ============================================================
   APPROVALS DETAIL · /approvals/:id · composed via DetailObject template
   ============================================================ */
const ApprovalsDetail = ({ decision, onBack, onApprove, onReject, onRevise,
                           onOpenEvidence, onOpenTrace, isExecuting }) => {
  // Per-design selection for KRAFT approvals — drives the inline detail
  // panel, the comment-thread filter, and per-tile refine scoping.
  const [selectedDesignId, setSelectedDesignId] = useState(null);
  // Reset selection when navigating between decisions.
  useEffect(() => { setSelectedDesignId(null); }, [decision?.id]);
  const selectedDesign = useMemo(
    () => decision?.designs?.find(d => d.id === selectedDesignId) || null,
    [decision, selectedDesignId]
  );
  if (!decision) {
    return (
      <DetailObject
        back={<button className="k-detail-back" onClick={onBack}>← Back to approvals</button>}
        pageHead={<PageHead crumb={['APPROVALS']} title="Decision not found" />}
        main={[
          <Card key="empty">
            <EmptyState
              mark="?"
              title="That decision doesn’t exist."
              body="It may have been signed, returned, or expired."
              cta={<Btn size="sm" onClick={onBack}>Back to inbox</Btn>}
            />
          </Card>
        ]}
        side={[]}
      />
    );
  }

  const isPending = decision.status === 'pending' || decision.status === 'executing';
  const isKraft   = decision.mod === 'kraft';

  return (
    <DetailObject
      back={<button className="k-detail-back" onClick={onBack}>← Back to approvals</button>}
      pageHead={
        <PageHead
          crumb={['APPROVALS', decision.runId]}
          title={decision.title}
          subtitle={decision.reasoning}
          actions={
            isPending ? (
              <>
                <Btn size="sm" variant="reject" onClick={() => onReject?.(decision.id)}>Reject</Btn>
                <Btn size="sm" onClick={() => onRevise?.(decision.id, isKraft && selectedDesignId ? { designId: selectedDesignId } : undefined)}>Revise</Btn>
                <Btn size="sm" variant="primary" onClick={() => onApprove?.(decision.id)} kbd="⌘⏎">Approve &amp; sign</Btn>
              </>
            ) : (
              <Chip variant={decision.status === 'approved' ? 'success' : 'danger'} dot>
                {decision.statusLabel}
              </Chip>
            )
          }
        />
      }
      // Status row: full set for non-KRAFT (Vault/Price/Orbit unchanged);
      // KRAFT collapses to one badge + run id + confidence per §11.4
      // ("CEOs see useful product states, not heartbeats").
      statusRow={isKraft ? (
        <>
          <StatusBadge kind={
            decision.status === 'approved'  ? 'verified' :
            decision.status === 'rejected'  ? 'failed' :
            decision.status === 'executing' ? 'pending' : 'pending'
          }>{decision.statusLabel}</StatusBadge>
          <RunBadge id={decision.runId} when={decision.runWhen} />
          {decision.confidence && <ConfidenceMeter level={decision.confidence} label={decision.confidenceLabel} mod="kraft" />}
        </>
      ) : (
        <>
          <VerificationStamp>{decision.stamp || 'Verified'}</VerificationStamp>
          <StatusBadge kind={
            decision.status === 'approved'  ? 'verified' :
            decision.status === 'rejected'  ? 'failed' :
            decision.status === 'executing' ? 'pending' : 'pending'
          }>{decision.statusLabel}</StatusBadge>
          <RunBadge id={decision.runId} version={decision.runVersion} when={decision.runWhen} />
          {decision.confidence && <ConfidenceMeter level={decision.confidence} label={decision.confidenceLabel} mod={decision.mod} />}
          {isExecuting && <Chip variant="info" dot>Executing</Chip>}
        </>
      )}
      // KRAFT main column: designs + slim 3-stat summary + two escape buttons.
      // Telemetry (RunObject, WorkflowTimeline) moves behind the MONITOR link.
      // Evidence (claims/receipts/math) moves behind the Evidence drawer.
      main={isKraft ? [
        decision.designs?.length > 0 && (
          <KraftApprovalDesignStrip key="strip"
            designs={decision.designs}
            designerName={decision.designerName || 'Designer'}
            sessionId={decision.sessionId || '—'}
            selectedId={selectedDesignId}
            onSelect={setSelectedDesignId}
          />
        ),
        selectedDesign && (
          <KraftDesignDetail key="detail"
            design={selectedDesign}
            onRefineThis={() => onRevise?.(decision.id, { designId: selectedDesign.id })}
            onClose={() => setSelectedDesignId(null)}
          />
        ),
        <Card key="stats">
          <div className="t-eyebrow" style={{ marginBottom: 12 }}>The numbers that decide it</div>
          <div className="kr-decide-stats">
            {decision.stats
              .filter(s => !/brief\s*ref/i.test(s.label))   // drop foreign-key noise
              .slice(0, 3)
              .map((s, i) => (
                <div key={i} className="kr-decide-stat">
                  <span className="t-eyebrow" style={{ color: 'var(--mute)' }}>{s.label}</span>
                  <span className={`kr-decide-stat-val${
                    s.color === 'success' ? ' is-success' :
                    s.color === 'danger'  ? ' is-danger'  : ''}`}>
                    {s.value}
                  </span>
                </div>
              ))}
          </div>
          <div className="kr-decide-actions">
            <Btn size="sm" onClick={onOpenEvidence}>Evidence ›</Btn>
            <Btn size="sm" variant="ghost" onClick={onOpenTrace}>Open trace in MONITOR ›</Btn>
          </div>
        </Card>,
      ] : [
        <Card key="stats">
          <div className="t-eyebrow" style={{ marginBottom: 12 }}>Decision summary</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 16 }}>
            {decision.stats.map((s, i) => (
              <div key={i} style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
                <span className="t-eyebrow" style={{ color: 'var(--mute)' }}>{s.label}</span>
                <span style={{ fontSize: 22, fontWeight: 600, color:
                  s.color === 'success' ? 'var(--success)' :
                  s.color === 'danger'  ? 'var(--danger)' :
                  'var(--ink)',
                  fontVariantNumeric: 'tabular-nums', letterSpacing: '-0.01em' }}>{s.value}</span>
              </div>
            ))}
          </div>
        </Card>,
        <RunObject key="run"
          mod={decision.mod}
          runId={decision.runId}
          status={decision.status === 'pending' ? 'pending' : decision.status === 'rejected' ? 'failed' : 'verified'}
          title={`${decision.mod}.daily · ${decision.runVersion} · ${decision.runWhen}`}
          agent={`${decision.mod}_agent · v2.1`}
          skillVersion={`acme.${decision.mod}.skills @ 2026.05.18-3`}
          memoryVersion="acme.memory @ 2026.05.20"
          startedAt={decision.runWhen}
          cost="$0.018"
          latency="8.4 s"
          onOpenTrace={() => location.hash = `monitor/${decision.runId}`}
        />,
        <WorkflowTimeline key="wf"
          title="Run · workflow timeline"
          actions={<Btn size="sm" variant="ghost" onClick={() => location.hash = `monitor/${decision.runId}`}>Open in MONITOR ›</Btn>}
          steps={decision.workflow}
        />,
      ]}
      // KRAFT side: comments + approval chain only. Evidence + impact-preview
      // are reachable via the buttons above; nothing is lost, page is calmer.
      side={isKraft ? [
        <CommentThread key="comments"
          initial={decision.comments || []}
          selectedDesignId={selectedDesignId}
          onClearScope={() => setSelectedDesignId(null)}
        />,
        <ApprovalSurface key="as"
          mod="kraft"
          runId={decision.runId}
          title="Approval chain"
          chain={decision.chain}
          onReject={isPending ? () => onReject?.(decision.id) : undefined}
          onRevise={isPending ? () => onRevise?.(decision.id, selectedDesignId ? { designId: selectedDesignId } : undefined) : undefined}
          onApprove={isPending ? () => onApprove?.(decision.id) : undefined}
        />,
      ] : [
        <EvidencePanel key="ev"
          runId={decision.runId}
          claims={decision.claims || []}
          receipts={decision.receipts || []}
          math={decision.math || []}
        />,
        <ApprovalSurface key="as"
          mod={decision.mod}
          runId={decision.runId}
          title="Approval chain"
          chain={decision.chain}
          onReject={isPending ? () => onReject?.(decision.id) : undefined}
          onRevise={isPending ? () => onRevise?.(decision.id) : undefined}
          onApprove={isPending ? () => onApprove?.(decision.id) : undefined}
        />,
        <div className="k-impact" key="impact">
          <div className="t-eyebrow" style={{ marginBottom: 10 }}>Impact preview</div>
          {decision.stats.slice(0, 4).map((s, i) => (
            <div className="k-impact-row" key={i}>
              <span className="l">{s.label}</span>
              <span className={`v${s.color === 'success' ? ' is-success' : s.color === 'danger' ? ' is-danger' : ''}`}
                    style={{ color: s.color === 'success' ? 'var(--success)' : s.color === 'danger' ? 'var(--danger)' : undefined }}>{s.value}</span>
            </div>
          ))}
          <div className="k-impact-row">
            <span className="l">External writes</span>
            <span className="v">{isPending ? 'on approval' : decision.status === 'approved' ? 'queued' : 'none'}</span>
          </div>
        </div>,
      ]}
      footer={isPending && (
        <div className="k-detail-footer">
          <div className="k-detail-footer-left">
            <Icon name="check" />
            <span>Signing executes the connector pipeline. This action is audited.</span>
          </div>
          <div className="k-detail-footer-right">
            <Btn variant="reject" onClick={() => onReject?.(decision.id)} kbd="⌘⇧⏎">Reject</Btn>
            <Btn onClick={() => onRevise?.(decision.id, isKraft && selectedDesignId ? { designId: selectedDesignId } : undefined)}>Revise</Btn>
            <Btn variant="primary" onClick={() => onApprove?.(decision.id)} kbd="⌘⏎">Approve &amp; sign</Btn>
          </div>
        </div>
      )}
    />
  );
};


/* ============================================================
   ASK KOVA — query surface (architecture §8.1 HOME button "Ask KOVA")
   Returns verified output cards, never raw model text.
   ============================================================ */
const ASK_FIXTURES = [
  { match: /margin|profit/i, mod: 'price', card: {
      stamp: 'Verified · Price engine',
      title: 'Weighted margin was + 6.4 % over the last 7 days, vs + 4.1 % the prior week.',
      reasoning: 'PRICE engine ran on closed-loop sales data with deterministic margin calculation. No agent inference.',
      stats: [
        { label: 'Margin · 7d',  value: '+ 6.4 %', color: 'success' },
        { label: 'vs. prev',     value: '+ 2.3 pp', color: 'success' },
        { label: 'SKUs in scope',value: '412' },
        { label: 'Confidence',   value: 'verified' },
      ],
      claims: [
        { text: 'Sales reconciled against POS for 412 SKUs in 7 days.', source: 'sales.read',     receipt: 'ask-rcp-71 / 1' },
        { text: 'Cost basis pulled from PRICE engine deterministic.',   source: 'price.read',     receipt: 'ask-rcp-71 / 2' },
        { text: 'Margin policy floor of 32 % respected throughout.',    source: 'wiki.lookup',    receipt: 'ask-rcp-71 / 3' },
      ],
  }},
  { match: /deadstock|aged|vault/i, mod: 'vault', card: {
      stamp: 'Verified · Vault deadstock scan',
      title: '38 SKUs are aged over 180 days · ₹14.2 L unlock identified.',
      reasoning: 'Last scan ran 11 min ago. 4 cohorts across Mumbai, Bengaluru, Pune. One pending CEO approval at rcp-44c9.',
      stats: [
        { label: 'Aged SKUs',  value: '38' },
        { label: 'Unlock',     value: '₹14.2 L' },
        { label: 'Cohorts',    value: '4' },
        { label: 'Confidence', value: 'high' },
      ],
      claims: [
        { text: 'Inventory snapshot taken 09:11 IST · 412 SKUs scanned.', source: 'inventory.read', receipt: 'ask-rcp-72 / 1' },
        { text: 'Age threshold of 180 d applied per VAULT policy.',       source: 'wiki.lookup',    receipt: 'ask-rcp-72 / 2' },
      ],
  }},
  { match: /quote|customer/i, mod: 'price', card: {
      stamp: 'Verified · Price quotes',
      title: '12 open quotes · ₹84 L in flight · 3 awaiting price approval.',
      reasoning: 'Quotes filtered to non-closed status from the last 14 days. CEO-ceiling breaches flagged separately.',
      stats: [
        { label: 'Open quotes', value: '12' },
        { label: 'In flight',   value: '₹84 L' },
        { label: 'Awaiting',    value: '3' },
        { label: 'Confidence',  value: 'verified' },
      ],
      claims: [
        { text: 'Quote table joined with status feed at 09:42 IST.', source: 'sales.read',    receipt: 'ask-rcp-73 / 1' },
        { text: 'Price ceiling policy checked on all 12 quotes.',    source: 'price.read',    receipt: 'ask-rcp-73 / 2' },
      ],
  }},
];

const askDecision = (q) => {
  const hit = ASK_FIXTURES.find(f => f.match.test(q));
  if (hit) return { ok: true, ...hit.card, mod: hit.mod, runId: `ask-rcp-${Math.floor(Math.random() * 100)}` };
  return null;  // → render failed state
};

const AskKovaPage = ({ onClose, onOpenEvidence }) => {
  const [q, setQ] = useState('');
  const [history, setHistory] = useState([]);
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    const t = setTimeout(() => inputRef.current?.focus(), 80);
    return () => clearTimeout(t);
  }, []);

  const submit = (e) => {
    e?.preventDefault();
    const query = q.trim();
    if (!query) return;
    const id = Math.random().toString(36).slice(2, 7);
    setHistory(prev => [{ id, q: query, status: 'thinking' }, ...prev]);
    setQ('');
    setTimeout(() => {
      const answer = askDecision(query);
      setHistory(prev => prev.map(h => h.id === id
        ? { ...h, status: answer ? 'verified' : 'failed', answer }
        : h));
    }, 1400);
  };

  return (
    <div className="k-page-enter">
      <PageHead
        crumb={['HOME', 'Ask KOVA']}
        title="Ask KOVA"
        subtitle="Ask a structured question. KOVA answers with a verified output card · never raw model text. Sources are always linked."
        actions={
          <Btn size="sm" variant="ghost" onClick={onClose}>← Back to home</Btn>
        }
      />

      <Card style={{ marginBottom: 20 }}>
        <form onSubmit={submit} style={{ display: 'flex', gap: 8 }}>
          <div className="k-input" style={{ flex: 1, height: 44 }}>
            <Icon name="search" size={16} />
            <input ref={inputRef} value={q} onChange={(e) => setQ(e.target.value)}
                   placeholder="e.g. What was margin last week · How many SKUs are aged · Show me open quotes"
                   style={{ fontSize: 15 }} />
          </div>
          <Btn variant="primary" type="submit" disabled={!q.trim()}>Ask</Btn>
        </form>
        <div className="t-meta" style={{ marginTop: 10, color: 'var(--mute)' }}>
          <span style={{ marginRight: 12 }}>Try:</span>
          {['What was margin last week', 'How much deadstock do we have', 'Show me open quotes'].map(s => (
            <button key={s} type="button"
                    onClick={() => { setQ(s); setTimeout(() => inputRef.current?.focus(), 0); }}
                    style={{ background: 'transparent', border: 0, color: 'var(--accent)',
                             fontSize: 12, cursor: 'pointer', marginRight: 12, padding: 0 }}>
              {s} ›
            </button>
          ))}
        </div>
      </Card>

      {history.length === 0 ? (
        <Card>
          <EmptyState
            mark="?"
            title="Ask anything KOVA has verified."
            body="Every answer is a structured card with claims, receipts, and a confidence indicator. There is no raw chat."
          />
        </Card>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
          {history.map(h => (
            <div key={h.id}>
              <div className="t-eyebrow" style={{ marginBottom: 8 }}>Your question</div>
              <div className="t-h2" style={{ margin: '0 0 12px' }}>{h.q}</div>

              {h.status === 'thinking' && (
                <Card>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                    <span className="k-spin" />
                    <span className="t-body-sm" style={{ color: 'var(--mute)' }}>
                      Routing to verified sources · running deterministic checks…
                    </span>
                  </div>
                </Card>
              )}

              {h.status === 'verified' && (
                <DecisionCard
                  {...h.answer}
                  status="verified"
                  statusLabel="Verified"
                  runWhen="just now"
                  confidence={4}
                  confidenceLabel="Verified"
                  onEvidence={() => onOpenEvidence?.(h.answer)}
                />
              )}

              {h.status === 'failed' && (
                <Card style={{ background: 'var(--warn-soft)', borderColor: 'var(--warn-line)' }}>
                  <div className="t-eyebrow" style={{ color: 'var(--warn)' }}>Could not verify</div>
                  <h3 className="t-h3" style={{ margin: '6px 0 0' }}>That question doesn't map to a verified source.</h3>
                  <p className="t-body-sm" style={{ marginTop: 6 }}>
                    KOVA only answers what it can fetch deterministically. Try rephrasing toward
                    margin, deadstock, quotes, or run history — or open the relevant module directly.
                  </p>
                </Card>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

Object.assign(window.K, { HomePage, ApprovalsInbox, ApprovalsDetail, ApprovalRow, AskKovaPage });
