// invodiff-compare.jsx — comparison view, summary, action bar, vendor rules.

const STATUS_META = {
  match:   { label: 'Match',      tone: 'ok',   short: '✓' },
  price:   { label: 'Price drift',tone: 'warn', short: '$' },
  qty:     { label: 'Qty change', tone: 'warn', short: '#' },
  multi:   { label: 'Multi flag', tone: 'bad',  short: '!' },
  missing: { label: 'Missing',    tone: 'bad',  short: '−' },
  added:   { label: 'Added line', tone: 'bad',  short: '+' },
};

function StatusPill({ status, resolved }) {
  if (resolved) {
    return <span className="status status-info" title="Auto-resolved by vendor rule"><span className="status-dot"/> Resolved</span>;
  }
  const m = STATUS_META[status];
  return <span className={`status status-${m.tone}`}><span className="status-dot"/> {m.label}</span>;
}

// ── Summary cards ────────────────────────────────────────────────────────
function SummaryStrip({ summary, vendor, historyCount }) {
  const sign = summary.totalDelta >= 0 ? '+' : '−';
  const deltaAbs = Math.abs(summary.totalDelta);
  const deltaTone = summary.totalDelta === 0 ? 'ok' : (summary.totalDelta > 0 ? 'warn' : 'bad');
  const matchTone = summary.matchPct >= 0.85 ? 'ok' : summary.matchPct >= 0.6 ? 'warn' : 'bad';

  return (
    <div className="summary">
      <SummaryCard
        label="Total discrepancy"
        valueClass={`sc-v-${deltaTone}`}
        value={(
          <>
            <span className="sc-sign">{sign}</span>
            <span>{fmtUSD(deltaAbs)}</span>
          </>
        )}
        sub={`Invoice B is ${summary.totalDelta >= 0 ? 'higher' : 'lower'} than baseline`}
        bar={Math.min(1, deltaAbs / Math.max(1, summary.totalA))}
        barTone={deltaTone}
      />
      <SummaryCard
        label="Match percentage"
        value={<><span>{Math.round(summary.matchPct * 100)}</span><span className="sc-unit">%</span></>}
        valueClass={`sc-v-${matchTone}`}
        sub={`${summary.matchCount} of ${summary.rowCount} rows align`}
        bar={summary.matchPct}
        barTone={matchTone}
      />
      <SummaryCard
        label="Items flagged"
        value={<><span>{summary.flaggedCount}</span><span className="sc-unit">/{summary.rowCount}</span></>}
        valueClass={summary.flaggedCount === 0 ? 'sc-v-ok' : 'sc-v-warn'}
        sub={summary.resolvedCount > 0 ? `${summary.resolvedCount} auto-resolved by rules` : 'Awaiting your review'}
        bar={summary.flaggedCount / Math.max(1, summary.rowCount)}
        barTone={summary.flaggedCount === 0 ? 'ok' : 'warn'}
      />
      <SummaryCard
        label="Vendor context"
        value={<><span>{historyCount}</span><span className="sc-unit">{historyCount === 1 ? 'rule' : 'rules'}</span></>}
        valueClass="sc-v-info"
        sub={vendor || '—'}
        bar={historyCount ? 1 : 0}
        barTone="info"
      />
    </div>
  );
}

function SummaryCard({ label, value, valueClass, sub, bar, barTone }) {
  return (
    <div className="sc">
      <div className="sc-l">{label}</div>
      <div className={`sc-v ${valueClass || ''}`}>{value}</div>
      <div className="sc-sub">{sub}</div>
      <div className="sc-bar">
        <div className={`sc-bar-fill sc-bar-${barTone}`} style={{ width: `${Math.min(100, Math.max(2, bar * 100))}%` }} />
      </div>
    </div>
  );
}

// ── Comparison Grid ──────────────────────────────────────────────────────
function CompareGrid({ comparison, invoiceA, invoiceB, filter, onSelect, selected }) {
  const rows = comparison.rows.filter((r) => {
    if (filter === 'all') return true;
    if (filter === 'flagged') return r.status !== 'match' && !r.resolved;
    if (filter === 'matches') return r.status === 'match' || r.resolved;
    return true;
  });

  return (
    <div className="cg">
      <div className="cg-head">
        <div className="cg-h cg-h-sku">SKU</div>
        <div className="cg-h cg-h-desc">Description</div>
        <div className="cg-h cg-h-qty">Qty A</div>
        <div className="cg-h cg-h-qty">Qty B</div>
        <div className="cg-h cg-h-num">Unit A</div>
        <div className="cg-h cg-h-num">Unit B</div>
        <div className="cg-h cg-h-num">Total A</div>
        <div className="cg-h cg-h-num">Total B</div>
        <div className="cg-h cg-h-num">Δ</div>
        <div className="cg-h cg-h-status">Status</div>
      </div>

      <div className="cg-body">
        {rows.length === 0 && (
          <div className="cg-empty">No rows match this filter.</div>
        )}
        {rows.map((r, i) => (
          <CompareRow key={r.sku + '-' + i} row={r}
                      selected={selected === r.sku}
                      onClick={() => onSelect(r.sku)} />
        ))}
      </div>

      <div className="cg-foot">
        <div className="cg-f cg-f-label">Subtotals</div>
        <div className="cg-f cg-f-num num">{fmtUSD(comparison.summary.subA)}</div>
        <div className="cg-f cg-f-num num">{fmtUSD(comparison.summary.subB)}</div>
        <div className="cg-f cg-f-num num cg-f-delta">
          {fmtDelta(+(comparison.summary.subB - comparison.summary.subA).toFixed(2))}
        </div>
      </div>
      <div className="cg-grand">
        <div className="cg-grand-label">Grand total</div>
        <div className="cg-grand-vals">
          <div><span className="cg-grand-k">A</span> <span className="num">{fmtUSD(comparison.summary.totalA)}</span></div>
          <div className="cg-grand-arrow"><Icon name="arrow" size={14}/></div>
          <div><span className="cg-grand-k">B</span> <span className="num">{fmtUSD(comparison.summary.totalB)}</span></div>
          <div className={`cg-grand-delta cg-grand-delta-${comparison.summary.totalDelta === 0 ? 'ok' : 'warn'}`}>
            {fmtDelta(comparison.summary.totalDelta)}
          </div>
        </div>
      </div>
    </div>
  );
}

