// kova/orbit.jsx — Wave E · Head of Merchandising
// ----------------------------------------------------------------
// Routes (architecture v7 §8.2):
//   /orbit                    OrbitOverviewPage
//   /orbit/briefs             OrbitBriefsPage (drafts + submitted + history)
//   /orbit/briefs/:id         OrbitBriefDetailPage (HoM drafting UI)
//   /orbit/signals            OrbitSignalsPage (incoming market signals)
//
// HoM's runtime loop (matches §2):
//   1. ORBIT agent emits a verified output card (status=pending, awaitingMe=hom)
//   2. HoM reviews, optionally requests revision (re-runs agent with constraints)
//   3. HoM "Submits" → chain advances to CEO → appears in /approvals
//   4. CEO signs → connector executes → outcome tracked
//
// Composition discipline (Brad Frost atomic + claude-design-skill):
//   Pages compose only Templates and Organisms · never atoms directly.
//   Direction restyles atoms, not Organisms.
// ----------------------------------------------------------------

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

const { useState, useMemo } = React;

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


/* ============================================================
   SIGNAL CARD — new organism specific to ORBIT
   Composes atoms only · respects the no-bespoke-UI rule.
   ============================================================ */
const SignalCard = ({ signal, onSendToVault, onSaveToWiki, onCreateBrief, onDismiss }) => {
  const isFresh = signal.freshness === 'fresh';
  const isDismissed = signal.status === 'dismissed';
  const isTriaged = signal.status === 'triaged';

  return (
    <Card style={{ opacity: isDismissed ? 0.55 : 1 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', marginBottom: 8 }}>
        <Chip variant="mute" dot>{signal.source.toUpperCase()}</Chip>
        {isFresh
          ? <Chip variant="info" dot>FRESH</Chip>
          : <Chip variant="mute">stale</Chip>}
        {isTriaged   && <Chip variant="success" dot>TRIAGED</Chip>}
        {isDismissed && <Chip variant="mute">DISMISSED</Chip>}
        <ConfidenceMeter level={signal.confidence}
                         label={['Low','Med','High','Verified'][signal.confidence - 1]}
                         mod="orbit" />
        {signal.runId && <RunBadge id={signal.runId} />}
      </div>

      <div className="t-h3" style={{ marginBottom: 6 }}>{signal.title}</div>
      <p className="t-body-sm" style={{ color: 'var(--ink-2)', lineHeight: 1.55, margin: 0 }}>
        {signal.description}
      </p>

      {signal.metrics && signal.metrics.length > 0 && (
        <div style={{ display: 'flex', gap: 24, marginTop: 14 }}>
          {signal.metrics.map((m, i) => (
            <div key={i} style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
              <span className="t-eyebrow" style={{ color: 'var(--mute)' }}>{m.label}</span>
              <span style={{ fontSize: 16, fontWeight: 600, fontVariantNumeric: 'tabular-nums',
                             color: m.color === 'success' ? 'var(--success)' :
                                    m.color === 'danger'  ? 'var(--danger)'  : 'var(--ink)' }}>
                {m.value}
              </span>
            </div>
          ))}
        </div>
      )}

      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                    marginTop: 16, paddingTop: 12, borderTop: '1px solid var(--line-2)' }}>
        <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
          {signal.modulesTagged.map(m => (
            <Chip key={m} variant="mute">{MOD_LABEL[m] || m.toUpperCase()}</Chip>
          ))}
        </div>
        {!isDismissed && (
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {signal.modulesTagged.includes('vault') && (
              <Btn size="sm" variant="ghost" onClick={() => onSendToVault?.(signal.id)}>Send to VAULT</Btn>
            )}
            {signal.modulesTagged.includes('kraft') && (
              <Btn size="sm" variant="ghost" onClick={() => onCreateBrief?.(signal.id)}>Create KRAFT brief</Btn>
            )}
            <Btn size="sm" variant="ghost" onClick={() => onSaveToWiki?.(signal.id)}>Save to Wiki</Btn>
            <Btn size="sm" variant="ghost" onClick={() => onDismiss?.(signal.id)}>Dismiss</Btn>
          </div>
        )}
      </div>
    </Card>
  );
};


