/* =====================================================================
   AI-COS — Universal record detail drawer + registry
   window.openDetail(type, data) opens a rich detail page for any list row.
   ===================================================================== */
let _detailListener = null;
function openDetail(type, data) { if (window._openDetail) window._openDetail(type, data); else if (_detailListener) _detailListener(type, data); }

/* ---- small building blocks ---- */
function KV({ items }) {
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px 20px' }}>
      {items.map(([k, v, mono], i) => (
        <div key={i}><div className="eyebrow" style={{ fontSize: 9 }}>{k}</div><div style={{ fontSize: 12.5, fontWeight: 650, marginTop: 2 }} className={mono ? 'mono' : ''}>{v}</div></div>
      ))}
    </div>
  );
}
function Timeline({ steps, current }) {
  return (
    <div style={{ position: 'relative' }}>
      {steps.map((s, i) => {
        const done = i < current, now = i === current;
        return (
          <div key={i} className="row" style={{ gap: 12, alignItems: 'flex-start', paddingBottom: i < steps.length - 1 ? 14 : 0, position: 'relative' }}>
            {i < steps.length - 1 && <span style={{ position: 'absolute', left: 12, top: 26, bottom: 0, width: 2, background: done ? 'var(--ok)' : 'var(--border-2)' }} />}
            <span style={{ width: 26, height: 26, borderRadius: '50%', flex: 'none', zIndex: 1, display: 'grid', placeItems: 'center', background: done ? 'var(--ok)' : now ? 'var(--primary-600)' : '#eef1f6', color: done || now ? '#fff' : 'var(--text-3)' }}>
              {done ? <Icon name="check" size={13} /> : <span style={{ fontSize: 10, fontWeight: 700 }}>{i + 1}</span>}
            </span>
            <div style={{ paddingTop: 3 }}><div style={{ fontSize: 12.5, fontWeight: now ? 700 : 600, color: now ? 'var(--ink)' : done ? 'var(--text)' : 'var(--text-3)' }}>{s}</div>{now && <div className="faint" style={{ fontSize: 11 }}>Current stage</div>}</div>
          </div>
        );
      })}
    </div>
  );
}
function Card({ title, icon, children }) {
  return (
    <div className="card">
      {title && <div className="card-head"><Icon name={icon || 'grid'} size={15} style={{ color: 'var(--primary-600)' }} /><div className="h-sec" style={{ fontSize: 13.5 }}>{title}</div></div>}
      <div className="card-body">{children}</div>
    </div>
  );
}

/* ---- customer communications / notes log (CRM-07) ---- */
function custComms(c, DB) {
  const T = DB.TODAY, day = 864e5;
  return [
    { d: DB.rel(new Date(T - 2 * day)), type: 'Call', who: 'Savad Ahammed', text: `Discussed the upcoming AMC renewal and 6-monthly calibration plan with ${c.contact}.` },
    { d: DB.rel(new Date(T - 6 * day)), type: 'Meeting', who: 'Lina Haddad', text: `Site visit — reviewed ${c.assets} monitors and gas-detection coverage; no concerns raised.` },
    { d: DB.rel(new Date(T - 14 * day)), type: 'Email', who: 'System', text: `Prequalification expiry reminder sent — renew before ${DB.fmt(c.prequalExp)}.` },
    { d: DB.rel(new Date(T - 23 * day)), type: 'Commitment', who: 'Savad Ahammed', text: 'Agreed a 2-day turnaround for emergency bump tests under the contract.' },
  ];
}
const COMM_TONE = { Call: 'info', Meeting: 'ai', Email: 'neutral', Commitment: 'warn' };