function CompareRow({ row, selected, onClick }) {
  const left = row.left || {};
  const right = row.right || {};
  const tone = STATUS_META[row.status].tone;
  const rowClass = row.resolved
    ? 'cg-row cg-row-resolved'
    : `cg-row cg-row-${tone}`;

  return (
    <div className={`${rowClass} ${selected ? 'is-selected' : ''} ${row.synthetic ? 'cg-row-synthetic' : ''}`}
         onClick={onClick}>
      <div className="cg-c cg-c-sku mono">{row.synthetic ? '—' : row.sku}</div>
      <div className="cg-c cg-c-desc" title={left.desc || right.desc}>
        {left.desc || right.desc}
        {row.synthetic && <span className="cg-c-syn">{row.synthetic}</span>}
      </div>

      {/* Qty */}
      <div className={`cg-c cg-c-qty num ${row.flags.qty || row.flags.missing ? 'is-flag-strike' : ''}`}>
        {row.left ? row.left.qty : <span className="cg-c-dash">—</span>}
      </div>
      <div className={`cg-c cg-c-qty num ${row.flags.qty || row.flags.added ? 'is-flag' : ''}`}>
        {row.right ? row.right.qty : <span className="cg-c-dash">—</span>}
      </div>

      {/* Unit */}
      <div className={`cg-c cg-c-num num ${row.flags.price || row.flags.missing ? 'is-flag-strike' : ''}`}>
        {row.left ? fmtUSD(row.left.unit) : <span className="cg-c-dash">—</span>}
      </div>
      <div className={`cg-c cg-c-num num ${row.flags.price || row.flags.added ? 'is-flag' : ''}`}>
        {row.right ? fmtUSD(row.right.unit) : <span className="cg-c-dash">—</span>}
      </div>

      {/* Total */}
      <div className="cg-c cg-c-num num cg-c-total">
        {row.left ? fmtUSD(row.lineA) : <span className="cg-c-dash">—</span>}
      </div>
      <div className="cg-c cg-c-num num cg-c-total">
        {row.right ? fmtUSD(row.lineB) : <span className="cg-c-dash">—</span>}
      </div>

      {/* Delta */}
      <div className={`cg-c cg-c-num num cg-c-delta ${row.lineDelta === 0 ? '' : (row.lineDelta > 0 ? 'cg-c-delta-pos' : 'cg-c-delta-neg')}`}>
        {row.lineDelta === 0 ? '—' : fmtDelta(row.lineDelta)}
      </div>

      <div className="cg-c cg-c-status">
        <StatusPill status={row.status} resolved={row.resolved} />
      </div>
    </div>
  );
}