/* ============================================================
   ORBIT OVERVIEW — HoM landing page
   Template: ModuleOverview
   ============================================================ */
const OrbitOverviewPage = ({
  user = 'Priya', drafts, signals, opportunities,
  onOpenBrief, onGenerateBrief, onAskMarket, onSubmit, onRevise, onDiscard,
  onOpenDrawer, onOpenCmdK, onTriageSignal, onConvertOpportunity,
}) => {
  const draftsPending = drafts.filter(d => d.status === 'pending' || d.status === 'revising');
  const primary = draftsPending[0];
  const freshSignals = signals.filter(s => s.freshness === 'fresh' && s.status === 'new');
  const openOpportunities = opportunities.filter(o => o.status === 'open');

  const pageHead = (
    <PageHead
      crumb={['ORBIT', 'today', '09:42 IST']}
      title={`Good morning, ${user}.`}
      subtitle={draftsPending.length === 0
        ? 'No drafts in flight. Generate a fresh brief or triage signals.'
        : `${draftsPending.length} draft${draftsPending.length === 1 ? '' : 's'} in flight · ${freshSignals.length} fresh signals waiting.`}
      actions={
        <>
          <Btn size="sm" onClick={onGenerateBrief}>Generate brief</Btn>
          <Btn size="sm" onClick={onAskMarket}>Ask market question</Btn>
          {primary
            ? <Btn size="sm" variant="primary" onClick={() => onOpenBrief?.(primary.id)} kbd="⌘⏎">
                Open next draft
              </Btn>
            : <Btn size="sm" variant="primary" onClick={() => location.hash = 'orbit/signals'}>
                Triage signals
              </Btn>}
        </>
      }
    />
  );

  const kpis = [
    <KPITile key="d" mod="orbit"     label="Drafts in flight"   value={String(draftsPending.length)}
             foot={draftsPending.length ? 'awaiting your submit' : 'inbox zero'} />,
    <KPITile key="s" mod="vault"     label="Fresh signals"      value={String(freshSignals.length)}
             foot="across all modules" />,
    <KPITile key="o" mod="kraft"     label="Open opportunities" value={String(openOpportunities.length)}
             foot="awaiting conversion" />,
    <KPITile key="r" mod="approvals" label="Briefs · 7 d"       value="12"
             foot="9 approved · 2 revised · 1 rejected" valueColor="var(--success)" />,
  ];

  const empty = (
    <Card>
      <EmptyState
        mark="O"
        title="No drafts in flight."
        body="Generate today's brief or jump straight into signals waiting on your triage."
        cta={<><Btn size="sm" variant="primary" onClick={onGenerateBrief}>Generate brief</Btn></>}
      />
    </Card>
  );

  const primaryNode = primary && (
    <DecisionCard
      {...primary}
      onEvidence={() => onOpenDrawer?.(primary.id)}
      onRunHistory={() => location.hash = `monitor/${primary.runId}`}
      onReject={() => onDiscard?.(primary.id)}
      onRevise={() => onRevise?.(primary.id)}
      onApprove={() => onSubmit?.(primary.id)}
      primaryKbd="⌘⏎"
    />
  );

  const secondary = draftsPending.length > 1 && (
    <Card>
      <div className="t-eyebrow" style={{ marginBottom: 12 }}>Other drafts · {draftsPending.length - 1}</div>
      {draftsPending.slice(1).map(d => (
        <DraftRow key={d.id} draft={d}
          onOpen={onOpenBrief}
          onSubmit={onSubmit}
          onDiscard={onDiscard} />
      ))}
    </Card>
  );

  const signalsPreview = freshSignals.length > 0 && (
    <Card>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
        <div className="t-eyebrow">Fresh signals · {freshSignals.length}</div>
        <Btn size="sm" variant="ghost" onClick={() => location.hash = 'orbit/signals'}>Triage all ›</Btn>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
        {freshSignals.slice(0, 3).map(s => (
          <div key={s.id} style={{ display: 'flex', justifyContent: 'space-between',
                                   padding: '8px 0', borderTop: '1px solid var(--line-2)' }}>
            <div>
              <div style={{ fontSize: 13, color: 'var(--ink)', fontWeight: 500 }}>{s.title}</div>
              <div className="t-meta" style={{ marginTop: 2 }}>
                <Chip variant="mute" dot>{s.source.toUpperCase()}</Chip>
                <span style={{ marginLeft: 8 }}>{s.modulesTagged.map(m => MOD_LABEL[m]).join(' · ')}</span>
              </div>
            </div>
            <Btn size="sm" variant="ghost" onClick={() => onTriageSignal?.(s.id)}>Triage</Btn>
          </div>
        ))}
      </div>
    </Card>
  );

  const side = [
    <Card key="quick">
      <div className="t-eyebrow" style={{ marginBottom: 10 }}>Quick actions</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
        <Btn size="sm" variant="ghost" onClick={onGenerateBrief}>Generate brief · ⌘ B</Btn>
        <Btn size="sm" variant="ghost" onClick={onAskMarket} kbd="⌘ K">Ask market question</Btn>
        <Btn size="sm" variant="ghost" onClick={() => location.hash = 'orbit/signals'}>Open signals feed</Btn>
        <Btn size="sm" variant="ghost" onClick={() => location.hash = 'orbit/opportunities'}>All opportunities</Btn>
        <Btn size="sm" variant="ghost" onClick={() => location.hash = 'orbit/briefs'}>All briefs · history</Btn>
        <Btn size="sm" variant="ghost" onClick={() => location.hash = 'wiki'}>Save to Wiki</Btn>
      </div>
    </Card>,
    <Card key="opps">
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
        <div className="t-eyebrow">Open opportunities · {openOpportunities.length}</div>
        <Btn size="sm" variant="ghost" onClick={() => location.hash = 'orbit/opportunities'}>See all ›</Btn>
      </div>
      {openOpportunities.slice(0, 3).map(o => (
        <div key={o.id} style={{ padding: '10px 0', borderTop: '1px solid var(--line-2)' }}>
          <div style={{ fontSize: 12.5, color: 'var(--ink)', lineHeight: 1.4 }}>{o.title}</div>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 6 }}>
            <span className="t-meta">{o.projectedImpact.value}</span>
            <Btn size="sm" variant="ghost"
                 onClick={() => onConvertOpportunity?.(o.id, o.conversionPaths?.[0])}>
              {o.conversionPaths?.[0] === 'create_brief' ? 'Convert' : 'Forward'}
            </Btn>
          </div>
        </div>
      ))}
    </Card>,
    <Card key="health">
      <div className="t-eyebrow" style={{ marginBottom: 10 }}>Source health</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {[
          ['Sales feed',         '4 / 4 green',   'var(--success)'],
          ['Inventory snapshot', 'last 11 min',   'var(--ink)'],
          ['Vendor partners',    '2 / 2 green',   'var(--success)'],
          ['Social listening',   'last 4 min',    'var(--ink)'],
        ].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>,
  ];

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