/* ---- per-type renderers ---- */
const DETAIL = {
  cylinder(c, DB) {
    const pct = Math.round((c.pressure / c.p0) * 100);
    return {
      icon: 'cylinder', color: 'var(--primary-600)', title: c.id, sub: `${c.mix} · ${c.conc}`, status: c.status,
      fields: [['Gas mixture', c.mix], ['Certified concentration', c.conc, 1], ['Lot / batch', c.lot, 1], ['Supplier', c.supplier], ['Fill date', DB.fmt(c.fill)], ['Expiry date', DB.fmt(c.exp)]],
      blocks: [
        { h: 'Pressure & content', icon: 'gauge', node: (
          <div><div className="row" style={{ justifyContent: 'space-between', marginBottom: 6 }}><span className="faint" style={{ fontSize: 12 }}>Current pressure</span><b className="mono">{c.pressure} / {c.p0} psi</b></div><Bar pct={pct} color={pct < 25 ? 'var(--bad)' : pct < 50 ? 'var(--warn)' : 'var(--ok)'} /><div className="faint" style={{ fontSize: 11, marginTop: 6 }}>{pct}% remaining · {c.status === 'Low pressure' ? 'reorder suggested' : c.status === 'Expired' ? 'hard-blocked from worksheets' : 'available for compatible monitors'}</div></div>
        ) },
        { h: 'Usage log', icon: 'history', list: [['Today 09:42', 'WS-26-3187 · H₂S span', '−40 psi'], ['Yesterday', 'WS-26-3180 · span', '−35 psi'], ['04 Jun', 'WS-26-3171 · span', '−38 psi']] },
      ],
      note: c.status === 'Expired' ? 'Expired calibration gas invalidates results — this cylinder is hard-blocked from every worksheet (CYL-03).' : null,
    };
  },
  labasset(a, DB) {
    return {
      icon: 'gauge', color: 'var(--primary-600)', title: a.id, sub: a.name, status: a.status,
      fields: [['Category', a.category], ['Serial', a.serial, 1], ['Location', a.location], ['Criticality', a.criticality], ['Last calibration', DB.fmt(a.last)], ['Next due', `${DB.fmt(a.due)} · ${a.dueRel}`]],
      blocks: [{ h: 'Calibration & PM history', icon: 'history', list: [[DB.fmt(a.last), 'Calibrated · in-cal certificate', 'Pass'], ['Quarterly', 'PM service completed', 'OK'], ['—', `Frequency: every ${a.freq} months`, '']] }],
      note: a.status === 'Overdue' ? 'Overdue reference standards are blocked from worksheet selection until re-calibrated (CYL-05).' : null,
    };
  },
  asset(m, DB) {
    const c = DB.custById(m.customer);
    const certs = DB.certificates.filter((x) => x.monitor === m.id);
    return {
      icon: 'cpu', color: 'var(--primary-600)', title: m.id, sub: `${m.model} · S/N ${m.serial}`, status: m.status,
      fields: [['Model', m.model], ['Serial', m.serial, 1], ['Customer', c.name], ['Sensors', m.sensors.join(' · ')], ['Last calibration', DB.fmt(m.last)], ['Next due', `${DB.fmt(m.due)} · ${m.dueRel}`]],
      blocks: [
        { h: 'Sensor configuration', icon: 'cpu', node: <div className="wrap" style={{ gap: 6 }}>{m.sensors.map((s) => <span key={s} className="tag">{s} sensor</span>)}</div> },
        { h: 'Certificates', icon: 'certificate', list: certs.length ? certs.map((x) => [x.id, x.method, x.status]) : [['—', 'No certificates on record yet', '']] },
      ],
    };
  },
  customer(c, DB) {
    const mons = DB.monitors.filter((m) => m.customer === c.id);
    const certs = DB.certificates.filter((x) => x.customer === c.id);
    const ctr = DB.contracts.find((x) => x.customer === c.id);
    return {
      icon: 'building', color: c.color, title: c.name, sub: `${c.sector} · ${c.site}`, status: c.prequal === 'Approved' ? 'Approved' : c.prequal,
      fields: [['Account tier', c.tier], ['Primary contact', c.contact], ['Site', c.site], ['Assets under mgmt', `${c.assets}`], ['Prequalification', c.prequal], ['Prequal expiry', DB.fmt(c.prequalExp)]],
      blocks: [
        ctr ? { h: 'Active contract', icon: 'briefcase', list: [[ctr.id, `${ctr.assets} assets · ${ctr.freq}`, `${ctr.value.toLocaleString()} OMR`]] } : null,
        { h: 'Communications & notes', icon: 'history', node: (
          <div>
            {custComms(c, DB).map((m, i) => (
              <div key={i} className="row" style={{ gap: 11, padding: '9px 0', alignItems: 'flex-start', borderBottom: i < 3 ? '1px solid var(--border)' : 'none' }}>
                <Badge kind={COMM_TONE[m.type] || 'neutral'} style={{ flex: 'none', width: 78, justifyContent: 'center' }}>{m.type}</Badge>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 12.5, lineHeight: 1.45 }}>{m.text}</div>
                  <div className="faint" style={{ fontSize: 11, marginTop: 2 }}>{m.who} · {m.d}</div>
                </div>
              </div>
            ))}
          </div>
        ) },
        { h: 'Recent certificates', icon: 'certificate', list: certs.slice(0, 4).map((x) => [x.id, x.model, x.status]) },
      ].filter(Boolean),
    };
  },
  contract(ct, DB) {
    const c = DB.custById(ct.customer);
    return {
      icon: 'briefcase', color: c.color, title: ct.id, sub: `${c.name} · ${ct.period}`, status: ct.status,
      preview: <ContractPreview ct={ct} />,
      fields: [['Customer', c.name], ['Covered assets', `${ct.assets}`], ['Frequency', ct.freq], ['Annual value', `${ct.value.toLocaleString()} OMR`], ['Period', ct.period], ['Renewal', `${DB.fmt(ct.renew)} · ${DB.rel(ct.renew)}`]],
      note: 'Covered equipment is auto-planned across the contract period — no manual scheduling (CRM-05).',
    };
  },
  capa(x, DB) {
    const stages = ['Containment', 'Root cause', 'Action', 'Verification', 'Closed'];
    const cur = Math.max(0, stages.indexOf(x.stage));
    return {
      icon: 'check-shield', color: x.severity === 'Major' ? 'var(--bad)' : 'var(--warn)', title: x.id, sub: x.title, status: x.status,
      fields: [['Source', x.source], ['Severity', x.severity], ['Owner', DB.staffById(x.owner).name], ['Due date', `${DB.fmt(x.due)} · ${DB.rel(x.due)}`]],
      blocks: [{ h: 'CAPA workflow', icon: 'refresh', node: <Timeline steps={stages} current={x.status === 'Closed' ? 5 : cur} /> }],
      note: 'AI proposes root-cause candidates from recurring-issue detection — confirmed or replaced by the Quality Manager (AIX-03).',
    };
  },
  inventory(it, DB) {
    return {
      icon: 'box', color: 'var(--primary-600)', title: it.id, sub: it.name, status: it.status,
      fields: [['Category', it.cat], ['On hand', `${it.qty} ${it.uom}`], ['Minimum level', `${it.min} ${it.uom}`], ['Preferred vendor', it.vendor], ['Batch / lot', it.batch, 1], ['Lot traceable', 'Yes — recall-ready']],
      blocks: [{ h: 'Recent movements', icon: 'history', list: [['Today', 'Issued to JOB-26-0411', '−1'], ['03 Jun', 'GRN received', '+12'], ['28 May', 'Issued to repair', '−2']] }],
      note: it.status === 'Low' ? 'Below minimum stock — AI suggests a reorder; sensor-failure prediction may raise demand next cycle (AIX-07).' : null,
    };
  },
  invoice(iv, DB) {
    const c = DB.custById(iv.customer);
    const net = iv.amount / (1 + iv.vat / 100);
    return {
      icon: 'receipt', color: 'var(--primary-600)', title: iv.id, sub: `${c.name}`, status: iv.status,
      preview: <InvoicePreview iv={iv} />,
      fields: [['Customer', c.name], ['Issue date', DB.fmt(iv.date)], ['Due date', DB.fmt(iv.due)], ['Payment status', iv.status]],
      blocks: [{ h: 'Amounts (OMR)', icon: 'receipt', node: (
        <div>{[['Net', net.toFixed(3)], [`VAT (${iv.vat}%)`, (iv.amount - net).toFixed(3)], ['Total', iv.amount.toFixed(3)]].map(([k, v], i) => (
          <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', borderTop: i === 2 ? '1px solid var(--border)' : 'none', marginTop: i === 2 ? 4 : 0 }}><span className={i === 2 ? 'cell-strong' : 'faint'} style={{ fontSize: 12.5 }}>{k}</span><b className="mono" style={{ fontSize: i === 2 ? 14 : 12.5 }}>{v}</b></div>
        ))}</div>
      ) }],
      note: 'Issued invoices are immutable — corrections are made via credit note. Numbering is gap-free per series (NFR-17).',
    };
  },
  document(d, DB) {
    return {
      icon: 'documents', color: 'var(--primary-600)', title: d.code, sub: d.title, status: d.status,
      fields: [['Type', d.type], ['Level', d.level], ['Version', d.ver], ['Owner', DB.staffById(d.owner).name], ['Next review', `${DB.fmt(d.reviewDate)} · ${d.reviewRel}`], ['Read-acknowledgment', `${d.ack}%`]],
      blocks: [
        { h: 'Approval workflow', icon: 'refresh', node: <Timeline steps={['Draft', 'Review', 'Approve', 'Publish']} current={d.status === 'Published' ? 4 : d.status === 'In review' ? 1 : 0} /> },
        { h: 'Revision history', icon: 'history', list: [[d.ver, 'Current — published', 'Active'], ['v' + (parseInt(d.ver.replace(/\D/g, '')) || 1 - 1 || ''), 'Superseded — watermarked', 'Obsolete']] },
      ],
    };
  },
  dcr(d, DB) {
    return { icon: 'refresh', color: 'var(--primary-600)', title: d.id, sub: `Change to ${d.doc}`, status: d.status,
      fields: [['Target document', d.doc, 1], ['Requested by', DB.staffById(d.by).name], ['Date', DB.fmt(d.date)], ['Status', d.status]],
      blocks: [{ h: 'Requested change', icon: 'documents', node: <div className="muted" style={{ fontSize: 13 }}>{d.desc}</div> }] };
  },
  method(m, DB) {
    return {
      icon: 'flask', color: 'var(--ai)', title: m.id, sub: `${m.title} · ${m.rev}`, status: m.status,
      fields: [['Title', m.title], ['Revision', m.rev], ['Owner', DB.staffById(m.owner).name], ['Points', m.points], ['Validated', m.validated ? 'Yes' : 'Pending'], ['MU budget', m.mu ? 'Linked' : 'Not linked']],
      blocks: [{ h: 'Method lifecycle', icon: 'refresh', node: <Timeline steps={['Draft', 'Validated', 'Active', 'Obsolete']} current={m.status === 'Active' ? 2 : m.status === 'In validation' ? 0 : 0} /> }],
      note: 'Each worksheet binds to a specific method revision; in-flight jobs finish on their bound revision (LAB-01).',
    };
  },
  pt(p, DB) {
    return { icon: 'trend', color: 'var(--primary-600)', title: p.id, sub: `${p.provider} · ${p.scheme}`, status: p.result,
      fields: [['Provider', p.provider], ['Scheme', p.scheme], ['Parameter', p.param, 1], ['Date', DB.fmt(p.date)], ['z-score', p.z.toFixed(1)], ['Evaluation', p.result]],
      note: p.capa ? `Questionable result — ${p.capa} opened automatically to investigate bias (LAB-04).` : 'Satisfactory — evidence of result validity maintained.' };
  },
  hse(x, DB) {
    return { icon: 'helmet', color: x.type === 'Incident' ? 'var(--bad)' : 'var(--warn)', title: x.id, sub: x.title, status: x.status,
      fields: [['Type', x.type], ['Severity', x.severity], ['Date', DB.fmt(x.date)], ['Linked CAPA', x.capa || '—', 1]],
      blocks: [{ h: 'Investigation', icon: 'refresh', node: <Timeline steps={['Reported', 'Investigation', 'Root cause', 'Closed']} current={x.status === 'Closed' ? 4 : 1} /> }],
      note: 'HSE findings open NCRs in the same shared register as quality — one improvement loop for the whole system.' };
  },
  risk(r, DB) {
    return { icon: 'shield', color: 'var(--primary-600)', title: r.id, sub: r.area, status: r.status,
      fields: [['Area / task', r.area], ['Next review', `${DB.fmt(r.review)} · ${DB.rel(r.review)}`]],
      blocks: [{ h: 'Controls', icon: 'check-shield', node: <div className="muted" style={{ fontSize: 13 }}>{r.controls}</div> }] };
  },
  pm(p, DB) {
    return { icon: 'wrench', color: p.crit === 'Critical' ? 'var(--bad)' : 'var(--primary-600)', title: p.id, sub: p.equip, status: p.status,
      fields: [['Equipment', p.equip], ['Task', p.task], ['Criticality', p.crit], ['Assignee', DB.staffById(p.assignee).name], ['Due', `${DB.fmt(p.due)} · ${DB.rel(p.due)}`]],
      note: p.status === 'Overdue' ? 'Overdue critical PM blocks this equipment from worksheet selection until serviced (PM-04).' : null };
  },
  role(r, DB) {
    const people = DB.staff.filter((s) => s.role.includes(r.role.split(' ')[0]) || r.role.includes(s.role.split(' ')[0]));
    return { icon: 'users', color: r.color, title: r.role, sub: `${r.count} user${r.count > 1 ? 's' : ''}`, status: 'Active',
      fields: [['Permissions', r.perms], ['Users assigned', `${r.count}`]],
      blocks: [{ h: 'Members', icon: 'users', node: people.length ? <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>{people.map((s) => <div key={s.id} className="row" style={{ gap: 9 }}><Avatar id={s.id} size="sm" /><span style={{ fontSize: 12.5, fontWeight: 600 }}>{s.name}</span></div>)}</div> : <div className="faint" style={{ fontSize: 12.5 }}>Assigned across the organization</div> }],
      note: 'Segregation of duties is enforced — e.g. a technician can never approve their own work (ISO 17025 §7.7).' };
  },
  fieldjob(f, DB) {
    const c = DB.custById(f.customer);
    return { icon: 'truck', color: c.color, title: f.id, sub: f.site, status: f.status,
      fields: [['Customer', c.name], ['Site', f.site], ['Technician', DB.staffById(f.tech).name], ['GPS stamp', f.gps, 1], ['Items', `${f.items}`], ['Synced', `${f.synced} / ${f.items}`]],
      blocks: [{ h: 'Offline job pack', icon: 'download', node: <div><div className="row" style={{ justifyContent: 'space-between', marginBottom: 6 }}><span className="faint" style={{ fontSize: 12 }}>Sync progress</span><b className="mono">{Math.round((f.synced / f.items) * 100)}%</b></div><Bar pct={(f.synced / f.items) * 100} color="var(--ok)" /><div className="faint" style={{ fontSize: 11, marginTop: 6 }}>{f.offline ? 'Encrypted local store · single-owner pack' : 'Fully synced'}</div></div> }],
      note: 'Same authorization, standards-validity and environment gates apply on the tablet; idempotent sync with conflict detection (NFR-13).' };
  },
  ptw(p, DB) {
    return { icon: 'flag', color: 'var(--primary-600)', title: p.id, sub: p.job, status: p.status,
      fields: [['Work / location', p.job], ['Permit type', p.type], ['Validity', p.validity], ['Status', p.status]],
      note: 'Permit-to-work is linked to field jobs with validity windows (HSE-04).' };
  },
  sds(s, DB) {
    return { icon: 'flask', color: 'var(--warn)', title: s.id, sub: s.chemical, status: s.review <= DB.TODAY ? 'Due soon' : 'Active',
      fields: [['Chemical', s.chemical], ['Supplier', s.supplier], ['Next review', `${DB.fmt(s.review)} · ${DB.rel(s.review)}`]],
      note: 'Calibration gases are tracked in the SDS register with review dates (HSE-05).' };
  },
  person(c, DB) {
    const s = DB.staffById(c.staff);
    const gl = { S: 'Sign', R: 'Review', E: 'Execute', '-': '—' };
    return { icon: 'users', color: s.color, title: s.name, sub: s.role, status: 'Authorized',
      fields: [['Role', s.role], ['OEM certifications', c.oem], ['Authorization expiry', `${DB.fmt(c.exp)} · ${DB.rel(c.exp)}`]],
      blocks: [{ h: 'Method grants', icon: 'check-shield', node: <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>{Object.entries(c.grants).map(([m, g]) => <div key={m} className="row" style={{ justifyContent: 'space-between' }}><span className="mono" style={{ fontSize: 12 }}>{m}</span><Badge kind={g === 'S' ? 'ok' : g === 'R' ? 'info' : g === 'E' ? 'warn' : 'neutral'}>{gl[g]}</Badge></div>)}</div> }],
      note: 'Authorization to execute, review and sign are separate grants; expiry automatically removes the grant (CTY-01/02).' };
  },
  cert(ct, DB) {
    const c = DB.custById(ct.customer);
    return { icon: 'certificate', color: ct.bump ? 'var(--warn)' : 'var(--primary-600)', title: ct.id, sub: `${ct.model} · ${c.name}`, status: ct.status,
      preview: <CertPreview ct={ct} />,
      fields: [['Equipment', ct.model], ['Asset ID', ct.monitor, 1], ['Customer', c.name], ['Method', ct.method], ['Uncertainty', ct.mu], ['Issued', DB.fmt(ct.issued)]],
      blocks: [{ h: 'Issuance lifecycle', icon: 'history', list: [['Composed', 'auto from worksheet', 'OK'], ['Hashed', 'tamper-evident', 'OK'], ['Published', 'portal + email', 'OK']] }],
      note: ct.status === 'Superseded' ? 'Superseded by a later issue; original immutable. QR verification returns Superseded and offers the current version.' : 'One approval composed, numbered, rendered, hashed, archived & published this certificate (CTX-04).' };
  },
  quotation(qt, DB) {
    const c = DB.custById(qt.customer);
    return { icon: 'receipt', color: 'var(--warn)', title: qt.id, sub: qt.title, status: qt.status,
      preview: <QuotationPreview qt={qt} />,
      fields: [['Customer', c.name], ['Items', `${qt.items}`], ['Value', `${qt.value.toLocaleString()} OMR`], ['Valid until', `${DB.fmt(qt.validity)} · ${DB.rel(qt.validity)}`], ['Status', qt.status], ['Created', DB.fmt(qt.date)]],
      note: 'On acceptance, converts to a one-off job or AMC contract; covered equipment is auto-scheduled (CRM-03/05).' };
  },
  audit(a, DB) {
    return { icon: 'history', color: 'var(--primary-600)', title: a.entity, sub: a.action, status: 'Logged',
      fields: [['Timestamp', a.ts], ['User', a.user === 'system' ? 'System (automated)' : DB.staffById(a.user)?.name], ['Action', a.action], ['Entity', a.entity, 1]],
      note: 'The audit trail is immutable — every create, change, approval and AI confirmation is recorded for assessment (ADM).' };
  },
};