// ── Detail panel for a selected row ──────────────────────────────────────
function DetailPanel({ row, onClose }) {
  if (!row) return (
    <div className="detail detail-empty">
      <div className="detail-empty-icon"><Icon name="eye" size={20}/></div>
      <div className="detail-empty-h">Row inspector</div>
      <div className="detail-empty-sub">Click any line item to see the side-by-side breakdown and applicable vendor rules.</div>
    </div>
  );

  const flagList = [
    row.flags.price && 'Unit price changed',
    row.flags.qty && 'Quantity changed',
    row.flags.missing && 'Line missing from Invoice B',
    row.flags.added && 'Line added in Invoice B',
  ].filter(Boolean);

  return (
    <div className="detail">
      <div className="detail-hd">
        <div>
          <div className="detail-tag mono">LINE INSPECTOR</div>
          <div className="detail-sku mono">{row.sku}</div>
        </div>
        <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="x" size={13}/></button>
      </div>
      <div className="detail-desc">{(row.left && row.left.desc) || (row.right && row.right.desc)}</div>

      <div className="detail-status">
        <StatusPill status={row.status} resolved={row.resolved} />
        {row.resolved && row.resolvedBy && (
          <span className="detail-resolved-note">
            via rule: <span className="mono">{row.resolvedBy.pattern}</span>
          </span>
        )}
      </div>

      <div className="detail-grid">
        <div className="detail-col">
          <div className="detail-col-h">Invoice A</div>
          <div className="detail-kv"><span>Qty</span><span className="num">{row.left ? row.left.qty : '—'}</span></div>
          <div className="detail-kv"><span>Unit</span><span className="num">{row.left ? fmtUSD(row.left.unit) : '—'}</span></div>
          <div className="detail-kv detail-kv-total"><span>Line total</span><span className="num">{row.left ? fmtUSD(row.lineA) : '—'}</span></div>
        </div>
        <div className="detail-arrow"><Icon name="arrow" size={14}/></div>
        <div className="detail-col">
          <div className="detail-col-h">Invoice B</div>
          <div className={`detail-kv ${row.flags.qty || row.flags.added ? 'is-diff' : ''}`}><span>Qty</span><span className="num">{row.right ? row.right.qty : '—'}</span></div>
          <div className={`detail-kv ${row.flags.price || row.flags.added ? 'is-diff' : ''}`}><span>Unit</span><span className="num">{row.right ? fmtUSD(row.right.unit) : '—'}</span></div>
          <div className="detail-kv detail-kv-total"><span>Line total</span><span className="num">{row.right ? fmtUSD(row.lineB) : '—'}</span></div>
        </div>
      </div>

      {flagList.length > 0 && (
        <div className="detail-flags">
          <div className="label">Flags</div>
          <ul>{flagList.map((f) => <li key={f}><Icon name="flag" size={11}/> {f}</li>)}</ul>
        </div>
      )}

      <div className="detail-delta">
        <div className="label">Line Δ</div>
        <div className={`detail-delta-v num ${row.lineDelta > 0 ? 'pos' : row.lineDelta < 0 ? 'neg' : ''}`}>
          {row.lineDelta === 0 ? fmtUSD(0) : fmtDelta(row.lineDelta)}
        </div>
      </div>
    </div>
  );
}