/* ============================================================
   DRAFT ROW — compact row used in lists
   ============================================================ */
const DraftRow = ({ draft, onOpen, onSubmit, onDiscard }) => (
  <div className="k-approval-row"
       style={{ '--m-mod': `var(--m-${draft.mod})` }}
       onClick={() => onOpen?.(draft.id)}>
    <div className="k-approval-stripe" />
    <div className="k-approval-body">
      <div className="k-approval-head">
        <Chip variant="mute" dot>ORBIT · DRAFT</Chip>
        <StatusBadge kind="pending">{draft.statusLabel}</StatusBadge>
        <RunBadge id={draft.runId} version={draft.runVersion} when={draft.runWhen} />
      </div>
      <div className="k-approval-title">{draft.title}</div>
      <div className="k-approval-stats">
        {draft.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>
    <div className="k-approval-actions" onClick={(e) => e.stopPropagation()}>
      <Btn size="sm" variant="primary" onClick={() => onSubmit?.(draft.id)} kbd="⌘⏎">Submit</Btn>
      <Btn size="sm" variant="reject" onClick={() => onDiscard?.(draft.id)}>Discard</Btn>
    </div>
  </div>
);


/* ============================================================
   ORBIT BRIEFS PAGE — list of drafts + submitted + history
   Template: ListTable
   ============================================================ */
const OrbitBriefsPage = ({ drafts, onOpenBrief, onSubmit, onDiscard, onGenerateBrief, onOpenCmdK }) => {
  const [tab, setTab] = useState('drafts');

  const filtered = useMemo(() => {
    if (tab === 'drafts')    return drafts.filter(d => d.status === 'pending' || d.status === 'revising');
    if (tab === 'submitted') return drafts.filter(d => d.status === 'executing' || d.status === 'approved');
    if (tab === 'rejected')  return drafts.filter(d => d.status === 'rejected');
    return drafts;
  }, [drafts, tab]);

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

  return (
    <ListTable
      pageHead={
        <PageHead
          crumb={['ORBIT', 'briefs']}
          title="Briefs · draft and history"
          subtitle="Drafts wait for your submit. Submitted briefs flow to CEO Approvals. Rejected come back here for revision."
          actions={
            <>
              <Btn size="sm" onClick={onOpenCmdK} kbd="⌘K">Jump to…</Btn>
              <Btn size="sm" variant="primary" onClick={onGenerateBrief}>Generate brief</Btn>
            </>
          }
        />
      }
      tabs={
        <Tabs value={tab} onChange={setTab} mod="orbit" items={[
          { id: 'drafts',    label: 'Drafts',    count: counts.drafts },
          { id: 'submitted', label: 'Submitted', count: counts.submitted },
          { id: 'rejected',  label: 'Rejected',  count: counts.rejected },
          { id: 'all',       label: 'All',       count: counts.all },
        ]} />
      }
      empty={filtered.length === 0 ? (
        <Card>
          <EmptyState
            mark="O"
            title={tab === 'drafts' ? 'No drafts in flight.' : `No ${tab} briefs.`}
            body={tab === 'drafts' ? 'Generate today’s brief or open the signals feed.' : 'Switch tabs above.'}
            cta={tab === 'drafts' ? <Btn size="sm" variant="primary" onClick={onGenerateBrief}>Generate brief</Btn> : null}
          />
        </Card>
      ) : null}
      body={filtered.map(d => (
        <DraftRow key={d.id} draft={d}
                  onOpen={onOpenBrief}
                  onSubmit={onSubmit}
                  onDiscard={onDiscard} />
      ))}
    />
  );
};


/* ============================================================
   ORBIT BRIEF DETAIL — HoM drafting UI
   Template: DetailObject
   Different actions than CEO's ApprovalsDetail:
     - "Submit to CEO" (primary)
     - "Refine with agent" (re-runs with constraints)
     - "Discard draft" (deletes)
   ============================================================ */
const OrbitBriefDetailPage = ({ draft, onBack, onSubmit, onRevise, onDiscard, onSendToVault, onCreateKraftBrief, onSaveToWiki }) => {
  if (!draft) {
    return (
      <DetailObject
        back={<button className="k-detail-back" onClick={onBack}>← Back to ORBIT</button>}
        pageHead={<PageHead crumb={['ORBIT', 'briefs']} title="Draft not found" />}
        main={[
          <Card key="x">
            <EmptyState
              mark="?"
              title="That draft doesn’t exist."
              body="It may have been submitted, discarded, or expired."
              cta={<Btn size="sm" onClick={onBack}>Back to briefs</Btn>}
            />
          </Card>
        ]}
        side={[]}
      />
    );
  }

  return (
    <DetailObject
      back={<button className="k-detail-back" onClick={onBack}>← Back to briefs</button>}
      pageHead={
        <PageHead
          crumb={['ORBIT', 'briefs', draft.runId]}
          title={draft.title}
          subtitle={draft.reasoning}
          actions={
            <>
              <Btn size="sm" variant="reject" onClick={() => onDiscard?.(draft.id)}>Discard</Btn>
              <Btn size="sm" onClick={() => onRevise?.(draft.id)}>Refine with agent</Btn>
              <Btn size="sm" variant="primary" onClick={() => onSubmit?.(draft.id)} kbd="⌘⏎">
                Submit to {draft.cosign?.includes('Pricing') ? 'Pricing co-sign' : 'CEO'}
              </Btn>
            </>
          }
        />
      }
      statusRow={
        <>
          <VerificationStamp>{draft.stamp || 'Verified'}</VerificationStamp>
          <StatusBadge kind="pending">{draft.statusLabel}</StatusBadge>
          <RunBadge id={draft.runId} version={draft.runVersion} when={draft.runWhen} />
          {draft.confidence && <ConfidenceMeter level={draft.confidence} label={draft.confidenceLabel} mod="orbit" />}
          <Chip variant="info" dot>HoM drafting</Chip>
        </>
      }
      main={[
        <Card key="stats">
          <div className="t-eyebrow" style={{ marginBottom: 12 }}>Brief summary</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 16 }}>
            {draft.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>,
        <Card key="actions">
          <div className="t-eyebrow" style={{ marginBottom: 12 }}>Forward to other modules</div>
          <p className="t-body-sm" style={{ marginTop: 0, color: 'var(--mute)' }}>
            Cross-pollinate this brief’s findings. Each action creates an entity in the target module
            with this brief’s runId as the source · audited.
          </p>
          <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 12 }}>
            <Btn size="sm" onClick={() => onSendToVault?.(draft.id)}>Send signal to VAULT</Btn>
            <Btn size="sm" onClick={() => onCreateKraftBrief?.(draft.id)}>Create KRAFT brief</Btn>
            <Btn size="sm" onClick={() => onSaveToWiki?.(draft.id)}>Save to Wiki</Btn>
          </div>
        </Card>,
        <RunObject key="run"
          mod="orbit"
          runId={draft.runId}
          status="pending"
          title={`orbit.daily_brief · ${draft.runVersion} · ${draft.runWhen}`}
          agent="orbit_brief_agent · v2.1"
          skillVersion="acme.orbit.skills @ 2026.05.18-3"
          memoryVersion="acme.memory @ 2026.05.20"
          startedAt={draft.runWhen}
          cost="$0.018"
          latency="8.4 s"
          onOpenTrace={() => location.hash = `monitor/${draft.runId}`}
        />,
        <WorkflowTimeline key="wf"
          title="Workflow · pre-submission"
          actions={<Btn size="sm" variant="ghost" onClick={() => location.hash = `monitor/${draft.runId}`}>Open in MONITOR ›</Btn>}
          steps={draft.workflow}
        />,
      ]}
      side={[
        <EvidencePanel key="ev"
          runId={draft.runId}
          claims={draft.claims || []}
          receipts={draft.receipts || []}
          math={draft.math || []}
        />,
        <ApprovalSurface key="as"
          mod="orbit"
          runId={draft.runId}
          title="Pre-approval chain"
          chain={draft.chain}
          onReject={() => onDiscard?.(draft.id)}
          onRevise={() => onRevise?.(draft.id)}
          onApprove={() => onSubmit?.(draft.id)}
          primaryKbd="⌘⏎"
        />,
      ]}
      footer={
        <div className="k-detail-footer">
          <div className="k-detail-footer-left">
            <Icon name="check" />
            <span>Submitting moves this brief to {draft.cosign?.includes('Pricing') ? 'Pricing for co-sign' : 'CEO Approvals'}. This action is audited.</span>
          </div>
          <div className="k-detail-footer-right">
            <Btn variant="reject" onClick={() => onDiscard?.(draft.id)}>Discard</Btn>
            <Btn onClick={() => onRevise?.(draft.id)}>Refine with agent</Btn>
            <Btn variant="primary" onClick={() => onSubmit?.(draft.id)} kbd="⌘⏎">
              Submit to {draft.cosign?.includes('Pricing') ? 'Pricing co-sign' : 'CEO'}
            </Btn>
          </div>
        </div>
      }
    />
  );
};