function RecordPage({ type, data, onBack, onNav }) {
  const DB = window.DB;
  const r = (DETAIL[type] || DETAIL.labasset)(data, DB);
  const hasPreview = !!r.preview;
  const flows = {
    quotation: [['Accept & convert to job', 'check', 'primary', () => window.toast('Quotation accepted → JOB-26-0413 created → draft invoice queued')], ['Revise & resend', 'refresh', 'ghost', () => window.toast('Revision drafted under version control', 'info')]],
    contract: [['Generate AMC invoice', 'receipt', 'primary', () => window.toast('Draft invoice generated from AMC schedule')], ['View covered assets', 'cpu', 'ghost', () => { onBack(); window._navTo && window._navTo('assets'); }]],
    cert: [['Verify (public QR)', 'qr', 'primary', () => window.toast('Public verification: Valid', 'ok')], ['Reissue / supersede', 'history', 'ghost', () => window.toast('Supersession started — new number, original immutable', 'info')]],
    invoice: [['Record payment', 'check', 'primary', () => window.toast('Payment recorded · invoice marked Paid')], ['Send to customer', 'ext', 'ghost', () => window.toast('Invoice emailed to customer', 'info')]],
    capa: [['Advance stage', 'arrowR', 'primary', () => window.toast('CAPA advanced to next stage', 'info')], ['Verify & close', 'check', 'ghost', () => window.toast('Effectiveness verified · CAPA closed')]],
    customer: [['Log interaction', 'plus', 'primary', () => window.toast('Interaction logged to the account timeline (CRM-07)', 'info')], ['New quotation', 'receipt', 'ghost', () => window.toast('Quotation drafted for ' + (data.name || 'customer'), 'info')]],
  }[type];
  const sideCard = (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      {flows && (
        <div className="card card-pad">
          <div className="eyebrow" style={{ marginBottom: 10 }}>Actions</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {flows.map(([label, icon, variant, fn], i) => <Btn key={i} variant={variant} icon={icon} onClick={fn}>{label}</Btn>)}
          </div>
        </div>
      )}
      <Card title="Details" icon={r.icon}><KV items={r.fields} /></Card>
      {(r.blocks || []).map((b, i) => (
        <Card key={i} title={b.h} icon={b.icon}>
          {b.node ? b.node : (
            <div>{b.list.map((row, j) => (
              <div key={j} className="lrow" style={{ padding: '9px 0' }}>
                <span className="mono cell-strong" style={{ fontSize: 11.5, width: 104, flex: 'none' }}>{row[0]}</span>
                <span style={{ flex: 1, fontSize: 12.5 }}>{row[1]}</span>
                {row[2] && <Badge kind={/pass|ok|active|valid/i.test(row[2]) ? 'ok' : /obsolete|superseded/i.test(row[2]) ? 'neutral' : 'info'}>{row[2]}</Badge>}
              </div>
            ))}</div>
          )}
        </Card>
      ))}
      {r.note && <AINote title="Standards & AI context">{r.note}</AINote>}
    </div>
  );
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 10, marginBottom: 16, flexWrap: 'wrap' }}>
        <button className="icon-btn" onClick={onBack}><Icon name="chevL" size={17} /></button>
        <span className="kpi-ico" style={{ width: 36, height: 36, background: 'var(--bg)', color: r.color }}><Icon name={r.icon} size={18} /></span>
        <div style={{ minWidth: 0 }}>
          <div className="row" style={{ gap: 9, flexWrap: 'wrap' }}><span className="h-page" style={{ fontSize: 20, whiteSpace: 'nowrap' }}>{r.title}</span>{r.status && <StatusBadge status={r.status} />}</div>
          <div className="h-sub">{r.sub}</div>
        </div>
        <span className="spacer" />
        <Btn icon="history" size="sm" onClick={() => window.toast('Full history opened', 'info')}>History</Btn>
        <Btn icon="download" size="sm" onClick={() => window.toast(`${r.title} exported (PDF)`)}>{hasPreview ? 'Download PDF' : 'Export'}</Btn>
        <Btn variant="primary" icon="ext" size="sm" onClick={() => window.toast('Edit form opened', 'info')}>Edit</Btn>
      </div>
      {hasPreview ? (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 360px', gap: 20, alignItems: 'start' }}>
          <div>{r.preview}</div>
          {sideCard}
        </div>
      ) : (
        <div style={{ maxWidth: 760 }}>{sideCard}</div>
      )}
    </div>
  );
}

Object.assign(window, { openDetail, RecordPage });