// ── Vendor Rules Panel ───────────────────────────────────────────────────
function VendorRulesPanel({ vendor, rules, onAddRule, onRemove }) {
  return (
    <div className="vrp">
      <div className="vrp-hd">
        <div>
          <div className="vrp-tag mono">VENDOR RULES CONTEXT</div>
          <div className="vrp-vendor">{vendor || '—'}</div>
        </div>
        <span className="status status-info"><span className="status-dot"/> {rules.length} rule{rules.length === 1 ? '' : 's'}</span>
      </div>

      <div className="vrp-list">
        {rules.length === 0 && (
          <div className="vrp-empty">
            <Icon name="rule" size={16} />
            <span>No saved rules. Reject discrepancies below with a correction note to build context for next time.</span>
          </div>
        )}
        {rules.map((r) => (
          <div key={r.id} className={`vrp-row vrp-row-${r.kind}`}>
            <div className="vrp-row-l">
              <div className="vrp-row-kind">
                <span className={`vrp-kind vrp-kind-${r.kind}`}>{r.kind}</span>
                <span className="mono vrp-row-pat">{r.pattern}</span>
              </div>
              <div className="vrp-row-note">{r.note}</div>
            </div>
            <div className="vrp-row-r">
              <span className="vrp-row-date mono">{r.added}</span>
              <button className="btn btn-ghost btn-sm" onClick={() => onRemove(r.id)} title="Remove rule">
                <Icon name="x" size={12}/>
              </button>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ── Action Bar ───────────────────────────────────────────────────────────
function ActionBar({ vendor, comparison, onApprove, onReject, onSaveRule, decision, onStartNew, onViewVendor }) {
  const [note, setNote] = React.useState('');
  const [pattern, setPattern] = React.useState('*');
  const [kind, setKind] = React.useState('ignore');

  const handleReject = () => {
    if (note.trim().length > 0) {
      onSaveRule({ kind, pattern, note: note.trim() });
    }
    onReject(note.trim());
    setNote('');
  };
  const handleApprove = () => {
    if (note.trim().length > 0) {
      onSaveRule({ kind: 'note', pattern: '*', note: note.trim() });
    }
    onApprove(note.trim());
    setNote('');
  };

  const skus = comparison.rows
    .filter((r) => !r.synthetic && (r.status !== 'match' || r.resolved))
    .map((r) => r.sku);

  if (decision) {
    return (
      <div className={`actionbar actionbar-${decision.kind}`}>
        <div className="ab-decision">
          <div className={`ab-decision-icon ab-decision-icon-${decision.kind}`}>
            <Icon name={decision.kind === 'approved' ? 'check' : 'flag'} size={18}/>
          </div>
          <div>
            <div className="ab-decision-h">{decision.kind === 'approved' ? 'Comparison approved' : 'Discrepancies flagged'}</div>
            <div className="ab-decision-sub">
              {decision.note
                ? <>Saved as context for <span className="mono">{vendor}</span> · <em>&ldquo;{decision.note}&rdquo;</em></>
                : <>No additional context saved for <span className="mono">{vendor}</span>.</>}
            </div>
          </div>
        </div>
        <div className="ab-decision-actions">
          <button className="btn btn-sm btn-ghost" onClick={decision.onUndo}>
            <Icon name="reset" size={12}/> Undo
          </button>
          {onViewVendor && (
            <button className="btn btn-sm" onClick={onViewVendor}>
              <Icon name="rule" size={12}/> View vendor context
            </button>
          )}
          <button className="btn btn-primary btn-sm" onClick={onStartNew}>
            <Icon name="plus" size={13}/> Compare another
          </button>
        </div>
      </div>
    );
  }

  return (
    <div className="actionbar">
      <div className="ab-inner">
        <div className="ab-left">
          <div className="label">Add vendor context / correction notes</div>
          <textarea
            className="textarea ab-textarea"
            placeholder="e.g. &ldquo;Vendor XYZ changed their standard shipping rate to $50&rdquo; or &ldquo;Disregard 5% fuel surcharge variance.&rdquo;"
            value={note}
            onChange={(e) => setNote(e.target.value)}
          />
          <div className="ab-rule-builder">
            <span className="ab-rb-pre">Save as</span>
            <select className="select ab-rb-select" value={kind} onChange={(e) => setKind(e.target.value)}>
              <option value="ignore">Ignore-rule</option>
              <option value="tolerance">Tolerance ±3%</option>
              <option value="note">Vendor note</option>
            </select>
            <span className="ab-rb-pre">for</span>
            <select className="select ab-rb-select" value={pattern} onChange={(e) => setPattern(e.target.value)}>
              <option value="*">All line items</option>
              {skus.map((s) => <option key={s} value={s}>{s}</option>)}
            </select>
          </div>
        </div>
        <div className="ab-right">
          <div className="label">Decision</div>
          <div className="ab-decision-buttons">
            <button className="btn btn-bad btn-lg" onClick={handleReject}>
              <Icon name="flag" size={14}/> Reject / Flag discrepancies
            </button>
            <button className="btn btn-ok btn-lg" onClick={handleApprove}>
              <Icon name="check" size={14}/> Approve / Accept match
            </button>
          </div>
          <div className="ab-help">Decision is logged against this vendor; notes feed future comparisons.</div>
        </div>
      </div>
    </div>
  );
}

// ── Claude analysis helpers ──────────────────────────────────────────────
function buildAnalysisPrompt(invoiceA, invoiceB, comparison, vendor, rules) {
  const { summary, rows } = comparison;
  const flagged  = rows.filter(r => r.status !== 'match' && !r.resolved);
  const resolved = rows.filter(r => r.resolved);
  const parts = [
    `Vendor: ${vendor}`,
    `Invoice A: ${invoiceA.id} (${invoiceA.date})`,
    `Invoice B: ${invoiceB.id} (${invoiceB.date})`,
    ``,
    `Totals: A = $${summary.totalA.toFixed(2)}, B = $${summary.totalB.toFixed(2)}, Delta = ${summary.totalDelta >= 0 ? '+' : ''}$${summary.totalDelta.toFixed(2)}`,
    `Match rate: ${Math.round(summary.matchPct * 100)}% (${summary.matchCount}/${summary.rowCount} rows)`,
  ];
  if (flagged.length) {
    parts.push('', `Flagged (${flagged.length}):`);
    for (const r of flagged) {
      const side = r.left || r.right;
      parts.push(`  ${r.sku} "${side.desc}" — ${r.status}, delta $${r.lineDelta.toFixed(2)}`);
    }
  }
  if (resolved.length) parts.push('', `Auto-resolved by vendor rules: ${resolved.length} item(s)`);
  if (rules.length) {
    parts.push('', 'Active vendor rules:');
    for (const r of rules) parts.push(`  [${r.kind}] ${r.pattern}: ${r.note}`);
  }
  return parts.join('\n');
}

function ClaudeAnalysisPanel({ text, onDismiss }) {
  return (
    <div className="cap">
      <div className="cap-hd">
        <div className="cap-tag mono">CLAUDE ANALYSIS</div>
        <button className="btn btn-ghost btn-sm" onClick={onDismiss}><Icon name="x" size={12}/></button>
      </div>
      <div className="cap-body">{text}</div>
    </div>
  );
}

// ── Compare View root ────────────────────────────────────────────────────
function CompareView({ state, vendorRules, setVendorRules, onBack, onStartNew, onViewVendors }) {
  const { invoiceA, invoiceB, vendor } = state;
  const [filter, setFilter] = React.useState('all');
  const [selectedSku, setSelectedSku] = React.useState(null);
  const [decision, setDecision] = React.useState(null);
  const [showRules, setShowRules] = React.useState(true);
  const [analysis, setAnalysis] = React.useState(null);

  const rules = vendorRules[vendor] || [];

  const runAnalysis = async () => {
    setAnalysis('loading');
    try {
      const result = await askClaude({
        system: 'You are a professional invoice analyst. Given a comparison summary, write a concise plain-prose analysis (max 180 words) covering: overall match quality, key discrepancies and their likely causes, and a recommended action. Output plain text only.',
        messages: [{ role: 'user', content: buildAnalysisPrompt(invoiceA, invoiceB, comparison, vendor, rules) }],
        max_tokens: 512,
      });
      setAnalysis(result);
    } catch (e) {
      setAnalysis(`Analysis failed: ${e.message}`);
    }
  };
  const comparison = React.useMemo(
    () => compareInvoices(invoiceA, invoiceB, rules),
    [invoiceA, invoiceB, rules]
  );
  const selectedRow = comparison.rows.find((r) => r.sku === selectedSku) || null;

  const counts = {
    all: comparison.rows.length,
    flagged: comparison.rows.filter((r) => r.status !== 'match' && !r.resolved).length,
    matches: comparison.rows.filter((r) => r.status === 'match' || r.resolved).length,
  };

  const onSaveRule = (rule) => {
    setVendorRules((prev) => ({
      ...prev,
      [vendor]: [
        ...(prev[vendor] || []),
        { id: 'r' + Date.now(), added: new Date().toISOString().slice(0, 10), ...rule },
      ],
    }));
  };
  const onRemoveRule = (id) => {
    setVendorRules((prev) => ({
      ...prev,
      [vendor]: (prev[vendor] || []).filter((r) => r.id !== id),
    }));
  };

  return (
    <div className="compare-view">
      <div className="cv-hd">
        <div className="cv-hd-l">
          <button className="btn btn-sm btn-ghost" onClick={onBack}>
            <Icon name="chev" size={14} style={{ transform: 'rotate(180deg)' }}/> Back
          </button>
          <div className="cv-hd-meta">
            <div className="cv-hd-vendor">{vendor}</div>
            <div className="cv-hd-ids mono">
              {invoiceA.id} <Icon name="arrow" size={11} style={{ verticalAlign: 'middle' }} /> {invoiceB.id}
            </div>
          </div>
        </div>
        <div className="cv-hd-r">
          <button className="btn btn-sm" onClick={() => setShowRules((s) => !s)}>
            <Icon name="rule" size={13}/> {showRules ? 'Hide' : 'Show'} rules
          </button>
          <button className="btn btn-sm btn-primary" disabled={analysis === 'loading'} onClick={runAnalysis}>
            {analysis === 'loading' ? 'Analyzing…' : 'Analyze with Claude'}
          </button>
        </div>
      </div>

      <SummaryStrip summary={comparison.summary} vendor={vendor} historyCount={rules.length} />

      {analysis && analysis !== 'loading' && (
        <ClaudeAnalysisPanel text={analysis} onDismiss={() => setAnalysis(null)} />
      )}

      {showRules && (
        <VendorRulesPanel
          vendor={vendor} rules={rules}
          onAddRule={onSaveRule}
          onRemove={onRemoveRule}
        />
      )}

      <div className="cv-toolbar">
        <div className="cv-filters">
          {['all', 'flagged', 'matches'].map((f) => (
            <button key={f} className={`cv-filter ${filter === f ? 'is-on' : ''}`} onClick={() => setFilter(f)}>
              <span>{f.charAt(0).toUpperCase() + f.slice(1)}</span>
              <span className="cv-filter-count num">{counts[f]}</span>
            </button>
          ))}
        </div>
        <div className="cv-toolbar-r">
          <div className="cv-legend">
            <span><span className="lg-sw lg-sw-ok"/> match</span>
            <span><span className="lg-sw lg-sw-warn"/> drift</span>
            <span><span className="lg-sw lg-sw-bad"/> missing/added</span>
            <span><span className="lg-sw lg-sw-info"/> resolved</span>
          </div>
        </div>
      </div>

      <div className="cv-main">
        <div className="cv-grid-wrap">
          <CompareGrid
            comparison={comparison}
            invoiceA={invoiceA}
            invoiceB={invoiceB}
            filter={filter}
            selected={selectedSku}
            onSelect={setSelectedSku}
          />
        </div>
        <div className="cv-side">
          <DetailPanel row={selectedRow} onClose={() => setSelectedSku(null)} />
        </div>
      </div>

      <ActionBar
        vendor={vendor}
        comparison={comparison}
        decision={decision}
        onApprove={(note) => setDecision({ kind: 'approved', note, onUndo: () => setDecision(null) })}
        onReject={(note) => setDecision({ kind: 'rejected', note, onUndo: () => setDecision(null) })}
        onSaveRule={onSaveRule}
        onStartNew={onStartNew}
        onViewVendor={onViewVendors}
      />

      <CompareViewStyles />
    </div>
  );
}

const CompareViewStyles = () => (
  <style>{`
    .compare-view { max-width: 1480px; margin: 0 auto; padding: 24px 24px 80px; }

    /* ── header ── */
    .cv-hd { display: flex; align-items: center; justify-content: space-between; padding: 4px 0 18px; }
    .cv-hd-l { display: flex; align-items: center; gap: 16px; }
    .cv-hd-meta { display: flex; flex-direction: column; gap: 2px; }
    .cv-hd-vendor { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
    .cv-hd-ids { font-size: 11.5px; color: var(--fg-dim); }
    .cv-hd-r { display: flex; gap: 8px; }

    /* ── summary strip ── */
    .summary { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; }
    .sc {
      background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
      padding: 14px 16px 16px; box-shadow: var(--shadow-1);
      display: flex; flex-direction: column; gap: 6px;
    }
    .sc-l { font-size: 11px; color: var(--fg-dim); letter-spacing: 0.06em; text-transform: uppercase; font-weight: 500; }
    .sc-v { font-size: 28px; font-weight: 600; letter-spacing: -0.025em; font-family: "IBM Plex Mono", monospace; display: flex; align-items: baseline; gap: 4px; }
    .sc-v-ok   { color: var(--ok); }
    .sc-v-warn { color: var(--warn); }
    .sc-v-bad  { color: var(--bad); }
    .sc-v-info { color: var(--info); }
    .sc-sign { font-size: 22px; opacity: 0.7; }
    .sc-unit { font-size: 13px; color: var(--fg-dim); margin-left: 2px; font-weight: 400; }
    .sc-sub { font-size: 11.5px; color: var(--fg-dim); margin-top: -2px; }
    .sc-bar { height: 3px; background: var(--surface-2); border-radius: 999px; overflow: hidden; margin-top: 6px; }
    .sc-bar-fill { height: 100%; border-radius: 999px; transition: width .4s cubic-bezier(.3,.7,.4,1); }
    .sc-bar-ok   { background: var(--ok); }
    .sc-bar-warn { background: var(--warn); }
    .sc-bar-bad  { background: var(--bad); }
    .sc-bar-info { background: var(--info); }

    /* ── vendor rules ── */
    .vrp {
      background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg);
      padding: 14px 18px; margin-bottom: 16px; box-shadow: var(--shadow-1);
    }
    .vrp-hd { display: flex; align-items: center; justify-content: space-between; padding-bottom: 12px; border-bottom: 1px solid var(--border); margin-bottom: 10px; }
    .vrp-tag { font-size: 10px; letter-spacing: 0.12em; color: var(--fg-dim); }
    .vrp-vendor { font-size: 13.5px; font-weight: 500; margin-top: 2px; }
    .vrp-list { display: flex; flex-direction: column; gap: 0; }
    .vrp-empty { display: flex; align-items: center; gap: 8px; padding: 10px 0; color: var(--fg-dim); font-size: 13px; }
    .vrp-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px dashed var(--border); }
    .vrp-row:last-child { border-bottom: none; padding-bottom: 4px; }
    .vrp-row-l { flex: 1; min-width: 0; }
    .vrp-row-kind { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
    .vrp-kind { font-size: 10px; padding: 2px 7px; border-radius: 4px; font-family: "IBM Plex Mono", monospace; font-weight: 500; letter-spacing: 0.04em; text-transform: uppercase; }
    .vrp-kind-ignore { background: var(--bad-bg); color: var(--bad); }
    .vrp-kind-tolerance { background: var(--warn-bg); color: var(--warn); }
    .vrp-kind-note { background: var(--info-bg); color: var(--info); }
    .vrp-row-pat { font-size: 12px; color: var(--fg); background: var(--surface-2); padding: 2px 8px; border-radius: 4px; border: 1px solid var(--border); }
    .vrp-row-note { font-size: 13px; color: var(--fg-muted); line-height: 1.5; }
    .vrp-row-r { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-top: 2px; }
    .vrp-row-date { font-size: 11px; color: var(--fg-dim); }

    /* ── claude analysis panel ── */
    .cap {
      background: var(--surface); border: 1px solid oklch(from var(--accent) l c h / .45);
      border-radius: var(--r-lg); padding: 14px 18px; margin-bottom: 16px; box-shadow: var(--shadow-1);
    }
    .cap-hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
    .cap-tag { font-size: 10px; letter-spacing: 0.12em; color: var(--accent); font-weight: 600; }
    .cap-body { font-size: 13.5px; color: var(--fg-muted); line-height: 1.65; white-space: pre-wrap; }

    /* ── toolbar ── */
    .cv-toolbar { display: flex; align-items: center; justify-content: space-between; padding: 4px 2px 12px; }
    .cv-filters { display: flex; gap: 4px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: 3px; }
    .cv-filter { appearance: none; background: transparent; color: var(--fg-muted); border: 0; padding: 6px 12px; border-radius: 4px; font: inherit; font-size: 12.5px; cursor: pointer; display: flex; align-items: center; gap: 6px; }
    .cv-filter.is-on { background: var(--surface-3); color: var(--fg); }
    .cv-filter:hover:not(.is-on) { color: var(--fg); }
    .cv-filter-count { font-size: 11px; color: var(--fg-dim); background: var(--surface-2); padding: 1px 6px; border-radius: 999px; }
    .cv-filter.is-on .cv-filter-count { background: var(--bg); color: var(--fg-muted); }
    .cv-legend { display: flex; gap: 14px; font-size: 11.5px; color: var(--fg-dim); }
    .cv-legend > span { display: inline-flex; align-items: center; gap: 6px; font-family: "IBM Plex Mono", monospace; letter-spacing: 0.02em; }
    .lg-sw { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
    .lg-sw-ok   { background: var(--ok-bg);   box-shadow: inset 0 0 0 1px var(--ok); }
    .lg-sw-warn { background: var(--warn-bg); box-shadow: inset 0 0 0 1px var(--warn); }
    .lg-sw-bad  { background: var(--bad-bg);  box-shadow: inset 0 0 0 1px var(--bad); }
    .lg-sw-info { background: var(--info-bg); box-shadow: inset 0 0 0 1px var(--info); }

    /* ── main ── */
    .cv-main { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 16px; align-items: flex-start; }

    /* ── grid ── */
    .cg { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-1); }
    .cg-head, .cg-row, .cg-foot {
      display: grid;
      grid-template-columns: 110px minmax(180px,1fr) 64px 64px 92px 92px 96px 96px 92px 130px;
    }
    .cg-head { background: var(--surface-2); border-bottom: 1px solid var(--border); }
    .cg-h {
      font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase;
      color: var(--fg-dim); font-weight: 500;
      padding: 10px 12px; border-right: 1px solid var(--border);
    }
    .cg-h:last-child { border-right: 0; }
    .cg-h-num, .cg-h-qty { text-align: right; }
    .cg-h-status { text-align: left; }

    .cg-body {}
    .cg-row {
      align-items: center;
      border-bottom: 1px solid var(--border);
      height: var(--row-h);
      cursor: pointer;
      transition: background .1s;
      position: relative;
    }
    .cg-row:last-child { border-bottom: 0; }
    .cg-row:hover { background: var(--surface-2); }
    .cg-row.is-selected { background: oklch(from var(--accent) l c h / 0.10); box-shadow: inset 2px 0 0 var(--accent); }
    .cg-row.is-selected:hover { background: oklch(from var(--accent) l c h / 0.14); }

    .cg-row-resolved { background: oklch(from var(--info) l c h / 0.06); }
    .cg-row-resolved:hover { background: oklch(from var(--info) l c h / 0.12); }
    .cg-row-warn::before, .cg-row-bad::before {
      content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
    }
    .cg-row-warn::before { background: var(--warn); }
    .cg-row-bad::before { background: var(--bad); }
    .cg-row-synthetic { background: var(--surface-2); }
    .cg-row-synthetic:hover { background: var(--surface-3); }

    .cg-c { padding: 0 12px; font-size: 12.5px; color: var(--fg); border-right: 1px solid var(--border); display: flex; align-items: center; min-height: var(--row-h); }
    .cg-c:last-child { border-right: 0; }
    .cg-c-num, .cg-c-qty { justify-content: flex-end; }
    .cg-c-desc { color: var(--fg); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; gap: 8px; }
    .cg-c-syn { font-size: 10px; color: var(--fg-dim); text-transform: uppercase; letter-spacing: 0.08em; padding: 2px 6px; background: var(--surface-3); border-radius: 3px; }
    .cg-c-total { color: var(--fg-muted); }
    .cg-c-delta { font-weight: 500; }
    .cg-c-delta-pos { color: var(--warn); }
    .cg-c-delta-neg { color: var(--info); }
    .cg-c-dash { color: var(--fg-dim); }

    .is-flag {
      color: var(--warn);
      background: oklch(from var(--warn) l c h / 0.10);
      font-weight: 500;
    }
    .is-flag-strike {
      color: var(--fg-dim);
      text-decoration: line-through;
      text-decoration-color: oklch(from var(--warn) l c h / 0.5);
    }
    .cg-row-bad .is-flag, .cg-row-bad .is-flag-strike {
      background: oklch(from var(--bad) l c h / 0.10);
      color: var(--bad);
    }
    .cg-row-bad .is-flag-strike { text-decoration-color: oklch(from var(--bad) l c h / 0.6); color: var(--fg-dim); }
    .cg-row-resolved .is-flag {
      background: oklch(from var(--info) l c h / 0.10);
      color: var(--info);
    }
    .cg-row-resolved .is-flag-strike { text-decoration-color: oklch(from var(--info) l c h / 0.5); }

    .cg-empty { padding: 24px; text-align: center; color: var(--fg-dim); font-size: 13px; }

    .cg-foot { grid-template-columns: 110px minmax(180px,1fr) 64px 64px 92px 92px 96px 96px 92px 130px; background: var(--surface-2); border-top: 1px solid var(--border-strong); height: 36px; align-items: center; }
    .cg-f { padding: 0 12px; font-size: 12px; color: var(--fg-muted); }
    .cg-f-label { grid-column: 1 / span 6; font-weight: 500; color: var(--fg-dim); letter-spacing: 0.04em; text-transform: uppercase; font-size: 10.5px; }
    .cg-f-num { text-align: right; }
    .cg-f-delta { color: var(--warn); font-weight: 500; }

    .cg-grand { display: flex; justify-content: space-between; align-items: center; padding: 14px 16px; background: var(--surface); border-top: 1px solid var(--border-strong); }
    .cg-grand-label { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--fg-dim); font-weight: 500; }
    .cg-grand-vals { display: flex; align-items: center; gap: 14px; font-size: 15px; }
    .cg-grand-k { font-size: 10.5px; color: var(--fg-dim); text-transform: uppercase; letter-spacing: 0.08em; margin-right: 6px; font-family: "IBM Plex Mono", monospace; }
    .cg-grand-arrow { color: var(--fg-dim); }
    .cg-grand-delta { font-family: "IBM Plex Mono", monospace; font-weight: 600; padding: 4px 10px; border-radius: 5px; }
    .cg-grand-delta-ok { color: var(--ok); background: var(--ok-bg); }
    .cg-grand-delta-warn { color: var(--warn); background: var(--warn-bg); }

    /* ── detail panel ── */
    .detail { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 16px 18px; box-shadow: var(--shadow-1); position: sticky; top: 76px; }
    .detail-empty { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 36px 22px; gap: 8px; }
    .detail-empty-icon { width: 44px; height: 44px; border-radius: 50%; background: var(--surface-2); display: grid; place-items: center; color: var(--fg-dim); margin-bottom: 4px; }
    .detail-empty-h { font-size: 13.5px; font-weight: 500; }
    .detail-empty-sub { font-size: 12px; color: var(--fg-dim); line-height: 1.5; }
    .detail-hd { display: flex; justify-content: space-between; align-items: flex-start; }
    .detail-tag { font-size: 10px; letter-spacing: 0.12em; color: var(--fg-dim); }
    .detail-sku { font-size: 16px; font-weight: 600; margin-top: 2px; color: var(--fg); }
    .detail-desc { font-size: 12.5px; color: var(--fg-muted); margin: 4px 0 12px; line-height: 1.5; }
    .detail-status { padding: 10px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
    .detail-resolved-note { font-size: 11px; color: var(--fg-dim); }
    .detail-grid { display: grid; grid-template-columns: 1fr 20px 1fr; gap: 8px; margin: 14px 0; }
    .detail-col { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r); padding: 10px 12px; }
    .detail-col-h { font-size: 10.5px; color: var(--fg-dim); letter-spacing: 0.08em; text-transform: uppercase; margin-bottom: 8px; font-weight: 500; }
    .detail-arrow { display: grid; place-items: center; color: var(--fg-dim); }
    .detail-kv { display: flex; justify-content: space-between; padding: 4px 0; font-size: 12px; }
    .detail-kv > span:first-child { color: var(--fg-dim); }
    .detail-kv > span:last-child { color: var(--fg); font-weight: 500; }
    .detail-kv.is-diff > span:last-child { color: var(--warn); background: oklch(from var(--warn) l c h / 0.14); padding: 1px 6px; border-radius: 4px; }
    .detail-kv-total { padding-top: 8px; margin-top: 4px; border-top: 1px dashed var(--border); }
    .detail-flags ul { margin: 6px 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 4px; }
    .detail-flags li { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--fg-muted); }
    .detail-flags li svg { color: var(--warn); }
    .detail-flags .label { margin-bottom: 4px; }
    .detail-delta { display: flex; justify-content: space-between; align-items: center; padding-top: 12px; margin-top: 12px; border-top: 1px solid var(--border); }
    .detail-delta-v { font-size: 17px; font-weight: 600; }
    .detail-delta-v.pos { color: var(--warn); }
    .detail-delta-v.neg { color: var(--info); }

    /* ── action bar ── */
    .actionbar { background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--r-lg); margin-top: 18px; box-shadow: var(--shadow-2); }
    .ab-inner { display: grid; grid-template-columns: 1.4fr 1fr; gap: 24px; padding: 18px 20px; }
    .ab-left .label, .ab-right .label { margin-bottom: 6px; }
    .ab-textarea { width: 100%; min-height: 78px; font-size: 13px; line-height: 1.55; }
    .ab-rule-builder { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 12px; color: var(--fg-dim); flex-wrap: wrap; }
    .ab-rb-pre { color: var(--fg-dim); font-size: 12px; }
    .ab-rb-select { height: 30px; font-size: 12px; padding: 0 28px 0 10px; width: auto; min-width: 130px; background-color: var(--surface-2); }
    .ab-right { display: flex; flex-direction: column; }
    .ab-decision-buttons { display: flex; flex-direction: column; gap: 8px; }
    .ab-decision-buttons .btn { justify-content: center; }
    .ab-help { font-size: 11.5px; color: var(--fg-dim); margin-top: 10px; }

    .actionbar-approved { border-color: oklch(from var(--ok) l calc(c*.5) h / .55); background: oklch(from var(--ok-bg) calc(l + 0.02) c h); }
    .actionbar-rejected { border-color: oklch(from var(--bad) l calc(c*.5) h / .55); background: oklch(from var(--bad-bg) calc(l + 0.02) c h); }
    .ab-decision { display: flex; align-items: center; gap: 14px; padding: 16px 20px; }
    .ab-decision-icon { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; }
    .ab-decision-icon-approved { background: oklch(from var(--ok) l c h / .25); color: var(--ok); }
    .ab-decision-icon-rejected { background: oklch(from var(--bad) l c h / .25); color: var(--bad); }
    .ab-decision-h { font-size: 14px; font-weight: 600; }
    .ab-decision-sub { font-size: 12.5px; color: var(--fg-muted); margin-top: 2px; }
    .actionbar-approved .ab-decision-sub em, .actionbar-rejected .ab-decision-sub em { font-style: italic; color: var(--fg); }
    .actionbar > .ab-decision { display: none; }
    .actionbar-approved, .actionbar-rejected { display: flex; align-items: center; justify-content: space-between; }
    .actionbar-approved > .ab-inner, .actionbar-rejected > .ab-inner { display: none; }
    .actionbar-approved > .ab-decision, .actionbar-rejected > .ab-decision { display: flex; }
    .ab-decision-actions { padding-right: 18px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }

    @media (max-width: 1180px) {
      .cv-main { grid-template-columns: 1fr; }
      .summary { grid-template-columns: repeat(2, 1fr); }
      .ab-inner { grid-template-columns: 1fr; }
    }
    @media (max-width: 900px) {
      .cg-head, .cg-row, .cg-foot { grid-template-columns: 100px minmax(140px,1fr) 50px 50px 80px 80px 80px 80px 80px 110px; font-size: 11px; }
    }
  `}</style>
);

Object.assign(window, { CompareView });