/* ============================================================
   ORBIT SIGNALS PAGE — incoming market signals with triage
   Template: ListTable
   ============================================================ */
const OrbitSignalsPage = ({ signals, onSendToVault, onSaveToWiki, onCreateBrief, onDismiss, onOpenCmdK }) => {
  const [tab, setTab] = useState('new');
  const [sourceFilter, setSourceFilter] = useState('all');

  const filtered = useMemo(() => {
    let xs = signals;
    if (tab === 'new')       xs = xs.filter(s => s.status === 'new');
    if (tab === 'triaged')   xs = xs.filter(s => s.status === 'triaged');
    if (tab === 'dismissed') xs = xs.filter(s => s.status === 'dismissed');
    if (sourceFilter !== 'all') xs = xs.filter(s => s.source === sourceFilter);
    return xs;
  }, [signals, tab, sourceFilter]);

  const counts = {
    new:       signals.filter(s => s.status === 'new').length,
    triaged:   signals.filter(s => s.status === 'triaged').length,
    dismissed: signals.filter(s => s.status === 'dismissed').length,
    all:       signals.length,
  };

  const sources = [...new Set(signals.map(s => s.source))];

  return (
    <ListTable
      pageHead={
        <PageHead
          crumb={['ORBIT', 'signals']}
          title="Signals · incoming"
          subtitle="Market signals from sales, catalogue, partners, social, news. Triage each into a brief, a VAULT action, or Wiki memory."
          actions={
            <>
              <Btn size="sm" onClick={onOpenCmdK} kbd="⌘K">Jump to…</Btn>
              <Btn size="sm" variant="primary" onClick={() => filtered[0] && onCreateBrief?.(filtered[0].id)}
                   disabled={!filtered.find(s => s.status === 'new')}>
                Brief from next signal
              </Btn>
            </>
          }
        />
      }
      tabs={
        <Tabs value={tab} onChange={setTab} mod="orbit" items={[
          { id: 'new',       label: 'New',       count: counts.new },
          { id: 'triaged',   label: 'Triaged',   count: counts.triaged },
          { id: 'dismissed', label: 'Dismissed', count: counts.dismissed },
          { id: 'all',       label: 'All',       count: counts.all },
        ]} />
      }
      filterBar={
        <div className="k-inbox-filter">
          <span className="k-inbox-filter-label">Source</span>
          <div className="k-inbox-filter-chips">
            <Chip variant={sourceFilter === 'all' ? 'solid' : 'mute'} onClick={() => setSourceFilter('all')}>All</Chip>
            {sources.map(s => (
              <Chip key={s}
                    variant={sourceFilter === s ? 'solid' : 'mute'}
                    onClick={() => setSourceFilter(s)}>{s.toUpperCase()}</Chip>
            ))}
          </div>
        </div>
      }
      empty={filtered.length === 0 ? (
        <Card>
          <EmptyState
            mark="O"
            title={tab === 'new' ? 'No new signals.' : `No ${tab} signals.`}
            body={tab === 'new' ? 'Orbit scans every 6 hours. Next scan in ~4 h.' : 'Switch tabs above.'}
          />
        </Card>
      ) : null}
      body={
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {filtered.map(s => (
            <SignalCard key={s.id} signal={s}
              onSendToVault={onSendToVault}
              onSaveToWiki={onSaveToWiki}
              onCreateBrief={onCreateBrief}
              onDismiss={onDismiss} />
          ))}
        </div>
      }
    />
  );
};


/* ============================================================
   OPPORTUNITY CARD — new organism for the dedicated page
   ============================================================ */
const PATH_LABEL = {
  create_brief:    'Convert to brief',
  send_to_vault:   'Send to VAULT',
  send_to_kraft:   'Send to KRAFT',
  cosign_pricing:  'Co-sign with PRICE',
  save_to_wiki:    'Save to WIKI',
};
const PATH_MOD = {
  create_brief:   'orbit',
  send_to_vault:  'vault',
  send_to_kraft:  'kraft',
  cosign_pricing: 'price',
  save_to_wiki:   'wiki',
};

const OpportunityCard = ({ opp, onConvert }) => {
  const isOpen = opp.status === 'open';
  return (
    <Card style={{ opacity: isOpen ? 1 : 0.6 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', marginBottom: 8 }}>
        <Chip variant="mute" dot>OPPORTUNITY</Chip>
        <ConfidenceMeter level={opp.confidence}
                         label={['Low','Med','High','Verified'][opp.confidence - 1]}
                         mod="orbit" />
        <StatusBadge kind={opp.status === 'open' ? 'pending'
                          : opp.status === 'converted' ? 'verified' : 'drift'}>
          {opp.status}
        </StatusBadge>
        {opp.expiresAt && (
          <span className="t-meta" style={{ marginLeft: 'auto' }}>
            expires · {new Date(opp.expiresAt).toLocaleDateString('en-IN', { day: 'numeric', month: 'short' })}
          </span>
        )}
      </div>

      <div className="t-h3" style={{ marginBottom: 6 }}>{opp.title}</div>
      <p className="t-body-sm" style={{ color: 'var(--ink-2)', lineHeight: 1.55, margin: 0 }}>
        {opp.description}
      </p>

      <div style={{ display: 'flex', gap: 24, marginTop: 14 }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
          <span className="t-eyebrow" style={{ color: 'var(--mute)' }}>Projected impact</span>
          <span style={{ fontSize: 18, fontWeight: 600, color: 'var(--success)',
                         fontVariantNumeric: 'tabular-nums' }}>
            {opp.projectedImpact.value}
          </span>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
          <span className="t-eyebrow" style={{ color: 'var(--mute)' }}>Related signals</span>
          <span className="t-mono" style={{ color: 'var(--ink-2)', fontSize: 12 }}>
            {opp.relatedSignals?.join(' · ') || '—'}
          </span>
        </div>
      </div>

      {isOpen && (
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 6, flexWrap: 'wrap',
                      marginTop: 16, paddingTop: 12, borderTop: '1px solid var(--line-2)' }}>
          {opp.conversionPaths.map(p => (
            <Btn key={p} size="sm"
                 variant={p === opp.conversionPaths[0] ? 'primary' : 'ghost'}
                 onClick={() => onConvert?.(opp.id, p)}>
              {PATH_LABEL[p] || p}
            </Btn>
          ))}
        </div>
      )}
    </Card>
  );
};


/* ============================================================
   OPPORTUNITIES PAGE · architecture §8.2 /orbit/opportunities
   Template: ListTable
   ============================================================ */
const OrbitOpportunitiesPage = ({ opportunities, onConvert, onOpenCmdK }) => {
  const [tab, setTab] = useState('open');

  const filtered = useMemo(() => {
    if (tab === 'open')      return opportunities.filter(o => o.status === 'open');
    if (tab === 'converted') return opportunities.filter(o => o.status === 'converted');
    if (tab === 'expired')   return opportunities.filter(o => o.status === 'expired');
    return opportunities;
  }, [opportunities, tab]);

  const counts = {
    open:      opportunities.filter(o => o.status === 'open').length,
    converted: opportunities.filter(o => o.status === 'converted').length,
    expired:   opportunities.filter(o => o.status === 'expired').length,
    all:       opportunities.length,
  };

  return (
    <ListTable
      pageHead={
        <PageHead
          crumb={['ORBIT', 'opportunities']}
          title="Opportunities · forward-looking action items"
          subtitle="Distilled from signals. Each opportunity advertises one or more conversion paths — pick the one that fits your week."
          actions={
            <>
              <Btn size="sm" onClick={onOpenCmdK} kbd="⌘K">Jump to…</Btn>
              <Btn size="sm" variant="primary"
                   onClick={() => filtered[0] && onConvert?.(filtered[0].id, filtered[0].conversionPaths[0])}
                   disabled={!filtered.find(o => o.status === 'open')}>
                Convert next
              </Btn>
            </>
          }
        />
      }
      tabs={
        <Tabs value={tab} onChange={setTab} mod="orbit" items={[
          { id: 'open',      label: 'Open',      count: counts.open },
          { id: 'converted', label: 'Converted', count: counts.converted },
          { id: 'expired',   label: 'Expired',   count: counts.expired },
          { id: 'all',       label: 'All',       count: counts.all },
        ]} />
      }
      empty={filtered.length === 0 ? (
        <Card>
          <EmptyState
            mark="O"
            title={tab === 'open' ? 'No open opportunities.' : `No ${tab} opportunities.`}
            body={tab === 'open' ? 'Orbit distills new opportunities from signals each scan cycle.' : 'Switch tabs above.'}
          />
        </Card>
      ) : null}
      body={
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {filtered.map(o => (
            <OpportunityCard key={o.id} opp={o} onConvert={onConvert} />
          ))}
        </div>
      }
    />
  );
};


Object.assign(window.K, {
  OrbitOverviewPage, OrbitBriefsPage, OrbitBriefDetailPage, OrbitSignalsPage,
  OrbitOpportunitiesPage,
  SignalCard, DraftRow, OpportunityCard,
  PATH_LABEL, PATH_MOD,
});
