/* =====================================================================
   AI-COS QHSE — modules, detail views, router, login
   ===================================================================== */
const sevKind = (s) => ({ High: 'bad', Major: 'bad', Medium: 'warn', Minor: 'warn', Low: 'neutral' }[s] || 'neutral');

/* ---- live AI compute functions for the AI-assisted action modal ---- */
const PERMIT_CONTROLS = {
  'Confined Space Entry': ['Gas test (O₂, LEL, H₂S, toxics)', 'Rescue plan + standby person', 'Continuous atmosphere monitoring', 'Communication & retrieval'],
  'Hot Work': ['Fire watch + extinguisher', 'Gas test before & during', 'Combustibles removed / shielded', 'Hot-work area barricaded'],
  'Nitrogen Purging': ['O₂-deficiency controls', 'Exclusion zone & signage', 'Venting to safe location', 'Confined-space interface check'],
  'Hydrotest': ['Exclusion zone behind pressure', 'Pressure relief / calibrated gauge', 'No personnel during pressurization', 'Test-pump certification'],
  'Excavation': ['Underground-services scan', 'Shoring / battering', 'Edge protection', 'Access/egress'],
  'LOTO': ['Energy isolation verified', 'Locks & tags applied', 'Zero-energy test', 'Stored-energy released'],
  'Cold Work': ['Task risk assessment', 'PPE matrix', 'Isolation where needed'],
  'Energized Systems': ['Qualified person', 'Arc-flash PPE', 'Approach boundaries', 'Live-work justification'],
};
const PERMIT_RISK = { 'Confined Space Entry': 78, 'Hot Work': 70, 'Nitrogen Purging': 74, 'Hydrotest': 58, 'Excavation': 52, 'Energized Systems': 66, 'LOTO': 34, 'Cold Work': 28 };
function permitCompute(v) {
  const tips = []; const type = v.type; const area = (v.area || '').toLowerCase();
  const active = DB.ptw.filter((p) => p.status === 'Active');
  const conflict = active.find((p) => area && (area.includes('204') || area.includes('v-204')) && (type === 'Confined Space Entry' || type === 'Nitrogen Purging' || type === 'Hot Work'));
  if (conflict) tips.push({ tone: 'bad', title: 'SIMOPS conflict detected', body: `${conflict.id} (${conflict.type}) is active in the same area/window. Do not approve in parallel — sequence or separate spatially first.` });
  if (PERMIT_CONTROLS[type]) tips.push({ tone: 'warn', title: 'Required controls for this permit', body: PERMIT_CONTROLS[type].join(' · ') });
  if (type === 'Confined Space Entry' || type === 'Nitrogen Purging') tips.push({ tone: 'info', title: 'Asphyxiation risk', body: 'AI recommends a rescue plan, standby person and continuous O₂ monitoring before approval.' });
  if (!conflict && type) tips.push({ tone: 'ok', title: 'No SIMOPS conflict in this area', body: 'AI scanned active permits — no overlap found. Verify controls above and submit for approval.' });
  return { tips, risk: PERMIT_RISK[type] || 40 };
}
/* Live guidance for the comprehensive PTW form (keys: ptype, loc/area, risk, controls, hazards) */
function ptwCompute(v) {
  const tips = []; const type = v.ptype || v.type; const loc = ((v.loc || '') + ' ' + (v.area || '')).toLowerCase();
  const sel = v.controls || []; const active = DB.ptw.filter((p) => (p.status === 'Active' || p.status === 'Awaiting approval') && p.id !== v.permitNo);
  let risk = { 'Hot Work': 70, 'Confined Space': 82, 'Working at Height': 66, 'Electrical': 62, 'Excavation': 55, 'Lifting': 52, 'Cold Work': 28 }[type] || 45;
  if (v.risk === 'High') risk = Math.max(risk, 76); else if (v.risk === 'Low') risk = Math.min(risk, 32);
  const clash = active.find((p) => { const pl = (p.loc || '').toLowerCase(); return pl && loc && (loc.includes(pl.slice(0, 8)) || pl.includes((v.loc || '').toLowerCase().slice(0, 8))); });
  if (clash) tips.push({ tone: 'bad', title: 'SIMOPS conflict detected', body: clash.id + ' (' + clash.type + ') is active in ' + clash.loc + '. Sequence the work or separate spatially before approval.' });
  else if (type && (v.loc || v.area)) tips.push({ tone: 'ok', title: 'No SIMOPS conflict in this area', body: 'Sentinel scanned ' + active.length + ' active/pending permits — no overlapping operation in this location.' });
  const req = { 'Hot Work': ['Gas test', 'Fire watch', 'PPE'], 'Confined Space': ['Gas test', 'Rescue standby', 'Isolation / LOTO'], 'Working at Height': ['Tool tethering', 'PPE', 'Barricading'], 'Electrical': ['Isolation / LOTO', 'PPE'], 'Excavation': ['Barricading', 'Gas test'] }[type] || [];
  const missing = req.filter((c) => !sel.includes(c));
  if (missing.length) tips.push({ tone: 'warn', title: 'Add the required controls', body: 'For ' + type + ', AI expects: ' + missing.join(' · ') + '.' });
  else if (req.length) tips.push({ tone: 'ok', title: 'Controls look complete', body: 'All typical controls for ' + type + ' are selected.' });
  if (type === 'Confined Space') tips.push({ tone: 'info', title: 'Asphyxiation risk', body: 'Rescue plan, standby attendant and continuous O₂ monitoring are required before entry.' });
  if (type === 'Hot Work') tips.push({ tone: 'info', title: 'Hot-work precautions', body: 'Confirm gas test < 10% LEL; fire watch remains 30 min after work stops.' });
  tips.push({ tone: 'ok', title: 'AI routes the approval chain', body: 'On submit, Sentinel sequences Area Supervisor → HSE → Ops Manager → Permit Issuer and tracks e-signatures.' });
  const block = v.risk === 'High' && sel.length < 2;
  return { tips, risk, riskLabel: 'Permit risk score', block, blockLabel: 'Add controls first' };
}
function incidentCompute(v) {
  const tips = []; const d = (v.description || '').toLowerCase();
  const stream = v.stream || 'HSE / Safety';
  const hs = v.classHS || []; const env = v.classEnv || []; const qual = v.classQual || []; const ast = v.classAsset || [];
  const loc = v.injuryLocation || []; const act = v.unsafeAct || []; const cond = v.unsafeCondition || [];
  const pf = v.personalFactor || []; const sf = v.systemFactor || [];
  const SEV_TOP = ['Fatality', 'Permanent Total Disability', 'Lost Time Injury', 'Serious Injury', 'Serious Dangerous Occurrence', 'Serious Occupational Illness / Disease'];
  const isTop = hs.some((x) => SEV_TOP.includes(x)) || /height|confined|asphyx|drop|fall|fire|explos|electroc/.test(d);
  // severity index
  let risk = 0;
  if (hs.includes('Fatality') || hs.includes('Permanent Total Disability')) risk = 100;
  else if (hs.includes('Lost Time Injury') || hs.some((x) => x.startsWith('Serious'))) risk = 80;
  else if (hs.includes('Restricted Workday Case') || hs.includes('Medical Treatment Case') || env.length) risk = 55;
  else if (hs.includes('First Aid Injury')) risk = 30;
  else if (hs.includes('Near Miss') || v.condition === 'Near miss') risk = 18;
  if (v.assetStatus === 'Out of service') risk = Math.max(risk, 65);
  if (qual.includes('Repeat NCR')) risk = Math.max(risk, 50);
  if (v.seriousness === 'Serious') risk = Math.max(risk, 70);

  // stream-specific guidance
  if (stream === 'Quality') {
    tips.push({ tone: 'info', title: 'Routed to Quality (ISO 9001 §10.2)', body: 'AI treats this as a quality non-conformity — it can raise/link an NCR and search for repeat signatures across projects.' });
    if (qual.includes('Repeat NCR') || qual.includes('Documentation')) tips.push({ tone: 'warn', title: 'Repeat-signature risk', body: 'AI finds matching prior NCRs in this category — treat as systemic; a containment-only action will likely recur.' });
  }
  if (stream === 'Asset / Property Damage') {
    tips.push({ tone: 'info', title: 'Routed to Asset Integrity', body: 'AI links the affected asset to its maintenance, calibration and TPI history to gauge integrity impact.' });
    if (v.assetStatus === 'Out of service') tips.push({ tone: 'bad', title: 'Asset out of service — readiness impact', body: 'AI flags an equipment-readiness gap — quarantine the asset, raise a breakdown work-order and check project schedule exposure.' });
  }
  if (isTop) tips.push({ tone: 'bad', title: 'High-potential (HIPO) classification', body: 'AI flags this as a HIPO event — escalate to senior management, secure the scene and account for all personnel before the investigation proceeds.' });
  if (hs.includes('Fatality') || hs.includes('Permanent Total Disability')) tips.push({ tone: 'bad', title: 'Statutory notification required', body: 'A fatality / PTD is reportable to the legal authority — set “Reportable = Yes” and notify the regulator within the mandated window (typically 24 h).' });
  if (v.reportable === 'Yes') tips.push({ tone: 'warn', title: 'Regulatory reporting clock started', body: 'AI will pre-fill the authority notification and track the statutory deadline alongside the investigation.' });
  if (loc.includes('Head') || loc.includes('Eyes')) tips.push({ tone: 'warn', title: 'Head / eye injury — escalate medical', body: 'Head and eye injuries can mask serious harm — confirm medical assessment and consider precautionary referral before classifying severity.' });
  if (env.length) tips.push({ tone: 'warn', title: 'Environmental release detected', body: 'AI links this to ISO 14001 §10.2 — capture quantity, receptor and containment, and notify the environmental focal point.' });
  if (/height|drop|fall/.test(d)) tips.push({ tone: 'warn', title: 'Pattern match — at-height events', body: 'Similar to 2 prior at-height near-misses on P-204 this quarter — likely a systemic lifting/tethering control gap.' });
  if ((v.description || '').length > 20 && !act.length && !cond.length) tips.push({ tone: 'info', title: 'Complete the causal analysis', body: 'You’ve described the event but no immediate cause is selected — pick the unsafe act(s)/condition(s) so Sentinel can target the root cause.' });
  if ((act.length || cond.length) && !pf.length && !sf.length) tips.push({ tone: 'info', title: 'Add the underlying factors', body: 'Immediate causes captured. Add the personal / system root-cause factors — AI weighs system factors highest for CAPA design.' });
  tips.push({ tone: 'info', title: 'Suggested immediate actions', body: 'Make safe · preserve the scene · notify HSE Manager · capture witness statements while fresh.' });
  tips.push({ tone: 'ok', title: 'AI will draft the investigation', body: 'On submit, Sentinel reconstructs the sequence, runs a 5-Why / TapRooT analysis and proposes a CAPA with owners and target dates (ISO 45001 §10.2).' });

  const block = ((hs.includes('Fatality') || hs.includes('Permanent Total Disability')) && v.reportable !== 'Yes');
  return { tips, risk, riskLabel: 'Incident severity index', block, blockLabel: 'Set Reportable = Yes' };
}
/* shared 5×5 risk matrix (P × S = RPN) — PD-QSP convention */
const RISK_P = ['1 · Most unlikely', '2 · Rather unlikely', '3 · Somewhat likely', '4 · Likely', '5 · Very likely'];
const RISK_S = ['1 · Negligible', '2 · Minor', '3 · Moderate', '4 · Major', '5 · Critical'];
function riskRating(p, s) {
  const rpn = (Number(p) || 0) * (Number(s) || 0);
  let label = 'Low', color = 'var(--ok)';
  if (rpn >= 15) { label = 'Extremely High'; color = 'var(--bad)'; }
  else if (rpn >= 10) { label = 'High'; color = '#f97316'; }
  else if (rpn >= 5) { label = 'Moderate'; color = 'var(--warn)'; }
  return { rpn, label, color };
}
const parseLead = (x) => parseInt(x, 10) || 0;
function ncrCompute(v) {
  const tips = []; const cat = v.category || ''; const proj = v.projectPo || v.project || '';
  const repeat = /Documentation|Repeat|Welding/.test(cat) || proj.includes('P-198');
  if (repeat) tips.push({ tone: 'warn', title: 'Repeat signature likely', body: 'AI finds 2 prior NCRs in this category/project (bolt-torque records). Treat as systemic, not isolated — a CAR, not just a correction.' });
  else tips.push({ tone: 'ok', title: 'No repeat pattern found', body: 'AI sees no matching prior NCRs — likely an isolated occurrence; containment may be sufficient.' });
  tips.push({ tone: 'info', title: 'Probable root-cause direction', body: /Competency/.test(cat) ? 'Authorization/competency gap at point of work — check the training matrix.' : /Documentation/.test(cat) ? 'Missing verification gate in the record step under schedule pressure.' : 'Single-point process deviation — verify against the method statement.' });
  if (v.severity === 'Major') tips.push({ tone: 'bad', title: 'Major non-conformity', body: 'AI escalates — disposition (rework/reject/concession) needs QC Manager sign-off and a full CAR with effectiveness verification.' });
  if (v.mocRequired === 'Yes' || /Process|Procedure/.test(cat)) tips.push({ tone: 'warn', title: 'Management of Change may be required', body: 'A process/procedure change to fix this should run through MOC — AI can raise a linked MOC request so the change is risk-assessed and approved.' });
  tips.push({ tone: 'ok', title: 'AI drafts the CAR & effectiveness check', body: 'On submit, Sentinel proposes a corrective/preventive action (CAR) targeting the root cause, plus a verification-of-effectiveness step and target dates (ISO 9001 §10.2).' });
  return { tips, risk: v.severity === 'Major' ? 75 : 35, riskLabel: 'NC severity index' };
}
function mocCompute(v) {
  const tips = []; const p = parseLead(v.probability), s = parseLead(v.severity); const rr = riskRating(p, s);
  const types = v.changeType || [];
  tips.push({ tone: rr.rpn >= 10 ? 'bad' : rr.rpn >= 5 ? 'warn' : 'ok', title: `Risk rating: ${rr.label}${rr.rpn ? ` (RPN ${rr.rpn})` : ''}`, body: p && s ? `Probability ${p} × Severity ${s} = ${rr.rpn}. ${rr.rpn >= 10 ? 'High RPN — detailed mitigation controls and MD/VP approval are mandatory before execution.' : 'Document the mitigation controls and route for MR review.'}` : 'Select probability and severity — AI computes the 5×5 risk rating live.' });
  if (types.includes('Critical Equipment Change') || types.includes('Critical Supplier')) tips.push({ tone: 'warn', title: 'Critical change — extra controls', body: 'AI recommends an updated risk assessment, supplier/equipment re-qualification and a post-implementation verification step.' });
  if (types.includes('Product / Process Change') || types.includes('QMS Changes')) tips.push({ tone: 'info', title: 'Document & training impact', body: 'AI links this to Document Control and Competency — procedures and training records will need updating before the change takes effect.' });
  if (types.includes('Key Personnel Change')) tips.push({ tone: 'info', title: 'Competency continuity', body: 'AI flags an authority/competency handover — verify the successor holds the required certifications before the change is effective.' });
  tips.push({ tone: 'ok', title: 'AI routes the approval chain', body: 'On submit, Sentinel builds the MR → MD/VP approval workflow and notifies the change executor with the impact checklist.' });
  return { tips, risk: Math.min(100, rr.rpn * 4), riskLabel: 'Change risk (5×5 RPN)' };
}
/* assign worker → live competency/medical check */
const TASK_REQ = { 'Confined Space Entry': ['H2S', 'CSE', 'Medical'], 'Nitrogen Unit Operation': ['H2S', 'CSE', 'N2 Ops', 'Aramco CSTP', 'Medical'], 'Lifting Supervision': ['Rigging', 'Aramco CSTP', 'Medical'], 'NDT Inspection': ['CSWIP', 'NDT L2', 'Medical'], 'Hot Work / Welding': ['H2S', 'Medical'] };
function competencyCompute(v) {
  const tips = []; const s = DB.staff.find((x) => x.name === v.worker); const rec = s && DB.competency.find((c) => c.staff === s.id); const req = TASK_REQ[v.task] || [];
  if (!rec) { tips.push({ tone: 'info', title: 'Select an authorized worker', body: 'AI will verify certifications & medical fitness against the task requirements.' }); return { tips }; }
  const missing = req.filter((r) => !rec.certs[r] || rec.certs[r] === 'X'); const expiring = req.filter((r) => rec.certs[r] === 'E');
  if (missing.length) tips.push({ tone: 'bad', title: 'Not authorized for this task', body: `${s.name} is missing: ${missing.join(', ')}. AI blocks the assignment until renewed.` });
  else if (expiring.length) tips.push({ tone: 'warn', title: 'Authorization expiring soon', body: `${expiring.join(', ')} for ${s.name} expires shortly — assign but schedule a renewal now.` });
  else tips.push({ tone: 'ok', title: 'Authorized for this task', body: `${s.name} holds all required certifications and a current medical fitness.` });
  tips.push({ tone: 'info', title: 'Required for ' + v.task, body: req.join(' · ') });
  return { tips };
}
/* plan journey → live fatigue / journey-risk */
function journeyCompute(v) {
  const tips = []; const route = (v.route || '').toLowerCase(); const dep = (v.departure || '').toLowerCase();
  const remote = /remote|field|desert|block|north|p-211|cross|highway/.test(route); const night = /night|late|early|0[0-4]:|2[0-3]:/.test(dep);
  let risk = 30 + (remote ? 25 : 0) + (night ? 22 : 0);
  if (night) tips.push({ tone: 'bad', title: 'Fatigue / night-driving alert', body: 'Departure falls in a low-light / fatigue window — verify driver hours, mandate rest stops, reconsider timing.' });
  if (remote) tips.push({ tone: 'warn', title: 'Remote-route risk', body: 'Route crosses remote field sections — AI recommends journey checkpoints, comms check and a buddy vehicle.' });
  tips.push({ tone: 'info', title: 'Journey management plan', body: 'Pre-trip inspection · GPS tracking · check-in intervals · authorized stops only.' });
  if (!remote && !night) tips.push({ tone: 'ok', title: 'Low journey risk', body: 'No remote-route or fatigue flags — standard journey management applies.' });
  return { tips, risk: Math.min(risk, 96) };
}
/* close CAPA → live effectiveness check */
function capaCheckCompute(capa) {
  return function (v) {
    const tips = []; const ev = (v.evidence || '').trim();
    tips.push({ tone: 'ok', title: 'No recurrence detected', body: 'AI scanned 90 days of incidents & NCRs — no repeat of this issue since the action was implemented.' });
    if (ev.length < 10) tips.push({ tone: 'warn', title: 'Objective evidence required', body: 'Attach verification evidence (audit, record, observation) — AI cannot confirm effectiveness without it.' });
    else tips.push({ tone: 'ok', title: 'Evidence captured', body: 'Verification evidence recorded — AI assesses the action as effective.' });
    tips.push({ tone: 'info', title: 'Residual risk', body: `${capa.severity === 'Major' ? 'Elevated' : 'Low'} — AI recommends a 30-day effectiveness re-check after closure.` });
    tips.push({ tone: ev.length < 10 ? 'warn' : 'ok', title: 'Recommendation', body: ev.length < 10 ? 'Hold closure until objective evidence is attached.' : 'Effective — safe to verify & close.' });
    return { tips };
  };
}
const openAssign = () => window.openAIAssist({ title: 'Assign worker to task', sub: 'AI live-verifies competency & medical fitness', icon: 'users', compute: competencyCompute, fields: [{ key: 'worker', label: 'Worker', type: 'select', options: DB.staff.map((s) => s.name) }, { key: 'task', label: 'Task', type: 'select', options: Object.keys(TASK_REQ) }, { key: 'project', label: 'Project', type: 'select', options: DB.projects.map((p) => p.id) }], submitLabel: 'Assign', done: 'Worker assigned · competency verified & audit-logged' });
const openJourney = () => window.openAIAssist({ title: 'Plan journey', sub: 'AI live journey-risk & fatigue assessment', icon: 'truck', compute: journeyCompute, fields: [{ key: 'vehicle', label: 'Vehicle', type: 'select', options: DB.fleet.map((f) => f.id + ' · ' + f.type) }, { key: 'driver', label: 'Driver', type: 'text', placeholder: 'Driver name' }, { key: 'route', label: 'Route', type: 'text', placeholder: 'e.g. Camp → P-211 remote field' }, { key: 'departure', label: 'Departure', type: 'text', placeholder: 'e.g. 05:00 (early)' }], submitLabel: 'Approve journey', done: 'Journey approved · live tracking active' });
const openCapaCheck = (capa) => window.openAIAssist({ title: 'Verify & close — ' + capa.id, sub: 'AI effectiveness check', icon: 'refresh', compute: capaCheckCompute(capa), fields: [{ key: 'evidence', label: 'Closure evidence / verification notes', type: 'textarea', placeholder: 'Audit ref, records reviewed, observation evidence…' }], submitLabel: 'Verify & close', done: capa.id + ' verified & closed · 30-day re-check scheduled' });
/* assign equipment → readiness lockout (FR-E.2) */
function assetCompute(v) {
  const tips = []; const a = DB.assets.find((x) => v.asset && v.asset.indexOf(x.id) > -1);
  if (!a) { tips.push({ tone: 'info', title: 'Select equipment', body: 'Sentinel verifies certification, calibration and readiness before assignment.' }); return { tips }; }
  const overdue = a.cert <= DB.TODAY || a.status === 'Cert overdue';
  const due = !overdue && (a.cert - DB.TODAY) / 864e5 < 14;
  if (overdue) {
    const alt = DB.assets.find((x) => x.type === a.type && x.status === 'Certified' && x.id !== a.id);
    tips.push({ tone: 'bad', title: 'Readiness lockout — assignment blocked', body: `${a.id} (${a.name}) certification is overdue. It cannot be assigned to a permit or job until re-certified.` });
    tips.push({ tone: 'info', title: 'Suggested alternative', body: alt ? `${alt.id} (${alt.name}) is certified and available — assign it instead.` : 'No certified unit of this type is currently available — escalate to the asset coordinator.' });
    return { tips, block: true, blockLabel: 'Assignment blocked' };
  }
  if (due) tips.push({ tone: 'warn', title: 'Certification expiring soon', body: `${a.id} certification expires in under 14 days — assign but schedule re-certification now.` });
  else tips.push({ tone: 'ok', title: 'Equipment ready', body: `${a.id} is certified, calibrated and ready for assignment.` });
  return { tips };
}
const openAssignAsset = () => window.openAIAssist({ title: 'Assign equipment to job', sub: 'Sentinel verifies readiness & blocks expired-cert assets', icon: 'cpu', compute: assetCompute, fields: [{ key: 'asset', label: 'Equipment', type: 'select', options: DB.assets.map((a) => a.id + ' · ' + a.name) }, { key: 'project', label: 'Project / job', type: 'select', options: DB.projects.map((p) => p.id) }], submitLabel: 'Assign equipment', done: 'Equipment assigned · readiness verified & logged' });

/* ===================== BUSINESS EXCELLENCE DASHBOARD ================= */
/* ---------- dashboard chart helpers ---------- */
const DASH_TONE = { info: ['var(--info-bg)', 'var(--primary-600)'], ok: ['var(--ok-bg)', 'var(--ok)'], warn: ['var(--warn-bg)', 'var(--warn)'], bad: ['var(--bad-bg)', 'var(--bad)'], ai: ['var(--ai-bg)', 'var(--ai)'] };
function DashKpi({ k, v, icon, tone, d, dir, onClick }) {
  const t = DASH_TONE[tone] || DASH_TONE.info; const up = dir === 'up';
  return (
    <div className="card hover-lift" style={{ padding: '13px 14px', cursor: 'pointer' }} onClick={onClick}>
      <div className="row" style={{ gap: 11, alignItems: 'center' }}>
        <span style={{ width: 38, height: 38, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={icon} size={19} /></span>
        <div style={{ minWidth: 0 }}><div className="eyebrow" style={{ fontSize: 9, lineHeight: 1.25 }}>{k}</div><div style={{ fontSize: 26, fontWeight: 800, lineHeight: 1.05, marginTop: 1 }}>{v}</div></div>
      </div>
      <div className="row" style={{ gap: 4, marginTop: 8, fontSize: 10.5 }}><Icon name={up ? 'arrowUp' : 'arrowDown'} size={11} style={{ color: up ? 'var(--bad)' : 'var(--ok)' }} /><b style={{ color: up ? 'var(--bad)' : 'var(--ok)' }}>{d}</b><span className="faint">vs last month</span></div>
    </div>
  );
}
function DashDonut({ data, size = 138 }) {
  const total = data.reduce((s, d) => s + d.v, 0); const R = size / 2, r = R - 13, C = 2 * Math.PI * r; let off = 0;
  return (
    <svg viewBox={`0 0 ${size} ${size}`} style={{ width: size, height: size, flex: 'none' }}>
      <g transform={`rotate(-90 ${R} ${R})`}>{data.map((d, i) => { const dash = (d.v / total) * C; const seg = <circle key={i} cx={R} cy={R} r={r} fill="none" stroke={d.c} strokeWidth="20" strokeDasharray={`${dash} ${C - dash}`} strokeDashoffset={-off} />; off += dash; return seg; })}</g>
      <text x={R} y={R - 3} textAnchor="middle" fontSize="10" fill="var(--text-3)">Total</text>
      <text x={R} y={R + 17} textAnchor="middle" fontSize="24" fontWeight="800" fill="var(--text)">{total}</text>
    </svg>
  );
}
function DashLegend({ data, total }) {
  const tot = total || data.reduce((s, d) => s + d.v, 0);
  return <div style={{ display: 'flex', flexDirection: 'column', gap: 5, flex: 1 }}>{data.map((d, i) => (
    <div key={i} className="row" style={{ gap: 7, fontSize: 11 }}><span style={{ width: 9, height: 9, borderRadius: 2, background: d.c, flex: 'none' }} /><span style={{ flex: 1, color: 'var(--text-2)' }}>{d.l}</span><b>{d.v}</b><span className="faint" style={{ fontSize: 10 }}>({Math.round(d.v / tot * 100)}%)</span></div>
  ))}</div>;
}
function DashLine({ trend }) {
  const W = 430, H = 180, padL = 26, padB = 22, padT = 18;
  const max = Math.max(...trend.series.flatMap((s) => s.d)) * 1.12;
  const x = (i) => padL + i * ((W - padL - 10) / (trend.labels.length - 1));
  const y = (v) => H - padB - (v / max) * (H - padB - padT);
  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%' }}>
      {[0, 0.5, 1].map((g, i) => <line key={i} x1={padL} y1={padT + g * (H - padB - padT)} x2={W - 6} y2={padT + g * (H - padB - padT)} stroke="var(--border)" strokeWidth="1" />)}
      {trend.series.map((s, si) => <g key={si}><polyline points={s.d.map((v, i) => `${x(i)},${y(v)}`).join(' ')} fill="none" stroke={s.c} strokeWidth="2.4" strokeLinejoin="round" />{s.d.map((v, i) => <circle key={i} cx={x(i)} cy={y(v)} r="3" fill="#fff" stroke={s.c} strokeWidth="2" />)}</g>)}
      {trend.labels.map((l, i) => <text key={i} x={x(i)} y={H - 6} textAnchor="middle" fontSize="9.5" fill="var(--text-3)">{l}</text>)}
    </svg>
  );
}
function DashHBars({ data }) {
  const max = Math.max(...data.map((d) => d.v));
  return <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>{data.map((d, i) => (
    <div key={i} className="row" style={{ gap: 9, alignItems: 'center' }}>
      <span style={{ width: 100, fontSize: 11, color: 'var(--text-2)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{d.l}</span>
      <div style={{ flex: 1, height: 10, borderRadius: 5, background: 'var(--surface-2)' }}><div style={{ width: `${d.v / max * 100}%`, height: '100%', borderRadius: 5, background: d.c || 'var(--primary-600)' }} /></div>
      <span style={{ width: 20, textAlign: 'right', fontSize: 12, fontWeight: 700 }}>{d.v}</span>
    </div>))}</div>;
}
function DashGauge({ value, max, color, fmt }) {
  const R = 60, cx = 80, cy = 72, len = Math.PI * R, frac = Math.max(0, Math.min(1, value / max));
  const path = `M ${cx - R} ${cy} A ${R} ${R} 0 0 1 ${cx + R} ${cy}`;
  return (
    <svg viewBox="0 0 160 90" style={{ width: '100%', maxHeight: 92 }}>
      <path d={path} fill="none" stroke="var(--surface-2)" strokeWidth="13" strokeLinecap="round" />
      <path d={path} fill="none" stroke={color} strokeWidth="13" strokeLinecap="round" strokeDasharray={`${frac * len} ${len}`} />
      <text x="80" y="68" textAnchor="middle" fontSize="23" fontWeight="800" fill="var(--text)">{fmt}</text>
    </svg>
  );
}
function DashRiskGrid({ matrix }) {
  const cons = ['Insig.', 'Minor', 'Mod.', 'Major', 'Severe'];
  const like = ['Almost Certain', 'Likely', 'Possible', 'Unlikely', 'Rare'];
  const color = (li, ci) => { const r = (5 - li) * (ci + 1); return r >= 15 ? '#ef4444' : r >= 10 ? '#f97316' : r >= 6 ? '#f59e0b' : r >= 3 ? '#a3e635' : '#22c55e'; };
  return (
    <div>
      {matrix.map((row, li) => (
        <div key={li} className="row" style={{ gap: 3, marginBottom: 3, alignItems: 'center' }}>
          <span style={{ width: 70, fontSize: 8, color: 'var(--text-3)', textAlign: 'right', lineHeight: 1.1 }}>{like[li]}</span>
          {row.map((c, ci) => <div key={ci} style={{ flex: 1, height: 24, borderRadius: 4, background: color(li, ci), display: 'grid', placeItems: 'center', color: '#fff', fontWeight: 700, fontSize: 11 }}>{c || ''}</div>)}
        </div>
      ))}
      <div className="row" style={{ gap: 3 }}><span style={{ width: 70 }} />{cons.map((c, i) => <span key={i} style={{ flex: 1, textAlign: 'center', fontSize: 8, color: 'var(--text-3)' }}>{c}</span>)}</div>
    </div>
  );
}
function Dashboard({ onNav, onOpen }) {
  const m = DB.mgmt, x = DB.dash;
  const head = (t, sub, ico) => <div className="card-head" style={{ paddingBottom: 8 }}><Icon name={ico || 'grid'} size={15} style={{ color: 'var(--primary-600)' }} /><div className="h-sec" style={{ fontSize: 13 }}>{t}</div>{sub && <span className="faint" style={{ fontSize: 10.5, marginLeft: 'auto' }}>{sub}</span>}</div>;
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 16 }}>
        <div><div className="h-page">QHSE Dashboard</div><div className="h-sub">{((typeof demoUser === 'function' ? demoUser() : null) || {}).name || 'Yusuf Rahman'} · Meridian Offshore · <span title="Hijri (Umm al-Qura)">{DB.hijri(DB.TODAY)}</span> · <span style={{ color: 'var(--ok)', fontWeight: 600 }}>All systems nominal</span></div></div>
        <div className="row" style={{ gap: 8 }}><DateFilter /><Btn icon="sparkles" variant="ai" onClick={() => onNav('ai')}>Ask Sentinel</Btn><Btn icon="download" size="sm" onClick={() => window.toast('Executive pack exported (PDF)')}>Export</Btn></div>
      </div>
      {/* Quick links */}
      <div className="row" style={{ gap: 8, marginBottom: 14, flexWrap: 'wrap' }}>
        {[['Report incident', 'helmet', 'incidents'], ['Report near-miss', 'alert', 'incidents'], ['Safety observation', 'flag', 'safetyobs'], ['Raise permit', 'clipboard', 'ptw'], ['Toolbox talk', 'users', 'competency'], ['Safety alert', 'bell', 'safetyalerts']].map(([l, ic, nav]) => (
          <button key={l} onClick={() => onNav(nav)} style={{ display: 'inline-flex', alignItems: 'center', gap: 7, background: 'var(--surface)', border: '1px solid var(--border-2)', borderRadius: 9, padding: '8px 12px', fontSize: 12.5, fontWeight: 600, fontFamily: 'inherit', cursor: 'pointer', color: 'var(--text)' }}>
            <span style={{ width: 22, height: 22, borderRadius: 6, background: 'var(--info-bg)', color: 'var(--primary-600)', display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={13} /></span>{l}
          </button>
        ))}
      </div>
      {/* Row 1 — KPI cards */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))', gap: 12, marginBottom: 14 }}>
        {x.kpis.map((c, i) => <DashKpi key={i} {...c} onClick={() => onNav(c.nav)} />)}
      </div>
      {/* Row 2 — exposure & rates */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 14, marginBottom: 14 }}>
        <div className="card card-pad row" style={{ gap: 14, alignItems: 'center' }}>
          <span style={{ width: 46, height: 46, borderRadius: 12, background: 'var(--info-bg)', color: 'var(--primary-600)', display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name="users" size={22} /></span>
          <div><div className="eyebrow" style={{ fontSize: 9.5 }}>Total man-hours worked</div><div style={{ fontSize: 30, fontWeight: 800, letterSpacing: '-0.5px' }}>{x.manHours}</div><div className="row" style={{ gap: 4, fontSize: 11 }}><span className="faint">vs last month</span><Icon name="arrowUp" size={11} style={{ color: 'var(--ok)' }} /><b style={{ color: 'var(--ok)' }}>{x.manHoursDelta}</b></div></div>
        </div>
        <div className="card card-pad">
          <div className="eyebrow" style={{ fontSize: 9.5 }}>TRIR · total recordable incident rate</div>
          <div className="row" style={{ alignItems: 'flex-end', gap: 10, marginTop: 4 }}><span style={{ fontSize: 30, fontWeight: 800 }}>{x.trir}</span><span className="faint" style={{ fontSize: 11, marginBottom: 5 }}>target ≤ 1.00</span><span className="badge b-ok" style={{ marginLeft: 'auto', marginBottom: 4 }}>On track</span></div>
          <div className="row" style={{ gap: 4, fontSize: 11, marginTop: 4 }}><Icon name="arrowDown" size={11} style={{ color: 'var(--ok)' }} /><b style={{ color: 'var(--ok)' }}>{x.trirDelta}</b><span className="faint">vs last month</span></div>
        </div>
        <div className="card card-pad">
          <div className="eyebrow" style={{ fontSize: 9.5 }}>LTI-free days</div>
          <div className="row" style={{ alignItems: 'flex-end', gap: 10, marginTop: 4 }}><span style={{ fontSize: 30, fontWeight: 800, color: 'var(--primary-700)' }}>{x.ltiFree}</span><span className="faint" style={{ fontSize: 11, marginBottom: 5 }}>target {x.ltiTarget} days</span><span className="badge b-info" style={{ marginLeft: 'auto', marginBottom: 4 }}>In progress</span></div>
          <div className="progress" style={{ marginTop: 9, height: 6 }}><i style={{ width: `${x.ltiFree / x.ltiTarget * 100}%`, background: 'linear-gradient(90deg,var(--primary-500),#58d6a6)' }} /></div>
        </div>
      </div>
      {/* Row 3 — trend / type / location / body */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 14, marginBottom: 14 }}>
        <div className="card card-pad">{head('Incident trend', '6 months', 'trend')}
          <div className="row" style={{ gap: 12, flexWrap: 'wrap', margin: '2px 0 4px' }}>{x.trend.series.map((s, i) => <span key={i} className="row" style={{ gap: 5, fontSize: 10.5, color: 'var(--text-2)' }}><span style={{ width: 14, height: 3, borderRadius: 2, background: s.c }} />{s.k}</span>)}</div>
          <DashLine trend={x.trend} />
        </div>
        <div className="card card-pad">{head('Incidents by type', null, 'chart')}
          <div className="row" style={{ gap: 12, alignItems: 'center', marginTop: 4 }}><DashDonut data={x.byType} size={118} /><DashLegend data={x.byType} /></div>
        </div>
        <div className="card card-pad">{head('Incidents by location', null, 'pin')}
          <div style={{ marginTop: 6 }}><DashHBars data={x.byLocation} /></div>
        </div>
        <div className="card card-pad">{head('Injuries by body part', null, 'helmet')}
          <div className="row" style={{ gap: 6, alignItems: 'center', marginTop: 4 }}>
            <svg viewBox="0 0 338.64 839.2" style={{ width: 64, flex: 'none' }} dangerouslySetInnerHTML={{ __html: window.BODY_FRONT }} />
            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 4 }}>{x.bodyParts.map((b, i) => { const hot = b.v >= 6; return (
              <div key={i} className="row" style={{ gap: 5, alignItems: 'center' }}><span style={{ flex: 1, fontSize: 10, color: 'var(--text-2)' }}>{b.l}</span><b style={{ fontSize: 11, color: hot ? 'var(--bad)' : 'var(--text)' }}>{b.v}</b><span className="faint" style={{ fontSize: 9, width: 32, textAlign: 'right' }}>({b.p}%)</span></div>
            ); })}</div>
          </div>
        </div>
      </div>
      {/* Row 4 — risk matrix / actions / overdue / training / gauges */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(230px, 1fr))', gap: 14, marginBottom: 14 }}>
        <div className="card card-pad">{head('Risk matrix', 'live', 'alert')}<div style={{ marginTop: 6 }}><DashRiskGrid matrix={x.riskMatrix} /></div></div>
        <div className="card card-pad">{head('Action status', null, 'flag')}
          <div className="row" style={{ gap: 10, alignItems: 'center', marginTop: 2 }}><DashDonut data={x.actionStatus} size={108} /><DashLegend data={x.actionStatus} /></div>
        </div>
        <div className="card card-pad" style={{ display: 'flex', flexDirection: 'column' }}>{head('Overdue actions', null, 'clock')}
          <div style={{ textAlign: 'center', marginTop: 8 }}><div style={{ fontSize: 40, fontWeight: 800, color: 'var(--bad)', lineHeight: 1 }}>{x.overdueActions}</div><div className="faint" style={{ fontSize: 10.5, marginTop: 4 }}>overdue actions</div></div>
          <div style={{ marginTop: 'auto', textAlign: 'center', paddingTop: 10 }}><div className="faint" style={{ fontSize: 10 }}>avg. days overdue</div><div style={{ fontSize: 20, fontWeight: 800, color: 'var(--bad)' }}>{x.avgDaysOverdue}</div></div>
        </div>
        <div className="card card-pad">{head('Training compliance', null, 'users')}
          <div className="row" style={{ gap: 10, alignItems: 'center', marginTop: 2 }}>
            <Ring value={86} size={88} stroke={10} color="var(--ok)"><div style={{ fontSize: 18, fontWeight: 800 }}>86%</div></Ring>
            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 5 }}>
              {[['Compliant', x.training.compliant, 'var(--ok)'], ['Non-compliant', x.training.nonCompliant, 'var(--warn)'], ['Expired', x.training.expired, 'var(--bad)']].map(([l, v, c], i) => <div key={i} className="row" style={{ gap: 6, fontSize: 11 }}><span style={{ width: 8, height: 8, borderRadius: 2, background: c }} /><span style={{ flex: 1, color: 'var(--text-2)' }}>{l}</span><b>{v.toLocaleString()}</b></div>)}
            </div>
          </div>
        </div>
        <div className="card card-pad">{head('Performance gauges', null, 'gauge')}
          <div className="row" style={{ gap: 8 }}>
            <div style={{ flex: 1, textAlign: 'center' }}><div className="eyebrow" style={{ fontSize: 8.5 }}>TRIR</div><DashGauge value={x.trir} max={3} color={x.trir <= 1 ? 'var(--ok)' : 'var(--warn)'} fmt={x.trir} /><div className="faint" style={{ fontSize: 9 }}>target ≤ 1.00</div></div>
            <div style={{ flex: 1, textAlign: 'center' }}><div className="eyebrow" style={{ fontSize: 8.5 }}>LTI-free days</div><DashGauge value={x.ltiFree} max={x.ltiTarget} color="var(--primary-600)" fmt={x.ltiFree} /><div className="faint" style={{ fontSize: 9 }}>target {x.ltiTarget}</div></div>
          </div>
        </div>
      </div>
      {/* Row 5 — environment / audit / root causes / alerts */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: 14 }}>
        <div className="card card-pad">{head('Environmental performance', null, 'droplet')}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginTop: 6 }}>{x.env.map((e, i) => (
            <div key={i} style={{ textAlign: 'center' }}><Icon name={e.icon} size={20} style={{ color: 'var(--primary-600)' }} /><div style={{ fontSize: 20, fontWeight: 800, marginTop: 2 }}>{e.v}</div><div className="eyebrow" style={{ fontSize: 8.5 }}>{e.l}</div><div className="row" style={{ gap: 3, justifyContent: 'center', fontSize: 10, marginTop: 2 }}><Icon name={e.dir === 'up' ? 'arrowUp' : 'arrowDown'} size={10} style={{ color: e.dir === 'up' ? 'var(--ok)' : 'var(--ok)' }} /><b style={{ color: 'var(--ok)' }}>{e.d}</b></div></div>
          ))}</div>
        </div>
        <div className="card card-pad">{head('Audit & inspections', null, 'documents')}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 10, marginTop: 6 }}>{x.audit.map((e, i) => (
            <div key={i} style={{ textAlign: 'center' }}><Icon name={e.icon} size={18} style={{ color: 'var(--primary-600)' }} /><div style={{ fontSize: 19, fontWeight: 800, marginTop: 2 }}>{e.v}</div><div className="eyebrow" style={{ fontSize: 8 }}>{e.l}</div><div className="row" style={{ gap: 2, justifyContent: 'center', fontSize: 9.5, marginTop: 2 }}><Icon name={e.dir === 'up' ? 'arrowUp' : 'arrowDown'} size={9} style={{ color: 'var(--ok)' }} /><b style={{ color: 'var(--ok)' }}>{e.d}</b></div></div>
          ))}</div>
        </div>
        <div className="card card-pad">{head('Top 5 root causes', null, 'history')}<div style={{ marginTop: 6 }}><DashHBars data={x.rootCauses} /></div></div>
        <div className="card card-pad">{head('Alerts & notifications', null, 'bell')}
          <div style={{ display: 'flex', flexDirection: 'column', marginTop: 4 }}>{x.alerts.map((a, i) => { const t = DASH_TONE[a.tone] || DASH_TONE.info; return (
            <div key={i} className="row" style={{ gap: 9, padding: '9px 4px', borderBottom: i < x.alerts.length - 1 ? '1px solid var(--border)' : 'none', cursor: 'pointer' }} onClick={() => onNav(a.nav)}>
              <span style={{ width: 28, height: 28, borderRadius: 8, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={a.icon} size={14} /></span>
              <span style={{ flex: 1, fontSize: 12, fontWeight: 600 }}>{a.l}</span><b style={{ fontSize: 13 }}>{a.v}</b><Icon name="chevR" size={13} style={{ color: 'var(--text-3)' }} />
            </div>
          ); })}</div>
        </div>
      </div>
    </div>
  );
}

/* ===================== AI MODULE (Sentinel page) ===================== */
/* ===================== DEPARTMENT DASHBOARDS (AI-enabled) =========== */
function DeptDashboards({ onNav, onOpen }) {
  const _u = (typeof demoUser === 'function' ? demoUser() : null) || {};
  const _crossDept = !!(_u.sysadmin || _u.crossDept);
  const _home = window.DEMO_DEPT || 'hse';
  const [d, setD] = useState(_crossDept ? 'hse' : _home);
  const m = DB.mgmt, inc = DB.incidents, ncr = DB.ncrs, as = DB.assets, pj = DB.projects;
  const incCat = {}; inc.forEach((i) => incCat[i.cat] = (incCat[i.cat] || 0) + 1);
  const ALLDEPTS = [['hse', 'HSE'], ['quality', 'Quality'], ['compliance', 'Compliance'], ['asset', 'Asset Integrity'], ['people', 'Workforce'], ['projects', 'Projects'], ['fleet', 'Fleet']];
  const depts = _crossDept ? ALLDEPTS : ALLDEPTS.filter(([id]) => id === _home);
  const KGrid = ({ children }) => <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(5,1fr)', marginBottom: 16 }}>{children}</div>;
  const ChartRow = ({ children }) => <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.2fr 1.3fr', gap: 16, marginTop: 16, alignItems: 'start' }}>{children}</div>;
  const Panel = ({ title, children }) => <div className="card card-pad" style={{ minWidth: 0 }}><div className="eyebrow" style={{ marginBottom: 10 }}>{title}</div>{children}</div>;
  const deptHealth = [
    { id: 'hse', label: 'HSE', score: 88, tone: 'ok', metric: '2 open HIPO events', spark: [82, 84, 83, 86, 87, 88] },
    { id: 'quality', label: 'Quality', score: 84, tone: 'ok', metric: '5 open NCR / CAR', spark: [79, 80, 82, 81, 83, 84] },
    { id: 'compliance', label: 'Compliance', score: 84, tone: 'warn', metric: 'ISO 45001 audit in 12d', spark: [80, 81, 82, 82, 83, 84] },
    { id: 'asset', label: 'Asset Integrity', score: 91, tone: 'ok', metric: 'HP-03 cert overdue', spark: [88, 89, 90, 90, 91, 91] },
    { id: 'people', label: 'Workforce', score: 86, tone: 'warn', metric: '7 certs expiring 30d', spark: [83, 84, 84, 85, 85, 86] },
    { id: 'projects', label: 'Projects', score: 89, tone: 'ok', metric: 'P-211 mobilizing', spark: [85, 86, 87, 88, 88, 89] },
    { id: 'fleet', label: 'Fleet', score: 90, tone: 'ok', metric: '2 harsh-braking (wk)', spark: [86, 87, 88, 89, 89, 90] },
  ].filter((x) => _crossDept || x.id === _home);
  const Spark = ({ data, color }) => { const max = Math.max(...data), min = Math.min(...data), W = 96, H = 26; const pts = data.map((v, i) => `${i * (W / (data.length - 1))},${H - ((v - min) / (max - min || 1)) * (H - 4) - 2}`).join(' '); return <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', height: 26 }}><polyline points={pts} fill="none" stroke={color} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" /></svg>; };
  return (
    <div className="page page-wide rise">
      <PageHead title="Department Dashboards" sub="A separate AI-enabled dashboard for every department — the numbers behind the executive score">
        <DateFilter />
        <Btn icon="sparkles" variant="ai" size="sm" onClick={() => onNav('ai')}>Ask Sentinel</Btn>
      </PageHead>
      {_crossDept && <div style={{ display: 'grid', gridTemplateColumns: `repeat(${deptHealth.length},1fr)`, gap: 12, marginBottom: 18 }}>{deptHealth.map((h) => { const c = h.tone === 'ok' ? 'var(--ok)' : h.tone === 'warn' ? 'var(--warn)' : 'var(--bad)'; return (
        <div key={h.id} className="card hover-lift" style={{ padding: '12px 13px', cursor: 'pointer', borderTop: `3px solid ${c}` }} onClick={() => setD(h.id)}>
          <div className="eyebrow" style={{ fontSize: 9, marginBottom: 4 }}>{h.label}</div>
          <div className="row" style={{ alignItems: 'flex-end', gap: 5 }}><span style={{ fontSize: 24, fontWeight: 800, lineHeight: 1 }}>{h.score}</span><span className="faint" style={{ fontSize: 11, marginBottom: 2 }}>/100</span></div>
          <Spark data={h.spark} color={c} />
          <div className="faint" style={{ fontSize: 10, marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{h.metric}</div>
        </div>
      ); })}</div>}
      <Tabs tabs={depts} tab={d} setTab={setD} />

      {d === 'hse' && <React.Fragment>
        <KGrid>
          <Kpi label="Open incidents" value={inc.filter((i) => i.status !== 'Closed').length} icon="helmet" tone="warn" />
          <Kpi label="High-potential" value={inc.filter((i) => i.hipo).length} icon="alert" tone="bad" />
          <Kpi label="LTI-free days" value={m.ltiFreeDays} icon="check-circle" tone="ok" />
          <Kpi label="TRIR" value={m.trir} icon="trend" tone="ok" delta="↓ improving" />
          <Kpi label="Man-hours YTD" value={m.manHours} icon="clock" tone="info" />
        </KGrid>
        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 16, alignItems: 'start' }}>
          <div className="card"><div className="card-head"><Icon name="helmet" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Incidents by category (12 mo)</div></div>
            <div className="card-body">{Object.entries(incCat).map(([k, v], i) => <div key={i} className="row" style={{ gap: 10, padding: '5px 0' }}><span style={{ width: 120, fontSize: 12.5 }}>{k}</span><div style={{ flex: 1 }}><Bar pct={v * 28} color="var(--primary-600)" /></div><span className="mono faint" style={{ fontSize: 11 }}>{v}</span></div>)}</div>
          </div>
          <AINote title="At-height pattern — act now" clause="ISO 45001 §10.2" action="Open AI investigation" onAction={() => onOpen('incident', inc[0])}>3rd dropped-object near-miss on P-204 this quarter — systemic lifting-controls gap. Close CAPA-26-040 and broadcast the learning alert.</AINote>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginTop: 16 }}>
          <div className="card"><div className="card-head"><Icon name="helmet" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Injuries by body part (12 mo)</div></div>
            <div className="card-body">{[['Hand / finger', 3], ['Eye / face', 1], ['Back', 1], ['Foot', 1], ['Head', 0]].map(([k, v], i) => <div key={i} className="row" style={{ gap: 10, padding: '5px 0' }}><span style={{ width: 110, fontSize: 12.5 }}>{k}</span><div style={{ flex: 1 }}><Bar pct={v * 28} color={v ? 'var(--warn)' : 'var(--ok)'} /></div><span className="mono faint" style={{ fontSize: 11 }}>{v}</span></div>)}</div>
          </div>
          <div className="card"><div className="card-head"><Icon name="alert" size={16} style={{ color: 'var(--ok)' }} /><div className="h-sec">Environmental & waste</div><span className="spacer" /><Badge kind="ok">in target</Badge></div>
            <div className="card-body" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              {[['Waste recycled', '82%'], ['Reportable spills (YTD)', '1'], ['CO₂ (t, this mo)', '41'], ['Water reused', '94%'], ['Hazardous waste (t)', '3.2'], ['Energy (MWh, mo)', '128']].map(([k, v], i) => <div key={i} style={{ border: '1px solid var(--border)', borderRadius: 10, padding: '10px 11px' }}><div className="eyebrow" style={{ fontSize: 9 }}>{k}</div><div style={{ fontSize: 19, fontWeight: 800, marginTop: 3 }}>{v}</div></div>)}
            </div>
          </div>
        </div>
        <ChartRow>
          <Panel title="Incidents by status"><DashSplit data={[{ l: 'Open', v: inc.filter((i) => i.status !== 'Closed').length, c: '#f59e0b' }, { l: 'Investigation', v: inc.filter((i) => /investig/i.test(i.status || '')).length || 4, c: '#2563eb' }, { l: 'Closed', v: inc.filter((i) => i.status === 'Closed').length, c: '#22c55e' }]} /></Panel>
          <Panel title="Leading vs lagging (6 mo)"><DashHBars data={[{ l: 'Near-miss', v: 32, c: '#22c55e' }, { l: 'First-aid', v: 7, c: '#f59e0b' }, { l: 'MTC', v: 2, c: '#f97316' }, { l: 'LTI', v: 3, c: '#ef4444' }]} /></Panel>
          <Panel title="Incident frequency trend (6 mo)"><DashLine trend={{ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#2563eb', d: [9, 7, 8, 6, 7, 5] }, { c: '#ef4444', d: [2, 1, 1, 1, 0, 1] }] }} /></Panel>
        </ChartRow>
      </React.Fragment>}

      {d === 'quality' && <React.Fragment>
        <KGrid>
          <Kpi label="Open NCRs" value={ncr.filter((n) => n.status !== 'Closed').length} icon="check-shield" tone="warn" />
          <Kpi label="Repeat NCRs" value={ncr.filter((n) => n.repeat).length} icon="refresh" tone="bad" />
          <Kpi label="Observations" value={DB.observations.length} icon="flag" tone="info" />
          <Kpi label="Open complaints" value={DB.complaints.filter((c) => c.status !== 'Resolved').length} icon="chat" tone="warn" />
          <Kpi label="First-pass yield" value="92" unit="%" icon="trend" tone="ok" delta="+2%" />
        </KGrid>
        <ChartRow>
          <Panel title="NCR / CAR by status"><DashSplit data={[{ l: 'Open', v: 5, c: '#ef4444' }, { l: 'In progress', v: 7, c: '#f59e0b' }, { l: 'Verification', v: 3, c: '#2563eb' }, { l: 'Closed', v: 9, c: '#22c55e' }]} /></Panel>
          <Panel title="NCR by category"><DashHBars data={[{ l: 'Workmanship', v: 8, c: '#ef4444' }, { l: 'Documentation', v: 6, c: '#f59e0b' }, { l: 'Material', v: 5, c: '#2563eb' }, { l: 'Process', v: 4, c: '#22c55e' }, { l: 'Supplier', v: 3, c: '#7a5bff' }]} /></Panel>
          <Panel title="Raised vs closed (6 mo)"><DashLine trend={{ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#ef4444', d: [5, 7, 6, 8, 6, 5] }, { c: '#22c55e', d: [3, 5, 6, 6, 7, 8] }] }} /></Panel>
        </ChartRow>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginTop: 16 }}>
          <AINote title="Repeat NCR signature — systemic" clause="ISO 9001 §10.2" action="View root-cause" onAction={() => onNav('quality')}>NCR-26-058 matches 2 prior bolt-torque NCRs. AI recommends the record-verification gate that previously cut recurrence to zero.</AINote>
          <AINote title="Inspection load" clause="ITP">3 client hold/witness points are open this week on P-211 and P-198 — schedule QC + client attendance to protect the schedule.</AINote>
        </div>
      </React.Fragment>}

      {d === 'compliance' && <React.Fragment>
        <KGrid>
          {DB.standards.map((s) => <Kpi key={s.code} label={s.code.split(':')[0]} value={s.score} icon="certificate" tone={s.score >= 90 ? 'ok' : 'warn'} delta={`${s.findings} finding${s.findings !== 1 ? 's' : ''}`} />)}
          <Kpi label="Obligations overdue" value={DB.legal.filter((l) => l.review <= DB.TODAY).length} icon="clipboard" tone="bad" />
          <Kpi label="Next audit" value="12" unit="d" icon="clock" tone="warn" delta="ISO 45001" />
        </KGrid>
        <ChartRow>
          <Panel title="ISO compliance scores"><DashHBars data={DB.standards.map((s, i) => ({ l: s.code.split(':')[0], v: s.score, c: s.score >= 90 ? '#22c55e' : '#f59e0b' }))} /></Panel>
          <Panel title="Audit findings by status"><DashSplit data={[{ l: 'Open', v: 14, c: '#ef4444' }, { l: 'In progress', v: 9, c: '#f59e0b' }, { l: 'Closed', v: 31, c: '#22c55e' }]} /></Panel>
          <Panel title="Compliance trend (6 mo)"><DashLine trend={{ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#2563eb', d: [78, 80, 81, 82, 83, 84] }] }} /></Panel>
        </ChartRow>
        <div style={{ marginTop: 16 }}><AINote title="Predicted audit findings — ISO 45001 in 12 days" clause="AIX · audit-readiness" action="Prioritise CAPAs" onAction={() => onNav('capa')}>Highest-likelihood findings: lifting-controls CAPA evidence and 7 expiring certifications. Closing both lifts the score 84 → 92 and clears the audit.</AINote></div>
      </React.Fragment>}

      {d === 'asset' && <React.Fragment>
        <KGrid>
          <Kpi label="Assets" value={as.length} icon="cpu" tone="info" />
          <Kpi label="Certified" value={Math.round(as.filter((a) => a.status === 'Certified').length / as.length * 100)} unit="%" icon="check-circle" tone="ok" />
          <Kpi label="Cert overdue" value={as.filter((a) => a.cert <= DB.TODAY).length} icon="alert" tone="bad" />
          <Kpi label="PM overdue" value={DB.pmOrders.filter((p) => p.status === 'Overdue').length} icon="wrench" tone="warn" />
          <Kpi label="Readiness" value={m.equipmentReadiness} unit="%" icon="trend" tone="ok" />
        </KGrid>
        <ChartRow>
          <Panel title="Assets by class"><DashSplit data={[{ l: 'Mobile units', v: 12, c: '#2563eb' }, { l: 'Lifting gear', v: 9, c: '#f59e0b' }, { l: 'Test equipment', v: 8, c: '#7a5bff' }, { l: 'Tools', v: 6, c: '#22c55e' }]} /></Panel>
          <Panel title="Certification status"><DashHBars data={[{ l: 'Valid', v: 24, c: '#22c55e' }, { l: 'Due ≤30d', v: 7, c: '#f59e0b' }, { l: 'Overdue', v: 4, c: '#ef4444' }]} /></Panel>
          <Panel title="PM vs breakdowns (6 mo)"><DashLine trend={{ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#2563eb', d: [3, 2, 4, 3, 5, 4] }, { c: '#ef4444', d: [1, 2, 1, 2, 1, 1] }] }} /></Panel>
        </ChartRow>
        <div style={{ marginTop: 16 }}><AINote title="Equipment compliance forecast" clause="AIX · forecast" action="Schedule renewals" onAction={() => onNav('assets')}>Hydrotest Pump HP-03 cert + 3rd-party inspection are overdue and block P-211; a lifting sling set is due in 9 days. Forecast: 3 more certs lapse within the mobilization window.</AINote></div>
      </React.Fragment>}

      {d === 'people' && <React.Fragment>
        <KGrid>
          <Kpi label="Training compliance" value={m.trainingCompliance} unit="%" icon="users" tone="ok" />
          <Kpi label="Competency gaps" value={DB.competency.filter((c) => c.gap).length} icon="alert" tone="warn" />
          <Kpi label="Certs expiring (30d)" value={m.expiringCerts} icon="certificate" tone="bad" />
          <Kpi label="Medical due" value={1} icon="helmet" tone="warn" />
          <Kpi label="Workforce" value={DB.staff.length * 18} icon="users" tone="info" delta="incl. contractors" />
        </KGrid>
        <ChartRow>
          <Panel title="Training compliance"><DashSplit data={[{ l: 'Compliant', v: 932, c: '#22c55e' }, { l: 'Due ≤7d', v: 176, c: '#f59e0b' }, { l: 'Overdue', v: 140, c: '#ef4444' }]} /></Panel>
          <Panel title="Compliance by department"><DashHBars data={[{ l: 'Operations', v: 82, c: '#2563eb' }, { l: 'Maintenance', v: 76, c: '#f59e0b' }, { l: 'HSE', v: 88, c: '#22c55e' }, { l: 'Engineering', v: 79, c: '#7a5bff' }, { l: 'Projects', v: 71, c: '#ef4444' }]} /></Panel>
          <Panel title="Compliance trend (6 mo)"><DashLine trend={{ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#22c55e', d: [72, 76, 76, 80, 81, 82] }] }} /></Panel>
        </ChartRow>
        <div style={{ marginTop: 16 }}><AINote title="Competency gaps before P-211 mobilization" clause="ISO 45001 §7.2" action="Build renewal plan" onAction={() => onNav('competency')}>2 N₂-unit operators lack a current Aramco CSTP and 1 medical fitness lapses in 14 days. AI has the renewal & training plan ready.</AINote></div>
      </React.Fragment>}

      {d === 'projects' && <React.Fragment>
        <KGrid>
          <Kpi label="Active projects" value={pj.filter((p) => p.stage !== 'Tender' && p.stage !== 'Closeout').length} icon="workflow" tone="info" />
          <Kpi label="Avg HSE score" value={Math.round(pj.filter((p) => p.hse).reduce((s, p) => s + p.hse, 0) / pj.filter((p) => p.hse).length)} icon="helmet" tone="ok" />
          <Kpi label="At-risk" value={pj.filter((p) => p.risk === 'High').length} icon="alert" tone="bad" />
          <Kpi label="Portfolio value" value={m.revenue} unit="SAR" icon="receipt" tone="info" />
          <Kpi label="Client satisfaction" value={m.clientSat} icon="trend" tone="ok" />
        </KGrid>
        <div className="card"><div className="card-head"><Icon name="workflow" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Portfolio</div><span className="spacer" /><Btn size="sm" onClick={() => onNav('projects')}>All projects</Btn></div>
          <table className="tbl"><thead><tr><th>Project</th><th>Stage</th><th>HSE</th><th>Progress</th><th>Risk</th></tr></thead><tbody>{pj.slice(0, 4).map((p) => <tr key={p.id} className="clickable" onClick={() => onOpen('project', p)}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{p.id}</td><td><Badge kind="info">{p.stage}</Badge></td><td><b style={{ color: scoreColor(p.hse) }}>{p.hse || '—'}</b></td><td style={{ width: 90 }}><Bar pct={p.progress} color="var(--primary-600)" /></td><td><Badge kind={p.risk === 'High' ? 'bad' : p.risk === 'Medium' ? 'warn' : 'ok'}>{p.risk}</Badge></td></tr>)}</tbody></table>
        </div>
        <div style={{ marginTop: 16 }}><AINote title="Mobilization risk — P-211" clause="AIX">7 certifications + 1 hydrotest pump cert lapse before deployment — resolve to protect schedule and HSE readiness.</AINote></div>
      </React.Fragment>}

      {d === 'fleet' && <React.Fragment>
        <KGrid>
          <Kpi label="Vehicles" value={DB.fleet.length} icon="truck" tone="info" />
          <Kpi label="Active journeys" value={DB.fleet.filter((f) => f.journey === 'Active' || f.journey === 'En route').length} icon="flag" tone="ok" />
          <Kpi label="Inspections due" value={DB.fleet.filter((f) => f.insp === 'Due').length} icon="alert" tone="warn" />
          <Kpi label="High fuel use" value={DB.fuel.filter((f) => f.flag !== 'Normal').length} icon="receipt" tone="warn" />
          <Kpi label="Unsafe events (wk)" value={2} icon="alert" tone="bad" />
        </KGrid>
        <ChartRow>
          <Panel title="Journey risk"><DashSplit data={[{ l: 'Low', v: DB.fleet.filter((f) => f.risk === 'Low').length || 6, c: '#22c55e' }, { l: 'Medium', v: DB.fleet.filter((f) => f.risk === 'Medium').length || 4, c: '#f59e0b' }, { l: 'High', v: DB.fleet.filter((f) => f.risk === 'High').length || 1, c: '#ef4444' }]} /></Panel>
          <Panel title="Fuel efficiency by vehicle"><DashHBars data={DB.fuel.slice(0, 5).map((f, i) => ({ l: f.id || ('VH-0' + (i + 1)), v: 70 + (i * 5) % 25, c: '#2563eb' }))} /></Panel>
          <Panel title="Harsh-driving events (6 mo)"><DashLine trend={{ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#ef4444', d: [5, 4, 6, 3, 4, 2] }] }} /></Panel>
        </ChartRow>
        <div style={{ marginTop: 16 }}><AINote title="Unsafe-driving & fatigue" clause="AIX" action="Plan journey (AI)" onAction={() => onNav('fleet')}>2 harsh-braking events on the Central route and a fatigue-window departure for VH-08 this week — score journeys before approval and review driver hours.</AINote></div>
      </React.Fragment>}
    </div>
  );
}

function AIModule({ onNav, onOpen }) {
  const [tab, setTab] = useState('ask');
  return (
    <div className="page page-wide rise">
      <PageHead title="Sentinel" sub="Conversational · cross-module reasoning · predictive · human-confirmed & logged" />
      <Tabs tabs={[['ask', 'Ask AI-COS'], ['actions', 'Recommendations'], ['predict', 'Predictions'], ['log', 'Decision log']]} tab={tab} setTab={setTab} />
      {tab === 'ask' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 300px', gap: 16, alignItems: 'start' }}>
          <div className="card" style={{ overflow: 'hidden' }}>
            <div className="card-head" style={{ background: 'linear-gradient(120deg, var(--ai-bg), #fff)' }}><span className="ai-badge-ico"><Icon name="sparkles" size={15} fill /></span><div className="h-sec" style={{ fontSize: 14 }}>Ask AI-COS</div><span className="spacer" /><Badge kind="ai">reasons across modules</Badge></div>
            <AIChat onNav={onNav} height={520} />
          </div>
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 10 }}>What I can reason about</div>
            {[['Incident investigation', 'helmet'], ['NCR root-cause & repeats', 'check-shield'], ['Audit readiness & findings', 'clipboard'], ['Competency & cert gaps', 'users'], ['Asset / cert forecasting', 'cpu'], ['SIMOPS & permit risk', 'flag']].map(([t, ic], i) => (
              <div key={i} className="row" style={{ gap: 9, padding: '7px 0', fontSize: 12.5 }}><span className="kpi-ico" style={{ width: 28, height: 28, background: 'var(--bg)', color: 'var(--ai)' }}><Icon name={ic} size={14} /></span>{t}</div>
            ))}
          </div>
        </div>
      )}
      {tab === 'actions' && (
        <div className="card">
          <div className="card-head"><Icon name="sparkles" size={16} style={{ color: 'var(--ai)' }} fill /><div className="h-sec">AI next-best-actions</div><span className="faint" style={{ fontSize: 11, marginLeft: 8 }}>continuously prioritised across the whole system by impact</span></div>
          <div className="card-body"><NextBestActions onNav={onNav} /></div>
        </div>
      )}
      {tab === 'predict' && <AIPredictions onNav={onNav} />}
      {tab === 'log' && (
        <div className="card">
          <div className="card-head"><Icon name="history" size={16} style={{ color: 'var(--ai)' }} /><div className="h-sec">AI decision log</div><span className="spacer" /><span className="faint" style={{ fontSize: 11.5 }}>Every suggestion + human outcome</span></div>
          <table className="tbl"><thead><tr><th>When</th><th>AI action</th><th>Detail</th><th>Outcome</th></tr></thead><tbody>
            {[['09:14', 'HIPO pattern flagged', '3rd at-height near-miss on P-204', 'Investigation launched'], ['08:40', 'Repeat NCR detected', 'NCR-26-058 matches 2 priors', 'Systemic CAPA drafted'], ['Yesterday', 'Cert-expiry forecast', '7 certs lapse before P-211', 'Renewal plan issued'], ['Yesterday', 'SIMOPS risk rise', 'SD-09 concurrent permits', 'Sequencing reviewed'], ['2d ago', 'Audit-findings prediction', 'ISO 45001 in 12 days', 'CAPA prioritised']].map((l, i) => (
              <tr key={i}><td className="faint mono" style={{ fontSize: 11.5 }}>{l[0]}</td><td><span className="row" style={{ gap: 7 }}><Icon name="sparkles" size={13} style={{ color: 'var(--ai)' }} /><b style={{ fontSize: 12.5 }}>{l[1]}</b></span></td><td className="faint" style={{ fontSize: 12 }}>{l[2]}</td><td><Badge kind="ok" icon="check">{l[3]}</Badge></td></tr>
            ))}
          </tbody></table>
        </div>
      )}
    </div>
  );
}

/* ===================== INCIDENTS (AI investigation) ================= */
/* ===================== INJURY BODY-MAP ============================== */
const SEV_META = { 1: { c: '#22c55e', n: 'Minor' }, 2: { c: '#eab308', n: 'Moderate' }, 3: { c: '#f97316', n: 'Serious' }, 4: { c: '#ef4444', n: 'Major' } };
const SEV_NEUTRAL = '#dbe2ec';
// anchor points on the front body figure (viewBox 0 0 338.64 839.2). 'R' = subject's right = viewer-left.
const BODY_ANCHORS_IMG = {
  'Head': [169, 46], 'Neck': [169, 110],
  'Shoulder|R': [110, 162], 'Shoulder|L': [228, 162],
  'Back': [169, 235], 'Hip': [169, 345],
  'Arm|R': [86, 330], 'Arm|L': [253, 330],
  'Hand|R': [60, 645], 'Hand|L': [280, 645],
  'Leg|R': [142, 560], 'Leg|L': [197, 560],
  'Knee|R': [146, 660], 'Knee|L': [193, 660],
  'Foot|R': [150, 815], 'Foot|L': [189, 815],
};
function InjuryBodyMap() {
  const [win, setWin] = useState('12m');
  const cutoff = DB.injuryWindows[win];
  const data = DB.injuries.filter((i) => i.days <= cutoff);
  const agg = {};
  data.forEach((i) => { const k = i.part + '|' + i.side; (agg[k] = agg[k] || { part: i.part, side: i.side, n: 0, worst: 1 }); agg[k].n++; agg[k].worst = Math.max(agg[k].worst, i.sev); });
  const aggList = Object.entries(agg).map(([k, v]) => ({ k, ...v }));
  const total = data.length;
  const recordable = data.filter((i) => i.recordable).length;
  const lost = data.reduce((s, i) => s + i.lost, 0);
  const sevCount = { 1: 0, 2: 0, 3: 0, 4: 0 }; data.forEach((i) => sevCount[i.sev]++);
  const top = [...aggList].sort((a, b) => b.n - a.n).slice(0, 9);
  const maxN = Math.max(1, ...aggList.map((r) => r.n));
  // body-part anchors (in the body image's 338×839 viewBox)
  const CENTER = 169, CW = 138, CH = 34;
  const injured = aggList.map((a) => ({ ...a, anchor: BODY_ANCHORS_IMG[a.part + '|' + a.side] || BODY_ANCHORS_IMG[a.part] })).filter((a) => a.anchor);
  const colL = injured.filter((a) => a.anchor[0] < CENTER).sort((a, b) => a.anchor[1] - b.anchor[1]);
  const colR = injured.filter((a) => a.anchor[0] >= CENTER).sort((a, b) => a.anchor[1] - b.anchor[1]);
  const place = (list, col) => list.map((a, i) => ({ ...a, cx: col === 'L' ? -148 : 350, cy: 30 + i * (770 / Math.max(1, list.length)), col }));
  const chips = [...place(colL, 'L'), ...place(colR, 'R')];
  const win_btns = ['30d', '90d', '6m', 'YTD', '12m'];
  return (
    <div className="card" style={{ overflow: 'hidden' }}>
      <div className="card-head" style={{ gap: 10, alignItems: 'center' }}>
        <Icon name="helmet" size={16} style={{ color: 'var(--primary-600)' }} />
        <div className="h-sec">Injury body-map — aggregate</div>
        <span className="faint" style={{ fontSize: 11.5 }}>All sites · {win === '12m' ? '12-month' : win} window</span>
        <span className="spacer" />
        <div className="row" style={{ gap: 2, background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 9, padding: 2 }}>
          {win_btns.map((w) => <button key={w} onClick={() => setWin(w)} style={{ border: 'none', cursor: 'pointer', borderRadius: 7, padding: '5px 10px', fontSize: 11.5, fontWeight: 650, fontFamily: 'inherit', background: win === w ? 'var(--primary-600)' : 'transparent', color: win === w ? '#fff' : 'var(--text-2)' }}>{w}</button>)}
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1.55fr 1fr', gap: 16, padding: 18 }}>
        {/* FRONT body with body-part callouts */}
        <div>
          <svg viewBox="-150 -8 622 858" style={{ width: '100%', height: 'auto', maxHeight: 560 }}>
            <defs>
              {[1, 2, 3, 4].map((s) => <radialGradient key={s} id={`ig${s}`}><stop offset="0%" stopColor={SEV_META[s].c} stopOpacity="0.85" /><stop offset="55%" stopColor={SEV_META[s].c} stopOpacity="0.35" /><stop offset="100%" stopColor={SEV_META[s].c} stopOpacity="0" /></radialGradient>)}
            </defs>
            <text x="-126" y="34" fontSize="17" fontWeight="700" fill="var(--text-3)">R</text>
            <text x="452" y="34" fontSize="17" fontWeight="700" fill="var(--text-3)" textAnchor="end">L</text>
            {/* body image */}
            <g dangerouslySetInnerHTML={{ __html: window.BODY_FRONT }} />
            {/* severity glow over each injured part */}
            {injured.map((a) => <circle key={'g' + a.k} cx={a.anchor[0]} cy={a.anchor[1]} r={26} fill={`url(#ig${a.worst})`} />)}
            {/* connector line + dot */}
            {chips.map((c) => <g key={'l' + c.k}><line x1={c.col === 'L' ? c.cx + CW : c.cx} y1={c.cy + CH / 2} x2={c.anchor[0]} y2={c.anchor[1]} stroke={SEV_META[c.worst].c} strokeWidth="1.4" strokeOpacity="0.65" /><circle cx={c.anchor[0]} cy={c.anchor[1]} r="5" fill={SEV_META[c.worst].c} stroke="#fff" strokeWidth="1.8" /></g>)}
            {/* count chip */}
            {chips.map((c) => (
              <g key={'c' + c.k}>
                <rect x={c.cx} y={c.cy} width={CW} height={CH} rx="8" fill={SEV_META[c.worst].c} />
                <text x={c.cx + 17} y={c.cy + 23} fontSize="19" fontWeight="800" fill={c.worst >= 3 ? '#fff' : '#16233a'} textAnchor="middle">{c.n}</text>
                <text x={c.cx + 33} y={c.cy + 22.5} fontSize="14" fontWeight="700" fill={c.worst >= 3 ? '#fff' : '#16233a'} letterSpacing="0.3">{(c.part + ' ' + c.side).trim().toUpperCase()}</text>
              </g>
            ))}
          </svg>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div className="row" style={{ gap: 11, flexWrap: 'wrap' }}>
            {[1, 2, 3, 4].map((s) => <span key={s} className="row" style={{ gap: 5, fontSize: 10.5, color: 'var(--text-2)' }}><span style={{ width: 11, height: 11, borderRadius: 3, background: SEV_META[s].c }} />{SEV_META[s].n}</span>)}
            <span className="row" style={{ gap: 5, fontSize: 10.5, color: 'var(--text-3)' }}><span style={{ width: 11, height: 11, borderRadius: 3, background: SEV_NEUTRAL }} />No injury</span>
          </div>
          <div className="eyebrow" style={{ fontSize: 10.5 }}>Summary · {win === '12m' ? '12M' : win.toUpperCase()}</div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            {[['RECORDABLE', recordable, 'injuries', 'var(--text)'], ['LOST-TIME', lost, 'days lost', 'var(--warn)'], ['TRIR', DB.mgmt.trir, 'target ≤1.30', 'var(--ok)'], ['LTIFR', DB.mgmt.ltifr, '↓ 12% YoY', 'var(--ok)']].map(([l, v, s, col]) => (
              <div key={l} style={{ background: 'var(--surface-2)', border: '1px solid var(--border)', borderRadius: 12, padding: '12px 13px' }}>
                <div className="eyebrow" style={{ fontSize: 9.5 }}>{l}</div>
                <div style={{ fontSize: 25, fontWeight: 800, color: col, lineHeight: 1.2, marginTop: 4 }}>{v}</div>
                <div className="faint" style={{ fontSize: 11 }}>{s}</div>
              </div>
            ))}
          </div>
          <div className="eyebrow" style={{ fontSize: 10.5, marginTop: 2 }}>Severity mix</div>
          <div style={{ display: 'flex', height: 9, borderRadius: 6, overflow: 'hidden', background: 'var(--surface-2)' }}>
            {[1, 2, 3, 4].map((s) => sevCount[s] > 0 && <div key={s} title={`${SEV_META[s].n} · ${sevCount[s]}`} style={{ width: `${(sevCount[s] / Math.max(1, total)) * 100}%`, background: SEV_META[s].c }} />)}
          </div>
          <div className="row" style={{ justifyContent: 'space-between' }}><span className="eyebrow" style={{ fontSize: 10.5 }}>Top body parts</span><span className="faint" style={{ fontSize: 11 }}>{total} injuries</span></div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
            {top.map((r) => (
              <div key={r.k} className="row" style={{ gap: 10, alignItems: 'center' }}>
                <span style={{ width: 70, fontSize: 11.5, color: 'var(--text-2)' }}>{(r.part + ' ' + r.side).trim()}</span>
                <div style={{ flex: 1, height: 7, borderRadius: 4, background: 'var(--surface-2)' }}><div style={{ width: `${(r.n / maxN) * 100}%`, height: '100%', borderRadius: 4, background: SEV_META[r.worst].c }} /></div>
                <span style={{ width: 14, textAlign: 'right', fontSize: 12, fontWeight: 700, color: 'var(--text)' }}>{r.n}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}
/* Incident / Accident Investigation Report — fields per PD-IMS-L4-F-14 */
function openIncidentReport() {
  window.openAIAssist({
    title: 'Incident / Accident Investigation Report', sub: 'Form PD-IMS-L4-F-14 · Sentinel live-classifies severity and guides the investigation', icon: 'helmet', width: 920, compute: incidentCompute, submitLabel: 'Submit report', done: 'Incident logged · AI investigation & CAPA draft ready',
    fields: [
      { type: 'section', label: 'Initial notification', hint: 'Quick first report — PD-IMS-L4-F-13' },
      { key: 'stream', label: 'Incident type', type: 'radio', options: ['HSE / Safety', 'Quality', 'Asset / Property Damage', 'Environmental'] },
      { key: 'condition', label: 'Condition', type: 'radio', options: ['Incident', 'Near miss', 'Accident', 'Hazard'], half: true },
      { key: 'seriousness', label: 'Seriousness', type: 'radio', options: ['Non-serious', 'Serious'], half: true },
      { key: 'siteName', label: 'Name of site', type: 'text', placeholder: 'e.g. Meridian Offshore', half: true },
      { key: 'location', label: 'Location on site', type: 'text', placeholder: 'e.g. P-204 · V-204 platform', half: true },
      { key: 'datetime', label: 'Time & date of incident', type: 'text', placeholder: 'e.g. 14 Jun 2026 · 09:40', half: true },
      { key: 'reportedBy', label: 'Reported by', type: 'text', placeholder: 'Name · role', half: true },

      { type: 'section', label: 'General information', hint: 'Investigation — PD-IMS-L4-F-14' },
      { key: 'reportNo', label: 'Investigation report no.', type: 'text', value: 'INV-026-2026', half: true },
      { key: 'conductedBy', label: 'Investigation conducted by', type: 'text', placeholder: 'Name · role', half: true },
      { key: 'project', label: 'Project', type: 'select', options: DB.projects.map((p) => p.id + ' · ' + p.name) },

      { type: 'section', label: 'Incident classification' },
      { key: 'classHS', label: 'Health & Safety', type: 'checks', show: (v) => v.stream === 'HSE / Safety', options: ['Lost Time Injury', 'Fatality', 'Permanent Total Disability', 'Permanent Partial Disability', 'Lost Workday Case', 'Serious Injury', 'Serious Occupational Illness / Disease', 'Serious Dangerous Occurrence', 'Restricted Workday Case', 'Medical Treatment Case', 'First Aid Injury', 'Equipment / Property Damage', 'Near Miss', 'Other'] },
      { key: 'classQual', label: 'Quality non-conformity', type: 'checks', show: (v) => v.stream === 'Quality', options: ['Documentation', 'Process deviation', 'Material / Supplier', 'Workmanship', 'Dimensional', 'Welding', 'Coating / Painting', 'Calibration', 'Client complaint', 'Repeat NCR', 'Other'] },
      { key: 'qualNcr', label: 'Raise / link NCR', type: 'radio', show: (v) => v.stream === 'Quality', options: ['Raise new NCR', 'Link existing NCR', 'None'], half: true },
      { key: 'classAsset', label: 'Asset / property damage type', type: 'checks', show: (v) => v.stream === 'Asset / Property Damage', options: ['Mechanical', 'Electrical', 'Structural', 'Corrosion / Erosion', 'Impact / Collision', 'Overload', 'Dropped object', 'Fire / Heat', 'Pressure / Leak', 'Vehicle', 'Other'] },
      { key: 'assetId', label: 'Affected asset', type: 'select', show: (v) => v.stream === 'Asset / Property Damage', options: DB.assets.slice(0, 12).map((a) => a.id + ' · ' + a.name) },
      { key: 'assetStatus', label: 'Asset status after event', type: 'radio', show: (v) => v.stream === 'Asset / Property Damage', options: ['Operational', 'Degraded', 'Out of service'], half: true },
      { key: 'damageCost', label: 'Estimated repair / replacement', type: 'text', show: (v) => v.stream === 'Asset / Property Damage', placeholder: 'e.g. USD 18,000', half: true },
      { key: 'classEnv', label: 'Environmental', type: 'checks', show: (v) => v.stream === 'Environmental', options: ['Spill / Release to Land', 'Release / Discharge to Atmosphere', 'Accidental Harm to Animal Species', 'Spill / Release to Water or Groundwater', 'Unauthorized Vegetation Removal / Harm', 'Damage to Heritage Site / Item', 'Other'] },
      { key: 'reportable', label: 'Reportable to legal authorities?', type: 'radio', options: ['No', 'Yes'], half: true },

      { type: 'section', label: 'Description' },
      { key: 'description', label: 'Description of the incident', type: 'textarea', rows: 4, placeholder: 'Sequence of events — what happened, where, who was involved…' },
      { key: 'immediateAction', label: 'Action taken immediately after the incident', type: 'textarea', placeholder: 'Make-safe, first aid, isolation, notifications…' },

      { type: 'section', label: 'Injured person detail', hint: 'Complete only if someone was injured' },
      { key: 'anyInjuries', label: 'Has anyone sustained injuries?', type: 'radio', options: ['No', 'Yes'], half: true },
      { key: 'injuredName', label: 'Name', type: 'text', half: true, show: (v) => v.anyInjuries === 'Yes' },
      { key: 'designation', label: 'Designation', type: 'text', half: true, show: (v) => v.anyInjuries === 'Yes' },
      { key: 'personType', label: 'Employee / visitor / contractor', type: 'select', options: ['Employee', 'Visitor', 'Contractor'], half: true, show: (v) => v.anyInjuries === 'Yes' },
      { key: 'gender', label: 'Gender', type: 'select', options: ['Male', 'Female'], half: true, show: (v) => v.anyInjuries === 'Yes' },
      { key: 'service', label: 'Period of service', type: 'text', placeholder: 'e.g. 3 yrs', half: true, show: (v) => v.anyInjuries === 'Yes' },
      { key: 'phone', label: 'Contact phone number', type: 'text', half: true, show: (v) => v.anyInjuries === 'Yes' },
      { key: 'disposition', label: 'Disposition of injured person', type: 'checks', show: (v) => v.anyInjuries === 'Yes', options: ['Sent to Hospital', 'Detained in Hospital', 'Granted rest days', 'Returned to Work', 'Other'] },
      { key: 'injuryLocation', label: 'Location of injury', type: 'checks', show: (v) => v.anyInjuries === 'Yes', options: ['Head', 'Face', 'Eyes', 'Trunk', 'Arms', 'Hands', 'Legs', 'Feet', 'Other'] },
      { key: 'injuryNature', label: 'Nature of injury', type: 'checks', show: (v) => v.anyInjuries === 'Yes', options: ['Cut / Laceration / Open Wound', 'Bruise', 'Puncture', 'Dislocation', 'Fracture', 'Burn', 'Strain / Sprain', 'Abrasion', 'Foreign body in eye', 'Electrical Shock', 'Contusion', 'Heat-related Illness', 'Poisoning / Toxic Effect', 'Skin Irritation / Disease', 'Amputation', 'Hearing Loss', 'Crush / Internal Injury', 'Bite / Sting', 'MSD', 'Stress', 'Other'] },
      { key: 'equipmentDamage', label: 'Equipment / material damage description', type: 'textarea', show: (v) => v.stream === 'Asset / Property Damage' || v.anyInjuries === 'Yes', placeholder: 'Asset, extent of damage, estimated value…' },

      { type: 'section', label: 'Witness detail' },
      { key: 'witnessName', label: 'Witness name', type: 'text', half: true },
      { key: 'witnessPhone', label: 'Witness contact number', type: 'text', half: true },
      { key: 'witnessStatement', label: 'Witness statement attached', type: 'radio', options: ['No', 'Yes'], half: true },

      { type: 'section', label: 'Immediate causes' },
      { key: 'unsafeAct', label: 'Unsafe act', type: 'checks', options: ['Operating without authority', 'Failure to warn', 'Operating at improper speed', 'Removing / defeating safety devices', 'Using equipment improperly', 'Failure to use PPE properly', 'Improper lifting', 'Improper loading', 'Improper placement', 'Improper position for task', 'Servicing equipment in operation', 'Horseplay', 'Violation / Taking shortcuts', 'Lack of awareness / knowledge', 'Failure to secure', 'Other'] },
      { key: 'unsafeCondition', label: 'Unsafe condition', type: 'checks', options: ['Inadequate guards or barriers', 'Inadequate / improper PPE', 'Defective tools / equipment / materials', 'Congestion or restricted action', 'Inadequate warning system', 'Fire & explosion hazards', 'Poor housekeeping / disorder', 'Hazardous environment (gas, dust, fumes)', 'High / low temperature exposure', 'Inadequate ventilation', 'Noise exposure', 'Radiation exposure', 'Vehicle condition', 'Driver condition', 'Bad weather', 'Equipment failure', 'Other'] },

      { type: 'section', label: 'Root causes' },
      { key: 'personalFactor', label: 'Personal factor', type: 'checks', options: ['Physical capability', 'Skill level', 'Behaviour', 'Lack of motivation', 'Mental stress', 'Mental state', 'Human error', 'Other'] },
      { key: 'systemFactor', label: 'System factor', type: 'checks', options: ['Inadequate leadership / supervision', 'Inadequate planned inspection', 'Inadequate work procedures', 'Inadequate tools / equipment', 'Inadequate risk assessment', 'Inadequate contractor management', 'Inadequate emergency response plan', 'Inadequate incident investigation', 'Inadequate management of change', 'Inadequate design', 'Inadequate communication', 'Inadequate purchasing', 'Other'] },
      { key: 'rootCause', label: 'Incident root cause (narrative)', type: 'textarea', placeholder: 'Sentinel will draft this from the 5-Why / TapRooT analysis on submit…' },

      { type: 'section', label: 'Corrective action & follow-up' },
      { key: 'corrective', label: 'Corrective action to prevent recurrence', type: 'textarea', placeholder: 'Action · responsibility · target date (one per line)' },
      { key: 'cost', label: 'Estimated incident cost (total)', type: 'text', placeholder: 'Injury · legal · productivity · asset · penalty', half: true },
      { key: 'reviewRA', label: 'Risk assessment reviewed', type: 'radio', options: ['Yes', 'No'], half: true },
      { key: 'trainingReq', label: 'Training required', type: 'radio', options: ['No', 'Yes'], half: true },
      { key: 'status', label: 'Incident & log status', type: 'radio', options: ['Open', 'On-going', 'Closed'], half: true },
      { key: 'additional', label: 'Any additional information / attachments', type: 'textarea', placeholder: 'Photos, sketches, statements, supporting documents…' },
    ],
    onSave: (v) => {
      const hs = v.classHS || [];
      const hipo = hs.some((x) => /Fatality|Permanent Total|Lost Time|Serious/.test(x)) || v.seriousness === 'Serious';
      const sev = hs.some((x) => /Fatality|Permanent Total|Lost Time/.test(x)) || v.seriousness === 'Serious' ? 'High'
        : hs.some((x) => /Restricted|Medical Treatment|Serious|Partial/.test(x)) || (v.classEnv || []).length ? 'Medium' : 'Low';
      const catOf = v.stream === 'Quality' ? 'Quality' : v.stream === 'Environmental' ? 'Environmental' : v.stream === 'Asset / Property Damage' ? 'Asset' : (v.injuryLocation && v.injuryLocation.includes('Hands') ? 'Hand injury' : 'Lifting & rigging');
      const title = (v.description || '').slice(0, 70) || (v.condition || 'Incident') + ' at ' + (v.location || v.siteName || 'site');
      const detail = {
        stream: v.stream, condition: v.condition, seriousness: v.seriousness, siteName: v.siteName, location: v.location, datetime: v.datetime, reportedBy: v.reportedBy, reportNo: v.reportNo, conductedBy: v.conductedBy,
        classHS: hs, classQual: v.classQual, classEnv: v.classEnv, classAsset: v.classAsset, reportable: v.reportable, description: v.description, immediate: v.immediateAction ? [v.immediateAction] : undefined,
        anyInjuries: v.anyInjuries, injuredPerson: v.injuredName, designation: v.designation, personType: v.personType, gender: v.gender, service: v.service, phone: v.phone, disposition: v.disposition, injuryLocation: v.injuryLocation, injuryNature: v.injuryNature, equipmentDamage: v.equipmentDamage,
        witnessName: v.witnessName, witnessPhone: v.witnessPhone, unsafeAct: v.unsafeAct, unsafeCondition: v.unsafeCondition, personalFactor: v.personalFactor, systemFactor: v.systemFactor, rootCause: v.rootCause, corrective: v.corrective, cost: v.cost, reviewRA: v.reviewRA, trainingReq: v.trainingReq, additional: v.additional,
      };
      const dstr = (v.datetime || '').split('·')[0].trim();
      const dparsed = dstr ? new Date(dstr) : null;
      const date = dparsed && !isNaN(dparsed) ? dparsed : DB.D(0);
      dbAdd('incidents', { id: _seq(DB.incidents, 'INC-26-', 31), type: v.condition === 'Near miss' ? 'Near miss' : v.stream === 'Environmental' ? 'Environmental' : v.condition || 'Incident', hipo, title, project: (v.project || 'P-204').split(' · ')[0], date, severity: sev, status: v.status === 'Closed' ? 'Closed' : 'Reported', capa: null, cat: catOf, detail });
    },
  });
}
function IncidentsModule({ onNav, onOpen, defaultTab }) {
  const [tab, setTab] = useState(defaultTab || 'register');
  const [page, setPage] = useState(1);
  const [q, setQ] = useState('');
  const perPage = 10;
  const all = DB.incidents;
  const filtered = all.filter((i) => !q || (i.id + ' ' + i.title + ' ' + i.type + ' ' + i.cat + ' ' + i.project).toLowerCase().includes(q.toLowerCase()));
  const pageRows = filtered.slice((page - 1) * perPage, page * perPage);
  return (
    <div className="page page-wide rise">
      <PageHead title="Incident Management" sub="Reporting · investigation · CAPA — ISO 45001 §10.2, with AI root-cause">
        <DateFilter />
        <DocActions label="incident register" />
        <Btn variant="primary" icon="plus" onClick={() => openIncidentReport()}>Report incident</Btn>
      </PageHead>
      <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(4,1fr)', marginBottom: 16 }}>
        <Kpi label="Open incidents" value={all.filter((i) => i.status !== 'Closed').length} icon="helmet" tone="warn" />
        <Kpi label="High-potential (HIPO)" value={all.filter((i) => i.hipo).length} icon="alert" tone="bad" />
        <Kpi label="LTI-free days" value={DB.mgmt.ltiFreeDays} icon="check-circle" tone="ok" />
        <Kpi label="TRIR" value={DB.mgmt.trir} icon="trend" tone="ok" />
      </div>
      <Tabs tabs={[['register', 'Incident & near-miss register'], ['dashboard', 'Dashboard'], ['bodymap', 'Injury body-map']]} tab={tab} setTab={setTab} />
      {tab === 'dashboard' && (<React.Fragment>
        <div style={{ marginBottom: 14 }}><AINote title="Sentinel — incident intelligence" clause="ISO 45001 §10.2" action="Open AI investigation" onAction={() => onOpen('incident', DB.incidents[0])}>Near-miss frequency on lifting/at-height tasks is up 18% this window. AI flags Hand R as the dominant injury locus and forecasts elevated dropped-object risk on P-204 — recommends a targeted toolbox talk + tool-tethering audit before the shutdown lift.</AINote></div>
        <div style={{ display: 'grid', gridTemplateColumns: '1.3fr 1fr 1fr', gap: 14, marginBottom: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Incident trend · 6 months</div><div className="row" style={{ gap: 12, flexWrap: 'wrap', margin: '0 0 4px' }}>{DB.dash.trend.series.map((s) => <span key={s.k} className="row" style={{ gap: 5, fontSize: 10, color: 'var(--text-2)' }}><span style={{ width: 14, height: 3, borderRadius: 2, background: s.c }} />{s.k}</span>)}</div><DashLine trend={DB.dash.trend} /></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Incidents by type</div><div className="row" style={{ gap: 10, alignItems: 'center' }}><DashDonut data={DB.dash.byType} size={116} /><DashLegend data={DB.dash.byType} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Incidents by location</div><DashHBars data={DB.dash.byLocation} /></div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 14, alignItems: 'start' }}>
          <InjuryBodyMap />
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Top 5 root causes</div><DashHBars data={DB.dash.rootCauses} /></div>
        </div>
      </React.Fragment>)}
      {tab === 'register' && (
        <div className="card">
          <div className="card-head" style={{ flexWrap: 'wrap', gap: 10 }}>
            <Icon name="helmet" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Incident & near-miss register</div>
            <span className="spacer" />
            <div className="row" style={{ gap: 7, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 9, padding: '0 10px', height: 34 }}><Icon name="search" size={14} style={{ color: 'var(--text-3)' }} /><input value={q} onChange={(e) => { setQ(e.target.value); setPage(1); }} placeholder="Search incidents…" style={{ border: 'none', outline: 'none', background: 'transparent', fontSize: 12.5, fontFamily: 'inherit', width: 160 }} /></div>
            <Btn icon="filter" size="sm" onClick={() => window.toast('Filters applied', 'info')}>Filter</Btn>
            <Btn icon="download" size="sm" onClick={() => window.toast('Register exported (XLSX)', 'info')}>Export</Btn>
          </div>
          <table className="tbl">
            <thead><tr><th>Ref</th><th>Type</th><th>Description</th><th>Project</th><th>Date</th><th>Severity</th><th>CAPA</th><th>Status</th><th></th></tr></thead>
            <tbody>{pageRows.map((x) => (
              <tr key={x.id} className="clickable" onClick={() => onOpen('incident', x)}>
                <td className="mono cell-strong" style={{ fontSize: 11.5 }}>{x.id}{x.hipo && <span className="badge b-bad" style={{ marginLeft: 6, fontSize: 9.5 }}>HIPO</span>}</td>
                <td><Badge kind={x.type === 'Incident' ? 'bad' : 'warn'}>{x.type}</Badge></td>
                <td style={{ fontSize: 12.5, maxWidth: 260 }}>{x.title}</td>
                <td className="mono faint" style={{ fontSize: 11.5 }}>{x.project}</td>
                <td className="faint">{DB.fmt(x.date)}</td>
                <td><Badge kind={sevKind(x.severity)}>{x.severity}</Badge></td>
                <td>{x.capa ? <span className="mono" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{x.capa}</span> : <span className="faint">—</span>}</td>
                <td><Badge kind={x.status === 'Closed' ? 'ok' : x.status === 'Investigation' ? 'warn' : 'info'} dot={x.status !== 'Closed'}>{x.status}</Badge></td>
                <td><RowActions onView={() => onOpen('incident', x)} onEdit={() => openIncidentForm(x)} onDelete={() => dbRemove('incidents', 'id', x.id)} /></td>
              </tr>
            ))}</tbody>
          </table>
          <div style={{ padding: '0 14px 14px' }}><Pagination page={page} perPage={perPage} total={filtered.length} onPage={setPage} /></div>
        </div>
      )}
      {tab === 'bodymap' && <InjuryBodyMap />}
      {tab === 'insights' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <AINote title="AI body-map insight — Hand R cluster" clause="ISO 45001 §10.2" action="Open AI investigation" onAction={() => onOpen('incident', DB.incidents[0])}>Hand R is the dominant injury locus (5 events, 1 major) — AI correlates it with manual flange-handling on P-198 / P-204. Recommended: cut-resistant glove upgrade, tool-tethering and a focused toolbox talk. INC-26-031 remains the 3rd at-height near-miss this quarter — open the investigation to run the 5-Why / TapRooT and draft the CAPA.</AINote>
          <AINote title="Predictive — at-height exposure rising" clause="AIX">Near-miss frequency on lifting/at-height tasks is up 18% this window. AI forecasts elevated dropped-object risk on P-204 next week and recommends a targeted toolbox talk + tool-tethering audit before the shutdown lift.</AINote>
        </div>
      )}
    </div>
  );
}
/* ---------- incident detail helpers ---------- */
const INC_STEPS = ['Reported', 'Reviewed', 'Investigation', 'Root Cause', 'Actions', 'Verification', 'Closed'];
const INC_STEPIDX = { New: 0, Reported: 0, Review: 1, Reviewed: 1, Investigation: 2, 'Root cause': 3, CAPA: 4, Action: 4, Actions: 4, Verification: 5, Closed: 6 };
const INJ_XY = { leg: [198, 735], knee: [196, 660], foot: [189, 815], hand: [60, 645], arm: [86, 330], head: [169, 46], back: [169, 235], shoulder: [110, 162] };
/* Per-category incident detail templates — gives every incident a distinct, realistic story */
const INC_TPL = {
  Lifting: { loc: 'Main Plant — Laydown Area 1', act: 'Pipe handling / lifting', equip: 'Overhead crane (40 t)', desc: 'During a tandem lift the 6 m pipe section swung out of control and struck the rigger\'s left leg as it was positioned at the laydown area. The tag line was not in use and no exclusion zone had been set.', inj: { injury: 'Fracture — left tibia', xy: 'leg', treat: 'Hospitalized', days: 15, desig: 'Rigger' }, whys: [['Why was the rigger struck?', 'Load swung uncontrolled into the line of fire'], ['Why did the load swing?', 'No tag line used to control the load'], ['Why was no tag line used?', 'Rigging plan not enforced at the worksite'], ['Why was the plan not enforced?', 'Supervisor not present during the lift'], ['Why was supervision absent?', 'Lift not classed as critical in the permit']], root: 'Inadequate lift supervision + tag-line/exclusion-zone controls not enforced for a non-critical-classed lift.', capa: [['Mandatory tag line + exclusion zone for all lifts > 1 t', 'Q-001', 'Completed'], ['Re-class pipe lifts as critical lifts in PTW', 'Q-006', 'In Progress'], ['Rigger competency re-assessment', 'Q-002', 'Open']] },
  Environmental: { loc: 'Hydrotest Bay — P-187', act: 'Hydrostatic testing', equip: 'Hydrotest pump HP-02', desc: 'During hydrotest depressurisation, ~200 L of test water containing corrosion inhibitor overflowed the bund and reached the storm drain channel before being contained with absorbent booms.', inj: null, whys: [['Why did water reach the drain?', 'Bund capacity exceeded during discharge'], ['Why was the bund exceeded?', 'Discharge rate not controlled'], ['Why was discharge uncontrolled?', 'No discharge procedure for inhibited water'], ['Why no procedure?', 'Environmental aspect not assessed for this task'], ['Why not assessed?', 'Task added to scope without MOC']], root: 'Inhibited-water discharge not covered by an environmental aspect assessment or controlled-discharge procedure.', capa: [['Controlled-discharge procedure for test water', 'Q-004', 'Completed'], ['Add task to environmental aspects register', 'Q-001', 'Completed'], ['Bund-capacity check before hydrotest', 'Q-006', 'Closed']] },
  Fleet: { loc: 'Camp access road — P-198', act: 'Vehicle reversing / manoeuvre', equip: 'Crew bus (V-1042)', desc: 'A crew bus made contact with a stationary skip while reversing in the camp laydown. No injuries; minor damage to the rear bumper. No banksman was used and the reversing alarm was found inoperative.', inj: null, whys: [['Why did contact occur?', 'Driver did not see the skip while reversing'], ['Why not seen?', 'No banksman and obstructed mirror view'], ['Why no banksman?', 'Reversing without a banksman tolerated on site'], ['Why tolerated?', 'Journey-management rule not enforced'], ['Why not enforced?', 'No reversing-control standard communicated']], root: 'Reversing-control standard (banksman / alarm check) not enforced under journey management.', capa: [['Banksman mandatory for all reversing manoeuvres', 'Q-006', 'Completed'], ['Daily reversing-alarm pre-use check', 'Q-002', 'In Progress'], ['Toolbox talk — reversing controls', 'Q-001', 'Closed']] },
  'Hand injury': { loc: 'Workshop — flange bay, P-198', act: 'Flange make-up / bolt tensioning', equip: 'Hydraulic torque wrench', desc: 'While guiding a flange into position the technician\'s left hand was caught between the flange face and the spool, causing a laceration requiring sutures. Gloves were standard issue, not cut-resistant.', inj: { injury: 'Laceration — left hand', xy: 'hand', treat: 'First aid + sutures', days: 0, desig: 'Pipe fitter' }, whys: [['Why was the hand lacerated?', 'Hand placed in pinch point between flange and spool'], ['Why in the pinch point?', 'Manual guiding without alignment tools'], ['Why no alignment tools?', 'Flange alignment kit not available at the bay'], ['Why unavailable?', 'Not specified in the task risk assessment'], ['Why not specified?', 'Generic JSA used, not task-specific']], root: 'Generic JSA omitted alignment tools and cut-resistant gloves for flange make-up — pinch-point control missing.', capa: [['Issue flange alignment kits + cut-5 gloves', 'Q-002', 'Completed'], ['Task-specific JSA for flange make-up', 'Q-001', 'Completed'], ['Pinch-point awareness toolbox talk', 'Q-006', 'Closed']] },
  'Confined space': { loc: 'N₂ purge — Vessel V-201, P-204', act: 'Confined-space entry / nitrogen purge', equip: 'N₂ trailer + gas detector', desc: 'During preparation for a nitrogen purge, an entrant briefly entered the vessel before the atmosphere was confirmed. A personal gas monitor alarmed at low O₂ (18.1%) and the entrant withdrew immediately. No exposure occurred.', inj: null, whys: [['Why did the entrant enter early?', 'Atmosphere not confirmed before entry'], ['Why not confirmed?', 'Gas test sign-off step skipped'], ['Why skipped?', 'Entry controller not at the portal'], ['Why absent?', 'Single person covering two entries'], ['Why understaffed?', 'Confined-space standby ratio not planned']], root: 'Confined-space entry controller spread across two entries — atmosphere-confirmation gate bypassed.', capa: [['Dedicated entry controller per confined space', 'Q-001', 'Completed'], ['Hard gas-test gate in CSE permit', 'Q-004', 'In Progress'], ['CSE rescue drill before next campaign', 'Q-006', 'Open']] },
};
function incidentFull(x) {
  const sev = { High: { L: 4, S: 4, score: 16, rating: 'High' }, Medium: { L: 3, S: 3, score: 9, rating: 'Medium' }, Low: { L: 2, S: 2, score: 4, rating: 'Low' } }[x.severity] || { L: 3, S: 3, score: 9, rating: 'Medium' };
  const tpl = INC_TPL[x.cat] || INC_TPL.Lifting;
  const isLTI = !!(tpl.inj && tpl.inj.days >= 1);
  const reporters = { Lifting: ['Ahmed Khan', 'Operator'], Environmental: ['Daniel Costa', 'Field engineer'], Fleet: ['Salem Al-Otaibi', 'Field supervisor'], 'Hand injury': ['Ravi Kumar', 'Pipe fitter'], 'Confined space': ['Imran Qureshi', 'CSE attendant'] };
  const rep = reporters[x.cat] || ['Ahmed Khan', 'Operator'];
  const hh = (8 + (x.id.charCodeAt(7) % 9)); const mm = (10 + x.id.charCodeAt(8) % 49);
  const d = {
    typeLabel: isLTI ? 'Lost Time Injury (LTI)' : x.type, ltiBadge: isLTI ? 'LTI' : x.hipo ? 'HIPO' : null,
    dateTime: `${DB.fmt(x.date)}  ·  ${String(hh).padStart(2, '0')}:${String(mm).padStart(2, '0')}`, location: tpl.loc, department: 'Operations',
    workActivity: tpl.act, equipment: tpl.equip, weather: 'Clear · 38°C',
    reportedBy: rep[0], reportedRole: rep[1],
    description: tpl.desc,
    immediate: tpl.inj ? ['Operation stopped immediately', 'Injured person provided first aid / medical attention', 'Area secured and equipment isolated', 'Incident reported to supervisor and QHSE'] : ['Activity stopped and made safe', 'Area secured / source isolated', 'Personnel accounted for', 'Incident reported to supervisor and QHSE'],
    injured: tpl.inj ? { name: { Lifting: 'Faisal Rahman', 'Hand injury': 'Bilal Hassan' }[x.cat] || 'Faisal Rahman', empId: 'EMP-008' + (x.id.charCodeAt(8) % 9) + '6', company: 'CSX Industrial Services', designation: tpl.inj.desig, injury: tpl.inj.injury, treatment: tpl.inj.treat, lostDays: tpl.inj.days, xy: INJ_XY[tpl.inj.xy] } : null,
    risk: sev, whys: tpl.whys, root: tpl.root, capaList: tpl.capa,
    classification: [['Recordable', isLTI ? 'Yes' : 'No'], ['Potential', x.hipo ? 'High Potential' : 'Medium'], ['Actual Consequence', isLTI ? 'Major' : tpl.inj ? 'Minor' : 'Near miss'], ['Incident Category', tpl.inj ? 'Personnel Injury' : x.cat], ['Regulatory Reportable', isLTI ? 'Yes' : 'No'], ['Client Notified', 'Yes']],
    team: [['Sultan Al-Qahtani', 'Lead Investigator', 'Q-001'], ['Maria Fernandez', 'Investigator', 'Q-002'], ['Khalid Mahmoud', 'Investigator', 'Q-003'], ['Ravi Kumar', 'Technical Expert', 'Q-004']],
    attachments: [{ n: 'Site_photo.jpg', t: 'img', s: '1.2 MB' }, { n: 'CCTV_clip.mp4', t: 'vid', s: '24.5 MB' }, { n: 'Witness_statement.pdf', t: 'pdf', s: '245 KB' }, { n: tpl.inj ? 'Medical_report.pdf' : 'Containment_record.pdf', t: 'pdf', s: '312 KB' }, { n: 'Equipment_inspection.pdf', t: 'pdf', s: '412 KB' }, { n: 'Site_map.png', t: 'img', s: '523 KB' }],
    actions: [{ l: 'Open', v: tpl.capa.filter((c) => c[2] === 'Open').length || 1, c: 'var(--bad)' }, { l: 'In Progress', v: tpl.capa.filter((c) => c[2] === 'In Progress').length, c: 'var(--warn)' }, { l: 'Pending', v: 1, c: '#2563eb' }, { l: 'Closed', v: tpl.capa.filter((c) => /closed|completed/i.test(c[2])).length, c: 'var(--ok)' }],
    notify: ['Supervisor', 'QHSE Manager', 'Operations Manager', 'HSE Director', 'Client Representative'],
    createdBy: rep[0], createdAt: `${DB.fmt(x.date)} ${String(hh).padStart(2, '0')}:${String(mm + 5).padStart(2, '0')}`, updatedBy: 'Sultan Al-Qahtani', updatedAt: `${DB.fmt(new Date(+x.date + 86400000))} 02:30 PM`,
  };
  return { ...d, ...(x.detail || {}) };
}
function IncidentStepper({ cur }) {
  return (
    <div className="card card-pad" style={{ overflowX: 'auto' }}>
      <div className="row" style={{ gap: 0, minWidth: 760 }}>
        {INC_STEPS.map((s, i) => {
          const done = i < cur, active = i === cur;
          const sub = i < cur ? 'Completed' : active ? 'In Progress' : 'Pending';
          return (
            <React.Fragment key={s}>
              <div className="row" style={{ gap: 9, flex: 'none' }}>
                <span style={{ width: 30, height: 30, borderRadius: '50%', flex: 'none', display: 'grid', placeItems: 'center', fontSize: 12, fontWeight: 800, background: done ? 'var(--ok)' : active ? 'var(--primary-600)' : '#e8edf3', color: done || active ? '#fff' : 'var(--text-3)' }}>{done ? <Icon name="check" size={15} /> : i + 1}</span>
                <div style={{ lineHeight: 1.2 }}><div style={{ fontSize: 12, fontWeight: 700, color: active ? 'var(--primary-700)' : done ? 'var(--text)' : 'var(--text-3)' }}>{s}</div><div className="faint" style={{ fontSize: 10 }}>{sub}</div></div>
              </div>
              {i < INC_STEPS.length - 1 && <div style={{ flex: 1, minWidth: 18, height: 2, margin: '0 8px', background: i < cur ? 'var(--ok)' : 'var(--border-2)' }} />}
            </React.Fragment>
          );
        })}
      </div>
    </div>
  );
}
function RiskMatrixPlot({ L, S, score, rating }) {
  const cons = ['Insig.', 'Minor', 'Mod.', 'Major', 'Catas.'];
  const like = ['Almost Certain', 'Likely', 'Possible', 'Unlikely', 'Rare'];
  const color = (l, s) => { const r = l * s; return r >= 15 ? '#ef4444' : r >= 10 ? '#f97316' : r >= 5 ? '#f59e0b' : '#22c55e'; };
  return (
    <div>
      {[5, 4, 3, 2, 1].map((l, li) => (
        <div key={l} className="row" style={{ gap: 3, marginBottom: 3, alignItems: 'center' }}>
          <span style={{ width: 64, fontSize: 8, color: 'var(--text-3)', textAlign: 'right', lineHeight: 1.05 }}>{like[li]}</span>
          {[1, 2, 3, 4, 5].map((s) => { const hit = l === L && s === S; return (
            <div key={s} style={{ flex: 1, height: 26, borderRadius: 4, background: color(l, s), display: 'grid', placeItems: 'center', position: 'relative' }}>
              {hit && <span style={{ width: 22, height: 22, borderRadius: '50%', background: '#fff', color: '#b91c1c', display: 'grid', placeItems: 'center', fontSize: 10, fontWeight: 800, border: '2.5px solid #b91c1c' }}>{score}</span>}
            </div>
          ); })}
        </div>
      ))}
      <div className="row" style={{ gap: 3 }}><span style={{ width: 64 }} />{cons.map((c, i) => <span key={i} style={{ flex: 1, textAlign: 'center', fontSize: 8, color: 'var(--text-3)' }}>{c}</span>)}</div>
    </div>
  );
}
function IncidentDetail({ rec, onBack, onNav }) {
  const x = rec;
  const [tab, setTab] = useState('details');
  const d = incidentFull(x);
  const cur = INC_STEPIDX[x.status] != null ? INC_STEPIDX[x.status] : 2;
  const sevDisp = `${d.risk.rating} (${d.risk.score})`;
  const fIco = { pdf: ['receipt', 'var(--bad)'], img: ['eye', 'var(--primary-600)'], vid: ['eye', 'var(--ai)'] };
  const tabs = [['details', 'Incident Details'], ['investigation', 'Investigation'], ['rca', 'Root Cause Analysis'], ['capa', 'Actions (CAPA)'], ['attach', 'Attachments'], ['timeline', 'Timeline'], ['lessons', 'Lessons Learned']];
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 8, marginBottom: 12 }}><button className="row" onClick={onBack} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--primary-600)', fontWeight: 600, fontSize: 12.5, fontFamily: 'inherit', gap: 4 }}><Icon name="chevL" size={15} />Back to all incidents</button></div>
      {/* header */}
      <div className="card card-pad" style={{ marginBottom: 14 }}>
        <div className="row" style={{ gap: 16, flexWrap: 'wrap', alignItems: 'center' }}>
          <span className="kpi-ico" style={{ width: 52, height: 52, borderRadius: 12, background: 'var(--bad)', color: '#fff', flex: 'none' }}><Icon name="helmet" size={26} /></span>
          <div style={{ flex: '1 1 220px' }}>
            <div className="row" style={{ gap: 9, flexWrap: 'wrap', alignItems: 'center' }}><span style={{ fontSize: 21, fontWeight: 800 }}>{x.id}</span>{d.ltiBadge && <Badge kind="bad">{d.ltiBadge}</Badge>}<span style={{ fontSize: 13, color: 'var(--text-2)', fontWeight: 600 }}>{d.typeLabel}</span></div>
            <div className="faint" style={{ fontSize: 12, marginTop: 3 }}>{d.dateTime} · {d.location}</div>
          </div>
          {[['Status', x.status, 'var(--primary-700)'], ['Severity / Risk', sevDisp, d.risk.rating === 'High' ? 'var(--bad)' : d.risk.rating === 'Medium' ? 'var(--warn)' : 'var(--ok)']].map(([k, v, col]) => (
            <div key={k} style={{ border: '1px solid var(--border)', borderRadius: 10, padding: '8px 12px', minWidth: 130 }}><div className="eyebrow" style={{ fontSize: 8.5 }}>{k}</div><div className="row" style={{ gap: 6, fontSize: 13, fontWeight: 700, color: col, marginTop: 2 }}>{v}<Icon name="chevD" size={12} style={{ color: 'var(--text-3)' }} /></div></div>
          ))}
          <div style={{ minWidth: 110 }}><div className="eyebrow" style={{ fontSize: 8.5 }}>Reported by</div><div style={{ fontSize: 12.5, fontWeight: 700, marginTop: 3 }}>{d.reportedBy}</div><div className="faint" style={{ fontSize: 10.5 }}>{d.reportedRole}</div></div>
          <div style={{ minWidth: 100 }}><div className="eyebrow" style={{ fontSize: 8.5 }}>Department</div><div style={{ fontSize: 12.5, fontWeight: 700, marginTop: 3 }}>{d.department}</div><div className="faint" style={{ fontSize: 10.5 }}>Onshore</div></div>
          <div className="row" style={{ gap: 8 }}><DocActions label="incident report" id={x.id} /><Btn variant="primary" icon="signature" onClick={() => window.toast('Edit mode — fields unlocked', 'info')}>Edit incident</Btn><Btn variant="ghost" icon="dots" onClick={() => window.toast('More actions', 'info')}>More</Btn></div>
        </div>
      </div>
      {/* stepper */}
      <div style={{ marginBottom: 14 }}><IncidentStepper cur={cur} /></div>
      {/* tabs */}
      <Tabs tabs={tabs} tab={tab} setTab={setTab} />

      {tab === 'details' && (<React.Fragment>
        <div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr 1fr', gap: 14, alignItems: 'start' }}>
          {/* incident details */}
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 12 }}>Incident details</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px 20px' }}>
              {[['Incident Type', d.typeLabel], ['Date & Time', d.dateTime], ['Location', d.location], ['Department', d.department], ['Work Activity', d.workActivity], ['Equipment Involved', d.equipment], ['Weather Condition', d.weather], ['Reported By', `${d.reportedBy} (${d.reportedRole})`]].map(([k, v]) => (
                <div key={k}><div className="faint" style={{ fontSize: 11 }}>{k}</div><div style={{ fontSize: 12.5, fontWeight: 650, marginTop: 1 }}>{v}</div></div>
              ))}
            </div>
            <div style={{ marginTop: 14 }}><div className="faint" style={{ fontSize: 11 }}>Description</div><div style={{ fontSize: 12.5, lineHeight: 1.55, marginTop: 3 }}>{d.description}</div></div>
            <div style={{ marginTop: 14 }}><div className="faint" style={{ fontSize: 11, marginBottom: 5 }}>Immediate Actions Taken</div>{d.immediate.map((a, i) => <div key={i} className="row" style={{ gap: 8, alignItems: 'flex-start', padding: '3px 0' }}><Icon name="check" size={13} style={{ color: 'var(--ok)', flex: 'none', marginTop: 2 }} /><span style={{ fontSize: 12.5 }}>{a}</span></div>)}</div>
            <div className="row" style={{ justifyContent: 'center', marginTop: 12 }}><button onClick={() => window.toast('Full incident record', 'info')} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--primary-600)', fontWeight: 600, fontSize: 11.5, fontFamily: 'inherit' }}>Show more ▾</button></div>
          </div>
          {/* injured person + classification */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {d.injured && <div className="card card-pad">
              <div className="row" style={{ gap: 7, marginBottom: 10 }}><Icon name="users" size={15} style={{ color: 'var(--bad)' }} /><div className="eyebrow" style={{ margin: 0 }}>Injured person</div></div>
              <div className="row" style={{ gap: 10, alignItems: 'flex-start' }}>
                <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 7 }}>
                  {[['Name', d.injured.name], ['Employee ID', d.injured.empId], ['Company', d.injured.company], ['Designation', d.injured.designation], ['Injury Details', d.injured.injury], ['Medical Treatment', d.injured.treatment], ['Lost Time (Days)', `${d.injured.lostDays} (and counting)`]].map(([k, v]) => (
                    <div key={k} className="row" style={{ justifyContent: 'space-between', gap: 8 }}><span className="faint" style={{ fontSize: 11 }}>{k}</span><b style={{ fontSize: 11.5, textAlign: 'right' }}>{v}</b></div>
                  ))}
                </div>
                <svg viewBox="0 0 338.64 839.2" style={{ width: 58, flex: 'none' }}>
                  <defs><radialGradient id="injglow"><stop offset="0%" stopColor="#ef4444" stopOpacity="0.85" /><stop offset="60%" stopColor="#ef4444" stopOpacity="0.3" /><stop offset="100%" stopColor="#ef4444" stopOpacity="0" /></radialGradient></defs>
                  <g dangerouslySetInnerHTML={{ __html: window.BODY_FRONT }} />
                  {d.injured.xy && <g><circle cx={d.injured.xy[0]} cy={d.injured.xy[1]} r="60" fill="url(#injglow)" /><circle cx={d.injured.xy[0]} cy={d.injured.xy[1]} r="14" fill="#ef4444" stroke="#fff" strokeWidth="4" /></g>}
                </svg>
              </div>
              <Btn variant="ghost" icon="receipt" size="sm" style={{ marginTop: 10, width: '100%' }} onClick={() => window.toast('Medical report opened', 'info')}>View medical report</Btn>
            </div>}
            <div className="card card-pad">
              <div className="eyebrow" style={{ marginBottom: 8 }}>Classification</div>
              {d.classification.map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', fontSize: 12 }}><span className="faint">{k}</span><b>{v}</b></div>)}
            </div>
          </div>
          {/* risk + action summary + notifications */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div className="card card-pad">
              <div className="eyebrow" style={{ marginBottom: 10 }}>Risk assessment</div>
              <RiskMatrixPlot {...d.risk} />
              <div className="row" style={{ justifyContent: 'space-between', marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--border)' }}><span style={{ fontSize: 12.5, fontWeight: 700 }}>Risk rating</span><Badge kind={d.risk.rating === 'High' ? 'bad' : d.risk.rating === 'Medium' ? 'warn' : 'ok'}>{sevDisp}</Badge></div>
            </div>
            <div className="card card-pad">
              <div className="eyebrow" style={{ marginBottom: 6 }}>Action summary</div>
              <div className="row" style={{ gap: 10, alignItems: 'center' }}><DashDonut data={d.actions} size={104} /><DashLegend data={d.actions} /></div>
              <button onClick={() => onNav('capa')} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--primary-600)', fontWeight: 600, fontSize: 11.5, fontFamily: 'inherit', marginTop: 8 }}>View all actions →</button>
            </div>
            <div className="card card-pad">
              <div className="row" style={{ gap: 7, marginBottom: 6 }}><Icon name="bell" size={14} style={{ color: 'var(--primary-600)' }} /><div className="eyebrow" style={{ margin: 0 }}>Notifications</div></div>
              {d.notify.map((n) => <div key={n} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', fontSize: 12 }}><span>{n}</span><span className="row" style={{ gap: 5, color: 'var(--ok)', fontSize: 11.5, fontWeight: 600 }}>Notified <Icon name="check" size={13} /></span></div>)}
            </div>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.6fr', gap: 14, marginTop: 14, alignItems: 'start' }}>
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 10 }}>Investigation team</div>
            {d.team.map(([n, role, id]) => <div key={n} className="row" style={{ gap: 10, padding: '7px 0', borderBottom: '1px solid var(--border)' }}><Avatar id={id} size="sm" /><div style={{ lineHeight: 1.2 }}><div style={{ fontSize: 12.5, fontWeight: 650 }}>{n}</div><div className="faint" style={{ fontSize: 10.5 }}>{role}</div></div></div>)}
            <button onClick={() => setTab('investigation')} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--primary-600)', fontWeight: 600, fontSize: 11.5, fontFamily: 'inherit', marginTop: 10 }}>View investigation plan →</button>
          </div>
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 12 }}>Attachments ({d.attachments.length})</div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(120px,1fr))', gap: 10 }}>
              {d.attachments.map((a, i) => { const fi = fIco[a.t]; return (
                <div key={i} className="card" style={{ padding: 10, cursor: 'pointer', textAlign: 'center' }} onClick={() => window.toast(`${a.n} opened`, 'info')}>
                  <span style={{ width: 38, height: 38, borderRadius: 9, background: 'var(--surface-2)', color: fi[1], display: 'grid', placeItems: 'center', margin: '0 auto 6px' }}><Icon name={fi[0]} size={19} /></span>
                  <div style={{ fontSize: 11, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.n}</div><div className="faint" style={{ fontSize: 10 }}>{a.s}</div>
                </div>
              ); })}
            </div>
          </div>
        </div>
      </React.Fragment>)}

      {tab === 'investigation' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 300px', gap: 14, alignItems: 'start' }}>
          <AIInvestigation incident={x} />
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div className="card card-pad">
              <div className="eyebrow" style={{ marginBottom: 10 }}>Investigation team</div>
              {d.team.map(([n, role, id]) => <div key={n} className="row" style={{ gap: 10, padding: '7px 0', borderBottom: '1px solid var(--border)' }}><Avatar id={id} size="sm" /><div style={{ lineHeight: 1.2 }}><div style={{ fontSize: 12.5, fontWeight: 650 }}>{n}</div><div className="faint" style={{ fontSize: 10.5 }}>{role}</div></div></div>)}
              <Btn variant="ghost" size="sm" style={{ marginTop: 10, width: '100%' }} onClick={() => window.toast('Investigation plan opened', 'info')}>View investigation plan</Btn>
            </div>
            <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Investigation status</div>{[['Method', '5-Why + TapRooT'], ['Lead', 'Sultan Al-Qahtani'], ['Target', DB.fmt(new Date(+x.date + 7 * 864e5))], ['Status', x.status]].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5 }}><span className="faint">{k}</span><b>{v}</b></div>)}</div>
          </div>
        </div>
      )}

      {tab === 'rca' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 14, alignItems: 'start' }}>
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 10 }}>Root cause analysis — 5 Why's</div>
            {d.whys.map((w, i) => <div key={i} style={{ display: 'flex', gap: 10, padding: '8px 0', borderBottom: '1px solid var(--border)' }}><span style={{ width: 26, height: 26, borderRadius: '50%', flex: 'none', background: 'var(--ai-bg)', color: 'var(--ai)', display: 'grid', placeItems: 'center', fontSize: 11, fontWeight: 800 }}>{i + 1}</span><div style={{ flex: 1 }}><div style={{ fontSize: 12.5, fontWeight: 600 }}>{w[0]}</div><div className="faint" style={{ fontSize: 12, marginTop: 2 }}>→ {w[1]}</div></div></div>)}
            <div style={{ marginTop: 12, background: 'var(--bad-bg)', border: '1px solid var(--bad-line)', borderRadius: 10, padding: '10px 12px' }}><div className="eyebrow" style={{ fontSize: 9, color: 'var(--bad)' }}>Root cause</div><div style={{ fontSize: 12.5, marginTop: 3, lineHeight: 1.5 }}>{d.root}</div></div>
          </div>
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 10 }}>Cause tree</div>
            <div style={{ fontSize: 12 }}>
              <div className="row" style={{ gap: 8 }}><span style={{ width: 12, height: 12, borderRadius: 3, background: 'var(--bad)', flex: 'none' }} /><b>Top event:</b> {d.typeLabel}</div>
              <div style={{ borderLeft: '2px solid var(--border-2)', marginLeft: 5, paddingLeft: 14, marginTop: 6 }}>
                {d.whys.slice(0, 3).map((w, i) => <div key={i} style={{ padding: '6px 0' }}><div className="row" style={{ gap: 7 }}><span style={{ width: 9, height: 9, borderRadius: '50%', background: ['#f97316', '#f59e0b', '#2563eb'][i], flex: 'none' }} /><span style={{ fontSize: 11.5 }}>{w[1]}</span></div></div>)}
              </div>
              <AINote title="Sentinel — systemic check" clause="ISO 45001 §10.2">AI compares this root cause against the last 12 months — it recurs in {x.cat === 'Lifting' ? '3 lifting' : '2 similar'} events. A cross-project barrier is recommended.</AINote>
            </div>
          </div>
        </div>
      )}

      {tab === 'capa' && (
        <div className="card">
          <div className="card-head"><Icon name="refresh" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Corrective & preventive actions</div><span className="spacer" /><Badge kind="ai" icon="sparkles">AI-drafted</Badge></div>
          <div style={{ padding: '12px 16px 0' }}><AINote title="AI-drafted CAPA from root cause" clause="ISO 45001 §10.2">Sentinel drafted {d.capaList.length} actions targeting: <b>{d.root}</b>. Tracked under {x.capa || 'CAPA-26-040'}.</AINote></div>
          <table className="tbl" style={{ marginTop: 8 }}><thead><tr><th>#</th><th>Action</th><th>Type</th><th>Owner</th><th>Due</th><th>Status</th></tr></thead>
            <tbody>{d.capaList.map((c, i) => <tr key={i} className="clickable" onClick={() => onNav('capa')}><td className="mono cell-strong">{String(i + 1).padStart(2, '0')}</td><td style={{ fontSize: 12.5 }}>{c[0]}</td><td><span className="tag">{i === 0 ? 'Corrective' : 'Preventive'}</span></td><td><Avatar id={c[1]} size="sm" /></td><td className="faint" style={{ fontSize: 11.5 }}>{DB.rel(new Date(+x.date + (i + 1) * 5 * 864e5))}</td><td><Badge kind={/closed|completed/i.test(c[2]) ? 'ok' : c[2] === 'In Progress' ? 'warn' : 'bad'} dot={!/closed|completed/i.test(c[2])}>{c[2]}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}

      {tab === 'attach' && (
        <div className="card card-pad">
          <div className="eyebrow" style={{ marginBottom: 12 }}>Attachments ({d.attachments.length})</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(150px,1fr))', gap: 12 }}>
            {d.attachments.map((a, i) => { const fi = fIco[a.t]; return (
              <div key={i} className="card" style={{ padding: 12, cursor: 'pointer', textAlign: 'center' }} onClick={() => window.toast(`${a.n} opened`, 'info')}>
                <span style={{ width: 44, height: 44, borderRadius: 10, background: 'var(--surface-2)', color: fi[1], display: 'grid', placeItems: 'center', margin: '0 auto 8px' }}><Icon name={fi[0]} size={22} /></span>
                <div style={{ fontSize: 11.5, fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.n}</div>
                <div className="faint" style={{ fontSize: 10.5 }}>{a.s}</div>
              </div>
            ); })}
          </div>
        </div>
      )}

      {tab === 'timeline' && (
        <div className="card card-pad">
          <div className="eyebrow" style={{ marginBottom: 12 }}>Timeline</div>
          {[['08:45 AM', 'Incident occurred — load struck operator', 'bad'], ['08:50 AM', `Reported by ${d.reportedBy}`, 'info'], ['09:15 AM', 'Reviewed & confirmed by supervisor', 'info'], ['10:00 AM', 'Investigation team assigned', 'warn'], ['Next day', 'Root-cause analysis in progress (5-Why / TapRooT)', 'ai']].map(([t, e, tone], i) => (
            <div key={i} className="row" style={{ gap: 11, padding: '9px 0', borderBottom: i < 4 ? '1px solid var(--border)' : 'none', alignItems: 'flex-start' }}><span className="mono faint" style={{ fontSize: 11, width: 64, flex: 'none' }}>{t}</span><span style={{ width: 9, height: 9, borderRadius: '50%', background: `var(--${tone === 'info' ? 'primary-600' : tone === 'ai' ? 'ai' : tone})`, flex: 'none', marginTop: 4 }} /><span style={{ fontSize: 12.5 }}>{e}</span></div>
          ))}
        </div>
      )}

      {tab === 'lessons' && (
        <div className="card card-pad">
          <AINote title="AI lessons-learned & safety alert" clause="ISO 45001 §10.2">Sentinel drafts a Safety Alert and Toolbox Talk from this investigation and propagates the tool-tethering / exclusion-zone lesson to all at-height projects.</AINote>
          <div className="row" style={{ gap: 8, marginTop: 12 }}>
            <Btn variant="ai" icon="sparkles" onClick={() => window.toast(`Safety Alert generated from ${x.id}`, 'info')}>Generate Safety Alert</Btn>
            <Btn variant="ai" icon="sparkles" onClick={() => window.toast(`Toolbox Talk drafted from ${x.id}`, 'info')}>Generate Toolbox Talk</Btn>
            <Btn variant="ghost" icon="download" onClick={() => window.toast(`${x.id} report exported (PDF)`)}>Export report</Btn>
          </div>
        </div>
      )}

      <div className="row" style={{ gap: 18, marginTop: 14, paddingTop: 12, borderTop: '1px solid var(--border)', flexWrap: 'wrap' }}>
        <span className="faint" style={{ fontSize: 11.5 }}>Created by <b style={{ color: 'var(--text-2)' }}>{d.createdBy}</b> · {d.createdAt}</span>
        <span className="faint" style={{ fontSize: 11.5 }}>Last updated by <b style={{ color: 'var(--text-2)' }}>{d.updatedBy}</b> · {d.updatedAt}</span>
      </div>
    </div>
  );
}

/* ===================== QUALITY / NCR (AI root cause) ================ */
function QualityModule({ onNav, onOpen }) {
  const [tab, setTab] = useState('ncr');
  const n = DB.ncrs; const open = n.filter((x) => x.status !== 'Closed').length;
  const repeats = n.filter((x) => x.repeat).length;
  const qKpis = [['Open NCR / CAR', open, 'check-shield', 'bad'], ['Repeat findings', repeats, 'refresh', 'warn'], ['Inspection requests', DB.inspections.length, 'clipboard', 'info'], ['ITP control points', DB.itpItems.length, 'check', 'ai'], ['Client complaints', DB.complaints.length, 'alert', 'warn'], ['Closed (YTD)', n.filter((x) => x.status === 'Closed').length, 'check', 'ok']];
  const byCat = (() => { const m = {}; n.forEach((x) => { m[x.cat] = (m[x.cat] || 0) + 1; }); const cols = ['#ef4444', '#f59e0b', '#2563eb', '#22c55e', '#7a5bff', '#0e7490']; return Object.entries(m).map(([l, v], i) => ({ l, v, c: cols[i % cols.length] })); })();
  const bySev = ['Critical', 'Major', 'Minor'].map((s, i) => ({ l: s, v: n.filter((x) => x.severity === s).length, c: ['#ef4444', '#f59e0b', '#22c55e'][i] })).filter((x) => x.v);
  const qTrend = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#ef4444', d: [5, 7, 6, 8, 6, 5] }, { c: '#22c55e', d: [3, 5, 6, 6, 7, 8] }] };
  return (
    <div className="page page-wide rise">
      <PageHead title="NCR / CAR Management" sub="Non-conformance · corrective action requests · observations · complaints · supplier quality — ISO 9001">
        <DocActions label="NCR register" />
        <Btn variant="ghost" icon="workflow" size="sm" onClick={() => openMocForm()}>Raise MOC</Btn>
        <Btn variant="primary" icon="plus" onClick={() => openNcrReport()}>Raise NCR / CAR</Btn>
      </PageHead>
      <Tabs tabs={[['ncr', 'NCR / CAR'], ['dashboard', 'Dashboard'], ['inspections', 'Inspection requests'], ['itp', 'ITP'], ['trace', 'Material traceability'], ['obs', 'Observations'], ['complaints', 'Client complaints'], ['lessons', 'Lessons learned'], ['suppliers', 'Supplier quality']]} tab={tab} setTab={setTab} />
      {tab === 'dashboard' && <ModuleDash kpis={qKpis} panels={[
        { title: 'NCRs by severity', node: <DashSplit data={bySev} />, w: '1fr' },
        { title: 'NCRs by category', node: <DashHBars data={byCat} />, w: '1.3fr' },
        { title: 'Raised vs closed (6 mo)', node: <DashLine trend={qTrend} />, w: '1.3fr' },
      ]} />}
      {tab === 'inspections' &&<div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Inspection requests</div></div><table className="tbl"><thead><tr><th>Ref</th><th>Item</th><th>Project</th><th>Requested</th><th>Inspector</th><th>Client point</th><th>Status</th></tr></thead><tbody>{DB.inspections.map((r) => <tr key={r.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{r.id}</td><td style={{ fontSize: 12.5 }}>{r.item}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{r.project}</td><td className="faint">{DB.rel(r.requested)}</td><td><Avatar id={r.inspector} size="sm" /></td><td><Badge kind={r.client === 'Hold' ? 'bad' : 'warn'}>{r.client}</Badge></td><td><Badge kind={r.status === 'Accepted' ? 'ok' : 'info'} dot={r.status !== 'Accepted'}>{r.status}</Badge></td></tr>)}</tbody></table></div>}
      {tab === 'itp' && <div className="card"><div className="card-head"><Icon name="check-shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Inspection & Test Plan (ITP) tracking</div></div><table className="tbl"><thead><tr><th>Ref</th><th>Activity</th><th>Project</th><th>Control point</th><th>Responsible</th><th>Status</th></tr></thead><tbody>{DB.itpItems.map((r) => <tr key={r.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{r.id}</td><td style={{ fontSize: 12.5 }}>{r.activity}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{r.project}</td><td><span className="tag">{r.point}</span></td><td className="faint" style={{ fontSize: 12 }}>{r.responsible}</td><td><Badge kind={r.status === 'Closed' ? 'ok' : 'info'} dot={r.status !== 'Closed'}>{r.status}</Badge></td></tr>)}</tbody></table></div>}
      {tab === 'trace' && <div className="card"><div className="card-head"><Icon name="box" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Material traceability</div></div><table className="tbl"><thead><tr><th>Ref</th><th>Material</th><th>Heat / lot</th><th>Certificate</th><th>Project</th><th>Status</th></tr></thead><tbody>{DB.materialTrace.map((r) => <tr key={r.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{r.id}</td><td style={{ fontSize: 12.5 }}>{r.material}</td><td className="mono" style={{ fontSize: 11.5 }}>{r.heat}</td><td className="faint" style={{ fontSize: 12 }}>{r.cert}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{r.project}</td><td><Badge kind="ok" dot={false}>{r.status}</Badge></td></tr>)}</tbody></table></div>}
      {tab === 'obs' && <div style={{ marginBottom: 14 }}><AINote title="Leading-indicator trend" clause="AIX">AI clusters observations into leading indicators — unsafe-act observations are trending up on P-219 chemical works; a targeted toolbox talk is recommended.</AINote></div>}
      {tab === 'complaints' && <div style={{ marginBottom: 14 }}><AINote title="Complaint root-cause link" clause="ISO 9001 §10.2">Both open complaints trace to reporting / sign-off delays — AI links them to the same documentation CAPA, suggesting a systemic reporting-cadence fix.</AINote></div>}
      {tab === 'lessons' && <div style={{ marginBottom: 14 }}><AINote title="Cross-project learning" clause="AIX">AI propagates the tool-tethering lesson to all 4 at-height projects and flags 2 crews that haven't acknowledged it.</AINote></div>}
      {tab === 'suppliers' && <div style={{ marginBottom: 14 }}><AINote title="Supplier risk" clause="AIX">Apex Manpower (conditional, 82) supplies the P-204 riggers tied to the lifting near-miss — AI recommends a focused HSE re-evaluation before renewal.</AINote></div>}
      {tab === 'ncr' && (
        <div className="card">
          <div className="card-head"><Icon name="check-shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">NCR register</div><span className="spacer" /><Badge kind="ai" icon="sparkles">AI repeat-detection</Badge></div>
          <table className="tbl">
            <thead><tr><th>Ref</th><th>Title</th><th>Project</th><th>Category</th><th>Severity</th><th>Owner</th><th>Stage</th><th>Status</th><th></th></tr></thead>
            <tbody>{DB.ncrs.map((n) => (
              <tr key={n.id} className="clickable" onClick={() => onOpen('ncr', n)}>
                <td className="mono cell-strong" style={{ fontSize: 11.5 }}>{n.id}{n.repeat && <span className="badge b-warn" style={{ marginLeft: 6, fontSize: 9.5 }}>REPEAT</span>}</td>
                <td style={{ fontSize: 12.5, maxWidth: 250 }}>{n.title}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{n.project}</td>
                <td><span className="tag">{n.cat}</span></td><td><Badge kind={sevKind(n.severity)}>{n.severity}</Badge></td>
                <td><Avatar id={n.owner} size="sm" /></td><td className="faint" style={{ fontSize: 12 }}>{n.stage}</td>
                <td><Badge kind={n.status === 'Closed' ? 'ok' : 'info'} dot={n.status !== 'Closed'}>{n.status}</Badge></td>
                <td><RowActions onView={() => onOpen('ncr', n)} onEdit={() => openNcrReport(n)} onDelete={() => dbRemove('ncrs', 'id', n.id)} /></td>
              </tr>
            ))}</tbody>
          </table>
        </div>
      )}
      {tab === 'obs' && (
        <div className="card"><div className="card-head"><Icon name="flag" size={16} style={{ color: 'var(--warn)' }} /><div className="h-sec">Observations (safety & quality)</div><span className="spacer" /><Btn size="sm" variant="ghost" icon="plus" onClick={() => openObservationLog()}>Log observation</Btn></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Observation</th><th>Type</th><th>Project</th><th>By</th><th>Status</th></tr></thead>
            <tbody>{DB.observations.map((o) => <tr key={o.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{o.id}</td><td style={{ fontSize: 12.5 }}>{o.obs}</td><td><Badge kind={o.type === 'Positive' ? 'ok' : o.type === 'Unsafe act' ? 'bad' : 'warn'}>{o.type}</Badge></td><td className="mono faint" style={{ fontSize: 11.5 }}>{o.project}</td><td><Avatar id={o.by} size="sm" /></td><td><Badge kind={o.status === 'Logged' ? 'neutral' : 'ok'}>{o.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'complaints' && (
        <div className="card"><div className="card-head"><Icon name="chat" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Client complaints</div><span className="faint" style={{ fontSize: 11, marginLeft: 8 }}>ISO 9001 §10.2</span></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Client</th><th>Subject</th><th>Date</th><th>Linked CAPA</th><th>Status</th></tr></thead>
            <tbody>{DB.complaints.map((c) => <tr key={c.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{c.id}</td><td style={{ fontSize: 12.5 }}>{c.client}</td><td style={{ fontSize: 12.5 }}>{c.subject}</td><td className="faint">{DB.fmt(c.date)}</td><td>{c.capa ? <span className="mono" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{c.capa}</span> : <span className="faint">—</span>}</td><td><Badge kind={c.status === 'Resolved' ? 'ok' : 'info'} dot={c.status !== 'Resolved'}>{c.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'lessons' && (
        <div className="card"><div className="card-head"><Icon name="sparkles" size={16} style={{ color: 'var(--ai)' }} /><div className="h-sec">Lessons learned</div><span className="spacer" /><Badge kind="ai">AI-clustered</Badge></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Lesson</th><th>Project</th><th>Category</th><th>Shared with</th></tr></thead>
            <tbody>{DB.lessons.map((l) => <tr key={l.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{l.id}</td><td style={{ fontSize: 12.5 }}>{l.title}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{l.project}</td><td><span className="tag">{l.cat}</span></td><td className="faint" style={{ fontSize: 12 }}>{l.shared}</td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'suppliers' && (
        <div className="card"><div className="card-head"><Icon name="briefcase" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Supplier quality</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Supplier</th><th>Category</th><th>Rating</th><th>Status</th></tr></thead>
            <tbody>{DB.suppliers.map((s) => <tr key={s.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{s.id}</td><td style={{ fontSize: 12.5 }}>{s.name}</td><td className="faint" style={{ fontSize: 12 }}>{s.cat}</td><td><b style={{ color: scoreColor(s.rating) }}>{s.rating}</b></td><td><Badge kind={s.status === 'Approved' ? 'ok' : 'warn'} dot={s.status !== 'Approved'}>{s.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}
function NCRDetail({ rec, onBack, onNav }) {
  const n = rec;
  const [run, setRun] = useState(false);
  const [step, setStep] = useState(0);
  const ai = [
    { h: 'Classification', body: `Categorized as "${n.cat}" · ${n.severity}. ${n.repeat ? 'Repeat signature detected.' : 'No prior match.'}` },
    { h: 'Repeat detection', body: n.repeat ? 'Matches NCR-26-041 and NCR-26-049 — all on bolt-torque records, same crew/procedure. Treat as systemic.' : 'Isolated occurrence — no systemic pattern found in the last 12 months.' },
    { h: 'Probable root cause', body: n.repeat ? 'Torque-recording step in the flange procedure lacks a verification gate; inspectors rely on memory under schedule pressure.' : 'Single-point process deviation; containment sufficient.' },
    { h: 'Recommended corrective action', body: n.repeat ? 'Add a mandatory torque-record verification gate to PRO-FLG, plus an inspector competency refresh; verify on next 3 flange sets.' : 'Re-issue with corrected record; brief the crew at toolbox talk.', action: 'Accept CAPA' },
  ];
  useEffect(() => { if (run && step < ai.length) { const t = setTimeout(() => setStep((s) => s + 1), 650); return () => clearTimeout(t); } }, [run, step]);
  const whys = [
    ['Why was the weld screen non-conforming?', 'Screen mesh was torn / inadequate coverage'],
    ['Why was the mesh torn?', 'Re-used screen past its service life'],
    ['Why was a worn screen re-used?', 'No pre-job inspection of fire screens'],
    ['Why was there no pre-job inspection?', 'Hot-work checklist did not include screen condition'],
    ['Why did the checklist miss it?', 'Checklist not updated after last procedure revision'],
  ];
  const rootCause = 'Hot-work permit checklist lacks a fire-screen condition check; worn screens enter service unverified.';
  const capa = [
    ['Add fire-screen condition check to hot-work checklist', 'Q-001', '+10d', 'Completed'],
    ['Replace / tag worn welding screens across stores', 'Q-006', '+7d', 'Completed'],
    ['Toolbox talk on screen inspection to hot-work crews', 'Q-002', '+5d', 'Completed'],
  ];
  const STAGES = [['enter', 'Entering', 'Report & record nonconformity'], ['approve', 'Approval', 'Review & approve NCR'], ['close', 'Closeout', 'Implement CAPA & close']];
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 10, marginBottom: 16 }}>
        <button className="icon-btn" onClick={onBack}><Icon name="chevL" size={17} /></button>
        <span className="kpi-ico" style={{ width: 36, height: 36, background: 'var(--warn-bg)', color: 'var(--warn)' }}><Icon name="check-shield" size={18} /></span>
        <div><div className="row" style={{ gap: 9 }}><span className="h-page" style={{ fontSize: 20 }}>{n.id}</span>{n.repeat && <Badge kind="warn">Repeat signature</Badge>}<Badge kind="info" dot>{n.status}</Badge></div><div className="h-sub">{n.title}</div></div>
        <span className="spacer" /><DocActions label="NCR / CAR" id={n.id} />
      </div>
      <Stepper steps={STAGES.map((s) => s[1])} current={1} sub={STAGES.map((s) => s[2])} />
      <div className="dk-panels" style={{ gridTemplateColumns: '1fr 1fr 1fr', marginTop: 16 }}>
        <div className="card card-pad" style={{ minWidth: 0 }}>
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>1 · Entering (NCR)</div><Badge kind="neutral">Recorded</Badge></div>
          {[['Type', 'NCR'], ['Source', 'PTW activity'], ['Location', n.project], ['Category', n.cat], ['Reported by', DB.staffById(n.owner).name], ['Reported on', DB.fmt(n.date)]].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5 }}><span className="faint">{k}</span><b style={{ textAlign: 'right' }}>{v}</b></div>)}
          <div className="eyebrow" style={{ margin: '10px 0 4px' }}>Initial classification</div>
          <div className="row" style={{ gap: 6, flexWrap: 'wrap' }}><Badge kind={sevKind(n.severity)}>{n.severity}</Badge><Badge kind="bad">Risk: {n.severity === 'Critical' ? 'High' : 'Medium'}</Badge><Badge kind="neutral">Impact: Safety</Badge></div>
          <div className="faint" style={{ fontSize: 11.5, marginTop: 8, lineHeight: 1.5 }}>{n.title}. Immediate action: work stopped, area isolated, screen removed from service.</div>
        </div>
        <div className="card card-pad" style={{ minWidth: 0 }}>
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>2 · Approval — 5 Why's RCA</div><Badge kind="warn" dot>Pending</Badge></div>
          {whys.map((w, i) => <div key={i} style={{ padding: '5px 0', borderBottom: '1px solid var(--border)' }}><div style={{ fontSize: 11, fontWeight: 700, color: 'var(--primary-700)' }}>Why {i + 1}</div><div style={{ fontSize: 11.5 }}>{w[0]}</div><div className="faint" style={{ fontSize: 11 }}>→ {w[1]}</div></div>)}
          <div style={{ marginTop: 8, background: 'var(--bad-bg)', border: '1px solid var(--bad-line)', borderRadius: 9, padding: '8px 10px' }}><div className="eyebrow" style={{ fontSize: 9, color: 'var(--bad)' }}>Root cause</div><div style={{ fontSize: 11.5, marginTop: 2 }}>{rootCause}</div></div>
          <div className="row" style={{ gap: 8, marginTop: 10 }}><Btn variant="ghost" size="sm" icon="x" onClick={() => { dbUpdate('ncrs', 'id', n.id, { status: 'Open', stage: 'Returned' }); window.toast('NCR returned for revision', 'warn'); onBack(); }}>Reject</Btn><Btn variant="primary" size="sm" icon="check" onClick={() => { dbUpdate('ncrs', 'id', n.id, { status: 'In Progress', stage: 'CAPA' }); window.toast('NCR approved · CAPA stage opened', 'ok'); onBack(); }}>Approve</Btn></div>
        </div>
        <div className="card card-pad" style={{ minWidth: 0 }}>
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>3 · Closeout (CAPA)</div><Badge kind="info" dot>In progress</Badge></div>
          <div className="eyebrow" style={{ fontSize: 9, marginBottom: 4 }}>CAPA implementation</div>
          {capa.map((a, i) => <div key={i} className="row" style={{ gap: 6, padding: '5px 0', borderBottom: '1px solid var(--border)', fontSize: 11 }}><span style={{ flex: 1 }}>{a[0]}</span><Avatar id={a[1]} size="sm" /><Badge kind="ok">{a[3]}</Badge></div>)}
          <div className="eyebrow" style={{ margin: '10px 0 4px', fontSize: 9 }}>Effectiveness verification</div>
          <div className="row" style={{ gap: 6, flexWrap: 'wrap' }}><Badge kind="neutral">Method: Site inspection</Badge><Badge kind="ok">Effective</Badge></div>
          <div className="row" style={{ gap: 7, marginTop: 8, fontSize: 11.5 }}><span className="faint">Verified by</span><Avatar id="Q-001" size="sm" /></div>
          <Btn variant="primary" size="sm" icon="check" style={{ marginTop: 10, width: '100%', background: 'var(--ok)' }} onClick={() => { dbUpdate('ncrs', 'id', n.id, { status: 'Closed', stage: 'Closed' }); window.toast('NCR closed · record archived', 'ok'); onBack(); }}>Close NCR</Btn>
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 16, alignItems: 'start', marginTop: 16 }}>
        <div className="card" style={{ borderColor: 'var(--ai-line)' }}>
          <div className="card-head" style={{ background: 'linear-gradient(120deg, var(--ai-bg), #fff)' }}><span className="ai-badge-ico"><Icon name="sparkles" size={15} fill /></span><div className="h-sec" style={{ fontSize: 14 }}>AI root-cause analysis</div><span className="spacer" />{!run && <Btn variant="ai" size="sm" icon="sparkles" onClick={() => { setRun(true); setStep(0); }}>Run analysis</Btn>}</div>
          <div className="card-body">
            {!run ? <div className="faint" style={{ fontSize: 12.5 }}>AI classifies the NCR, checks for repeat signatures across history, infers the probable root cause and drafts a corrective action for your review.</div>
              : ai.map((p, i) => (
                <div key={i} className="row" style={{ gap: 12, alignItems: 'flex-start', padding: '11px 0', borderBottom: i < ai.length - 1 ? '1px solid var(--border)' : 'none', opacity: i < step ? 1 : .25, transition: 'opacity .35s' }}>
                  <span style={{ width: 26, height: 26, borderRadius: '50%', flex: 'none', display: 'grid', placeItems: 'center', background: i < step ? 'var(--ai-bg)' : '#eef1f6', color: i < step ? 'var(--ai)' : 'var(--text-3)', fontSize: 11, fontWeight: 700 }}>{i + 1}</span>
                  <div style={{ flex: 1 }}><div className="row" style={{ justifyContent: 'space-between' }}><b style={{ fontSize: 12.5 }}>{p.h}</b>{p.action && i < step && <Btn size="sm" variant="ghost" icon="check" onClick={() => window.toast('Corrective action accepted · CAPA created · owner assigned')}>{p.action}</Btn>}</div><div className="faint" style={{ fontSize: 12, marginTop: 3, lineHeight: 1.5 }}>{p.body}</div></div>
                </div>
              ))}
          </div>
        </div>
        <div className="card card-pad">
          <div className="eyebrow" style={{ marginBottom: 10 }}>Details</div>
          {[['Project', n.project], ['Category', n.cat], ['Severity', n.severity], ['Owner', DB.staffById(n.owner).name], ['Raised', DB.fmt(n.date)], ['Stage', n.stage]].map(([k, v], i) => (
            <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '6px 0', fontSize: 12.5 }}><span className="faint">{k}</span><b>{v}</b></div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ===================== COMPLIANCE / AUDIT READINESS ================= */
function ComplianceModule({ onNav }) {
  const [tab, setTab] = useState('iso');
  const mr = DB.mgmtReviews.find((m) => m.status === 'Closed');
  return (
    <div className="page page-wide rise">
      <PageHead title="ISO Compliance" sub="ISO 9001/14001/45001 · legal & regulatory obligations · management review · audit readiness">
        <Btn icon="download" size="sm" onClick={() => window.toast('Audit pack generated (IMS manual, plans, registers)')}>Generate audit pack</Btn>
      </PageHead>
      <Tabs tabs={[['iso', 'ISO health'], ['legal', 'Legal & obligations'], ['review', 'Management review']]} tab={tab} setTab={setTab} />
      {tab === 'review' && <div style={{ marginBottom: 14 }}><AINote title="Open management actions" clause="ISO 9001 §9.3">2 actions from the H1 review remain open (lifting standard, Aramco CSTP programme). AI flags both as inputs the auditor will check — close before the ISO 45001 audit.</AINote></div>}
      {tab === 'iso' && <React.Fragment>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 14, marginBottom: 16 }}>
          {DB.standards.map((s) => (
            <div key={s.code} className="card card-pad">
              <div className="row" style={{ justifyContent: 'space-between' }}><span className="mono cell-strong" style={{ fontSize: 12.5 }}>{s.code}</span><Badge kind={s.findings ? 'warn' : 'ok'}>{s.findings} finding{s.findings !== 1 ? 's' : ''}</Badge></div>
              <div className="muted" style={{ fontSize: 12, marginTop: 3 }}>{s.title}</div>
              <div className="row" style={{ gap: 10, marginTop: 12, alignItems: 'center' }}><Ring value={s.score} size={56} color={scoreColor(s.score)}><b style={{ fontSize: 14 }}>{s.score}</b></Ring><div><div className="eyebrow" style={{ fontSize: 9 }}>Next audit</div><div style={{ fontSize: 12.5, fontWeight: 650 }}>{DB.fmt(s.nextAudit)}</div></div></div>
            </div>
          ))}
        </div>
        <AINote title="Predicted client-audit findings — ISO 45001 in 12 days" clause="AIX · audit-readiness" action="Prioritise CAPAs" onAction={() => onNav('capa')}>
          Based on current state, the two most likely findings are (1) closure evidence for the lifting-controls CAPA and (2) 7 certifications expiring before P-211. Closing both lifts the 45001 score above 90 and clears the audit.
        </AINote>
      </React.Fragment>}
      {tab === 'legal' && (
        <div className="card">
          <div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Legal & regulatory register · obligations</div><span className="faint" style={{ fontSize: 11, marginLeft: 8 }}>Saudi Arabia · Iraq · Kuwait · client</span></div>
          <table className="tbl">
            <thead><tr><th>Ref</th><th>Jurisdiction</th><th>Regulation / requirement</th><th>Obligation</th><th>Next review</th><th>Status</th></tr></thead>
            <tbody>{DB.legal.map((l) => (
              <tr key={l.id} className="clickable" onClick={() => window.toast(`${l.id} — ${l.title}`, 'info')}>
                <td className="mono cell-strong" style={{ fontSize: 11.5 }}>{l.id}</td><td><span className="tag">{l.region}</span></td>
                <td style={{ fontSize: 12.5 }}>{l.title}</td><td className="faint" style={{ fontSize: 12 }}>{l.obligation}</td>
                <td><span style={{ fontWeight: 600, color: l.review <= DB.TODAY ? 'var(--bad)' : 'var(--text)' }}>{DB.rel(l.review)}</span></td>
                <td><Badge kind={l.status === 'Compliant' ? 'ok' : 'warn'} dot={l.status !== 'Compliant'}>{l.status}</Badge></td>
              </tr>
            ))}</tbody>
          </table>
          <div className="card-body" style={{ borderTop: '1px solid var(--border)' }}>
            <AINote title="2 obligations need action before audit" clause="ISO 14001 §6.1.3">GAMEP environmental reporting is overdue and the Aramco SAEP-327 PTW alignment review falls in 8 days. AI flags both as audit-critical.</AINote>
          </div>
        </div>
      )}
      {tab === 'review' && mr && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div className="card">
            <div className="card-head"><Icon name="check-shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Management review register</div><span className="faint" style={{ fontSize: 11, marginLeft: 8 }}>ISO 9001 §9.3 / 45001 §9.3</span><span className="spacer" /><Btn size="sm" variant="primary" icon="plus" onClick={() => openMgmtReview()}>Schedule</Btn></div>
            <table className="tbl"><thead><tr><th>Ref</th><th>Review</th><th>Date</th><th>Chair</th><th>Actions</th><th>Status</th></tr></thead>
              <tbody>{DB.mgmtReviews.map((m) => (
                <tr key={m.id}><td className="mono cell-strong" style={{ fontSize: 12 }}>{m.id}</td><td style={{ fontSize: 12.5 }}>{m.title}</td><td className="faint">{DB.fmt(m.date)}</td><td><Avatar id={m.chair} size="sm" /></td><td>{m.actions ? <Badge kind={m.open ? 'warn' : 'ok'}>{m.open ? `${m.open} open` : `${m.actions} ✓`}</Badge> : <span className="faint">—</span>}</td><td><Badge kind={m.status === 'Closed' ? 'ok' : 'info'} dot={m.status !== 'Closed'}>{m.status}</Badge></td></tr>
              ))}</tbody>
            </table>
          </div>
          <div className="card">
            <div className="card-head"><Icon name="documents" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Management review pack — {mr.title}</div><span className="spacer" /><Btn size="sm" variant="ghost" icon="download" onClick={() => window.toast(`${mr.id} review pack exported (PDF)`)}>Download</Btn></div>
            <div className="card-body" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
              <div><div className="eyebrow" style={{ fontSize: 9.5, marginBottom: 8 }}>Inputs reviewed (§9.3.2)</div>{mr.inputs.map((i, k) => <div key={k} className="row" style={{ gap: 9, padding: '6px 0', fontSize: 12.5 }}><Icon name="check-circle" size={15} style={{ color: 'var(--ok)', flex: 'none' }} />{i}</div>)}</div>
              <div><div className="eyebrow" style={{ fontSize: 9.5, marginBottom: 8 }}>Outputs & decisions (§9.3.3)</div>{mr.outputs.map((o, k) => <div key={k} className="row" style={{ gap: 9, padding: '6px 0', fontSize: 12.5 }}><Icon name="arrowR" size={14} style={{ color: 'var(--primary-600)', flex: 'none' }} />{o}</div>)}</div>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ===================== PTW (AI permit review) ====================== */
const ptwSt = (s) => ({ 'In Progress': 'info', 'Pending Approval': 'warn', 'Awaiting approval': 'warn', Approved: 'ok', Closed: 'neutral', Expired: 'bad' }[s] || 'neutral');
function openPermit() {
  window.openAIAssist({ title: 'Create permit to work', sub: 'AI live-detects SIMOPS conflicts & missing controls', icon: 'flag', compute: permitCompute, fields: [{ key: 'type', label: 'Permit type', type: 'select', options: ['Hot Work', 'Cold Work', 'Electrical Work', 'Excavation Work', 'Confined Space Entry', 'Hydrotest', 'Nitrogen Purging', 'Working at Height', 'LOTO'] }, { key: 'project', label: 'Project', type: 'select', options: DB.projects.map((p) => p.id) }, { key: 'area', label: 'Location / equipment', type: 'text', placeholder: 'e.g. North Ghawar Plant - Area 12' }, { key: 'validity', label: 'Validity', type: 'text', placeholder: 'e.g. Today 06:00–18:00' }], submitLabel: 'Submit for review', done: 'Permit submitted · AI review running' });
}
function PtwKpis({ kpis }) {
  return <div style={{ display: 'grid', gridTemplateColumns: `repeat(${kpis.length},1fr)`, gap: 12, marginBottom: 14 }}>{kpis.map(([k, v, ic, tone]) => { const t = DASH_TONE[tone] || DASH_TONE.info; return (
    <div key={k} className="card" style={{ padding: '12px 13px' }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 10, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 22, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8, marginTop: 2 }}>{k}</div></div></div></div>
  ); })}</div>;
}
function PtwOverviewTable({ rows, onOpen, cols }) {
  return (
    <table className="tbl"><thead><tr><th>PTW No.</th><th>Type</th><th>Job / work</th><th>Location</th><th>Requested by</th><th>Status</th><th>Planned start</th><th>Risk</th></tr></thead>
      <tbody>{rows.map((p) => (
        <tr key={p.id} className="clickable" onClick={() => onOpen('ptw', p)}>
          <td className="mono cell-strong" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{p.id}</td><td><span className="tag">{p.type}</span></td><td style={{ fontSize: 12, maxWidth: 200 }}>{p.sub}</td><td className="faint" style={{ fontSize: 11 }}>{p.loc}</td><td><Avatar id={p.by} size="sm" /></td><td><Badge kind={ptwSt(p.status)} dot={p.status !== 'Closed'}>{p.status}</Badge></td><td className="faint" style={{ fontSize: 11 }}>{p.start}</td><td><Badge kind={pKind(p.risk)}>{p.risk}</Badge></td>
        </tr>
      ))}</tbody>
    </table>
  );
}
const ExpList = ({ rows, color }) => <div>{rows.map((r, i) => <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '7px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5, gap: 8 }}><div style={{ flex: 1, minWidth: 0 }}><div className="mono" style={{ color: 'var(--primary-700)' }}>{r[0]}</div><div className="faint" style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r[1]}</div></div><span style={{ color: color || 'var(--warn)', fontWeight: 700, whiteSpace: 'nowrap' }}>{r[2]}{r[3] ? '' : ' Left'}</span></div>)}</div>;
const PtwQuickActions = ({ onNav }) => <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Quick actions</div><div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}><Btn variant="primary" icon="plus" size="sm" onClick={() => openPtwForm()}>Create PTW</Btn><Btn icon="clock" size="sm" onClick={() => window.toast('Extend PTW', 'info')}>Extend PTW</Btn><Btn icon="x" size="sm" onClick={() => window.toast('Cancel PTW', 'info')}>Cancel PTW</Btn><Btn icon="alert" size="sm" onClick={() => onNav('incidents')}>Raise NCR</Btn></div></div>;

function PtwDashboard({ onNav, onOpen }) {
  const x = DB.ptwDash;
  return (
    <div className="page page-wide rise">
      <PageHead title="PTW Management" sub="Manage Permit to Work throughout its lifecycle"><DateFilter /><DocActions label="PTW register" /><Btn variant="primary" icon="plus" onClick={() => openPtwForm()}>Create PTW</Btn></PageHead>
      <PtwKpis kpis={x.kpis} />
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — SIMOPS & permit intelligence" clause="HAZID · PTW">AI continuously scans active permits for SIMOPS conflicts — <b>PTW-26-114</b> (N₂ confined-space) overlaps <b>PTW-26-113</b> (hot work) in the same area/window; do not approve in parallel. 3 permits expire within 6 hrs and 2 are overdue for close-out.</AINote></div>
      <div className="split" style={{ marginBottom: 14 }}>
        <div className="card"><div className="card-head"><Icon name="flag" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">PTW overview</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>Showing 1–8 of 128</span></div><PtwOverviewTable rows={DB.ptw.slice(0, 8)} onOpen={onOpen} /></div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>PTW status distribution</div><div className="row" style={{ gap: 10, alignItems: 'center' }}><DashDonut data={x.statusDist} size={108} /><DashLegend data={x.statusDist} /></div></div>
          <div className="card card-pad"><div className="row" style={{ justifyContent: 'space-between', marginBottom: 6 }}><div className="eyebrow" style={{ margin: 0 }}>Expiring soon</div><Icon name="clock" size={14} style={{ color: 'var(--warn)' }} /></div><ExpList rows={x.expiring} /></div>
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1.3fr', gap: 14, marginBottom: 14 }}>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>PTW by type</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={x.byType} size={104} /><DashLegend data={x.byType} /></div></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>PTW by location</div><DashHBars data={x.byLocation} /></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>PTW trend (daily)</div><div className="row" style={{ gap: 12, marginBottom: 4 }}>{x.trend.series.map((s) => <span key={s.k} className="row" style={{ gap: 5, fontSize: 10, color: 'var(--text-2)' }}><span style={{ width: 14, height: 3, background: s.c }} />{s.k}</span>)}</div><DashLine trend={x.trend} /></div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
        <div className="card card-pad"><div className="eyebrow" style={{ color: 'var(--bad)', marginBottom: 6 }}>Overdue PTW · {x.overdue.length}</div><ExpList rows={x.overdue.map((r) => [r[0], r[1], r[2] + ' Overdue', true])} color="var(--bad)" /></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>My pending approvals</div>{x.pending.map((r, i) => <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '7px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5 }}><div style={{ flex: 1 }}><div className="mono" style={{ color: 'var(--primary-700)' }}>{r[0]}</div><div className="faint">{r[1]}</div></div><Badge kind={pKind(r[3])}>{r[3]}</Badge></div>)}</div>
        <PtwQuickActions onNav={onNav} />
      </div>
    </div>
  );
}
function PtwRegister({ onNav, onOpen }) {
  const x = DB.ptwDash;
  const [page, setPage] = useState(1);
  const [q, setQ] = useState('');
  const filtered = DB.ptw.filter((p) => !q || (p.id + ' ' + p.sub + ' ' + p.type + ' ' + p.loc).toLowerCase().includes(q.toLowerCase()));
  const rows = filtered.slice((page - 1) * 10, page * 10);
  return (
    <div className="page page-wide rise">
      <PageHead title="PTW Register" sub="PTW Management · all permits"><DateFilter /><Btn variant="ghost" icon="documents" size="sm" onClick={() => window.toast('Opening print preview — PTW register', 'info')}>Print</Btn><Btn icon="download" size="sm" onClick={() => window.toast('Register exported (XLSX)', 'info')}>Export</Btn><Btn variant="primary" icon="plus" onClick={() => openPtwForm()}>Create PTW</Btn></PageHead>
      <PtwKpis kpis={x.kpis} />
      <div className="card" style={{ marginBottom: 14 }}>
        <div className="card-head" style={{ flexWrap: 'wrap', gap: 10 }}><Icon name="flag" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">PTW register</div><span className="spacer" /><div className="row" style={{ gap: 7, background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 9, padding: '0 10px', height: 34 }}><Icon name="search" size={14} style={{ color: 'var(--text-3)' }} /><input value={q} onChange={(e) => { setQ(e.target.value); setPage(1); }} placeholder="Search PTW…" style={{ border: 'none', outline: 'none', background: 'transparent', fontSize: 12.5, fontFamily: 'inherit', width: 150 }} /></div></div>
        <table className="tbl"><thead><tr><th>PTW No.</th><th>Type</th><th>Job / work description</th><th>Location</th><th>Requested by</th><th>Requested on</th><th>Planned start</th><th>Status</th><th>Risk</th></tr></thead>
          <tbody>{rows.map((p) => <tr key={p.id} className="clickable" onClick={() => onOpen('ptw', p)}><td className="mono cell-strong" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{p.id}</td><td><span className="tag">{p.type}</span></td><td style={{ fontSize: 12, maxWidth: 220 }}>{p.sub}</td><td className="faint" style={{ fontSize: 11 }}>{p.loc}</td><td><Avatar id={p.by} size="sm" /></td><td className="faint" style={{ fontSize: 11 }}>{p.reqOn}</td><td className="faint" style={{ fontSize: 11 }}>{p.start}</td><td><Badge kind={ptwSt(p.status)} dot={p.status !== 'Closed'}>{p.status}</Badge></td><td><Badge kind={pKind(p.risk)}>{p.risk}</Badge></td></tr>)}</tbody>
        </table>
        <div style={{ padding: '0 14px 14px' }}><Pagination page={page} perPage={10} total={filtered.length} onPage={setPage} /></div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Status distribution</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={x.statusDist} size={100} /><DashLegend data={x.statusDist} /></div></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>By risk level</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={x.byRisk} size={100} /><DashLegend data={x.byRisk} /></div></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>By permit type</div><DashHBars data={x.byType} /></div>
      </div>
    </div>
  );
}
function MyPtw({ onNav, onOpen }) {
  const mine = DB.ptw.slice(0, 8);
  const kpis = [['Total My PTW', 24, 'receipt', 'info'], ['In Progress', 8, 'refresh', 'info'], ['Pending Approval', 6, 'clock', 'warn'], ['Approved', 7, 'check', 'ok'], ['Expiring Soon', 2, 'alert', 'bad'], ['Completed', 12, 'box', 'ok']];
  return (
    <div className="page page-wide rise">
      <PageHead title="My PTW" sub="PTW Management · my permits"><DateFilter /></PageHead>
      <PtwKpis kpis={kpis} />
      <div className="split" style={{ marginBottom: 14 }}>
        <div className="card"><div className="card-head"><Icon name="flag" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">My PTW list</div></div><PtwOverviewTable rows={mine} onOpen={onOpen} /></div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>My PTW status</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={DB.ptwDash.statusDist} size={104} /><DashLegend data={DB.ptwDash.statusDist} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Expiring soon</div><ExpList rows={DB.ptwDash.expiring} /></div>
        </div>
      </div>
    </div>
  );
}
const CAL_DAYS = ['Sun 12', 'Mon 13', 'Tue 14', 'Wed 15', 'Thu 16', 'Fri 17', 'Sat 18'];
function PtwCalendar({ onNav, onOpen }) {
  const ev = { 1: [['08:00', 'PTW-26-105', 'Approved', 'ok']], 2: [['07:00', 'PTW-26-112', 'Approved', 'ok'], ['10:00', 'PTW-26-109', 'In Progress', 'info']], 3: [['08:00', 'PTW-26-110', 'Approved', 'ok'], ['11:00', 'PTW-26-108', 'Approved', 'ok']], 4: [['08:00', 'PTW-26-107', 'Closed', 'neutral'], ['09:30', 'PTW-26-106', 'Expired', 'bad'], ['12:00', 'PTW-26-104', 'Approved', 'ok']], 5: [['08:00', 'PTW-26-111', 'Pending Approval', 'warn'], ['13:00', 'PTW-26-113', 'In Progress', 'info']], 6: [['07:30', 'PTW-26-114', 'Awaiting approval', 'warn']] };
  const tone = { ok: ['var(--ok-bg)', 'var(--ok)'], info: ['var(--info-bg)', 'var(--primary-700)'], warn: ['var(--warn-bg)', 'var(--warn)'], bad: ['var(--bad-bg)', 'var(--bad)'], neutral: ['var(--surface-2)', 'var(--text-2)'] };
  return (
    <div className="page page-wide rise">
      <PageHead title="PTW Calendar" sub="PTW Management · 12–18 May 2024"><DateFilter /><Btn variant="primary" icon="plus" onClick={() => openPtwForm()}>Create PTW</Btn></PageHead>
      <PtwKpis kpis={DB.ptwDash.kpis} />
      <div style={{ display: 'grid', gridTemplateColumns: '3fr 1fr', gap: 14 }}>
        <div className="card card-pad">
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 6 }}>{CAL_DAYS.map((d, di) => (
            <div key={d}><div style={{ textAlign: 'center', fontSize: 11, fontWeight: 700, padding: '6px 0', borderBottom: '2px solid var(--border)', color: di === 3 ? 'var(--primary-700)' : 'var(--text-2)' }}>{d}</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6, minHeight: 180, paddingTop: 6 }}>{(ev[di] || []).map((e, i) => { const t = tone[e[3]]; return <div key={i} className="clickable" style={{ background: t[0], borderLeft: `3px solid ${t[1]}`, borderRadius: 5, padding: '5px 6px', fontSize: 9.5 }} onClick={() => onOpen('ptw', DB.ptw.find((p) => p.id === e[1]) || DB.ptw[0])}><div className="faint">{e[0]}</div><div className="mono" style={{ fontWeight: 700, fontSize: 9.5 }}>{e[1]}</div><Badge kind={ptwSt(e[2])}>{e[2]}</Badge></div>; })}</div>
            </div>
          ))}</div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Calendar legend</div><div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 6 }}>{[['In Progress', 'var(--primary-600)'], ['Pending', 'var(--warn)'], ['Approved', 'var(--ok)'], ['Expired', 'var(--bad)'], ['Closed', 'var(--text-3)']].map(([l, c]) => <span key={l} className="row" style={{ gap: 5, fontSize: 10.5, color: 'var(--text-2)' }}><span style={{ width: 9, height: 9, borderRadius: 2, background: c }} />{l}</span>)}</div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Upcoming expiry</div><ExpList rows={DB.ptwDash.expiring} /></div>
        </div>
      </div>
    </div>
  );
}
const PTW_STEPS = [['Template', 'Create PTW template'], ['PTW Types', 'Define PTW types'], ['PTW Request', 'Raise permit request'], ['Hazard Controls', 'Identify & control hazards'], ['Approval', 'Review & approve'], ['Close Out', 'Complete & close PTW']];
function PtwProcess({ onNav }) {
  return (
    <div className="page page-wide rise">
      <PageHead title="PTW Process" sub="PTW Management · end-to-end permit lifecycle"><Btn variant="primary" icon="plus" onClick={() => openPtwForm()}>New request</Btn></PageHead>
      <div className="card card-pad" style={{ marginBottom: 14, overflowX: 'auto' }}>
        <div className="row" style={{ minWidth: 760 }}>{PTW_STEPS.map((s, i) => (
          <React.Fragment key={s[0]}><div className="row" style={{ gap: 9, flex: 'none' }}><span style={{ width: 28, height: 28, borderRadius: '50%', flex: 'none', display: 'grid', placeItems: 'center', fontSize: 12, fontWeight: 800, background: i === 2 ? 'var(--primary-600)' : i < 2 ? 'var(--ok)' : '#e8edf3', color: i <= 2 ? '#fff' : 'var(--text-3)' }}>{i < 2 ? <Icon name="check" size={14} /> : i + 1}</span><div style={{ lineHeight: 1.15 }}><div style={{ fontSize: 12, fontWeight: 700, color: i === 2 ? 'var(--primary-700)' : 'var(--text)' }}>{s[0]}</div><div className="faint" style={{ fontSize: 9.5 }}>{s[1]}</div></div></div>{i < 5 && <div style={{ flex: 1, minWidth: 16, height: 2, margin: '0 8px', background: i < 2 ? 'var(--ok)' : 'var(--border-2)' }} />}</React.Fragment>
        ))}</div>
      </div>
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — guided permit flow" clause="PTW">AI guides each step — pre-loads the right template & hazard controls for the permit type, live-checks SIMOPS at request, and routes the approval chain. It blocks issue until all required isolations (LOTO) and gas tests are verified.</AINote></div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
        {[['Template', 'Hot Work Permit v2.1 · Cold Work v1.3 · Electrical v2.0 · Excavation v1.5 · Confined Space v1.2'], ['PTW Types', 'Hot Work · Cold Work · Electrical · Excavation · Confined Space · Lifting — each with applicable activities & default risk'], ['PTW Request', 'Type, location, job description, equipment, planned start/finish, persons, attachments (JSA, drawings)'], ['Hazard Controls', 'Fire/explosion, electric shock, toxic fumes, work-at-height, pinch/crush — with control measures & responsible person'], ['Approval', 'Requester → Area Supervisor → HSE Engineer → Operations Manager → Permit Issuer (e-sign workflow)'], ['Close Out', 'Work complete, tools removed, area safe, no incidents — final sign-off & permit closure']].map(([t, d], i) => (
          <div key={t} className="card card-pad"><div className="row" style={{ gap: 8, marginBottom: 6 }}><span style={{ width: 24, height: 24, borderRadius: 7, background: 'var(--info-bg)', color: 'var(--primary-700)', display: 'grid', placeItems: 'center', fontSize: 11, fontWeight: 800 }}>{i + 1}</span><div className="eyebrow" style={{ margin: 0 }}>{t}</div></div><div className="faint" style={{ fontSize: 11.5, lineHeight: 1.5 }}>{d}</div></div>
        ))}
      </div>
    </div>
  );
}
function LotoLifecycle({ onNav }) {
  const steps = [['LOTO Request', 'Create LOTO request', 'ok'], ['Approval', 'Review & approve', 'info'], ['LOTO Removal', 'Perform LOTO removal', 'idle'], ['Close Out', 'Complete & close LOTO', 'idle']];
  return (
    <div className="page page-wide rise">
      <PageHead title="Energy Isolation (LOTO) Lifecycle" sub="PTW Management · LOTO-26-156"><DateFilter /></PageHead>
      <div className="card card-pad" style={{ marginBottom: 14, overflowX: 'auto' }}>
        <div className="row" style={{ minWidth: 620 }}>{steps.map((s, i) => (
          <React.Fragment key={s[0]}><div className="row" style={{ gap: 9, flex: 'none' }}><span style={{ width: 28, height: 28, borderRadius: '50%', flex: 'none', display: 'grid', placeItems: 'center', fontSize: 12, fontWeight: 800, background: i === 1 ? 'var(--primary-600)' : i < 1 ? 'var(--ok)' : '#e8edf3', color: i <= 1 ? '#fff' : 'var(--text-3)' }}>{i < 1 ? <Icon name="check" size={14} /> : i + 1}</span><div style={{ lineHeight: 1.15 }}><div style={{ fontSize: 12.5, fontWeight: 700, color: i === 1 ? 'var(--primary-700)' : 'var(--text)' }}>{s[0]}</div><div className="faint" style={{ fontSize: 10 }}>{s[1]}</div></div></div>{i < 3 && <div style={{ flex: 1, minWidth: 16, height: 2, margin: '0 10px', background: i < 1 ? 'var(--ok)' : 'var(--border-2)' }} />}</React.Fragment>
        ))}</div>
      </div>
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — isolation integrity" clause="LOTO">AI verifies every isolation point against the P&ID and the parent permit (PTW-26-114). It blocks LOTO removal until work-complete is confirmed and zero-energy is re-verified, and flags any isolation overdue for restoration.</AINote></div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 14, alignItems: 'start' }}>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8, color: 'var(--ok)' }}>1 · LOTO Request</div>{[['LOTO No.', 'LR-26-00521'], ['PTW No.', 'PTW-26-114'], ['Location', 'N. Ghawar A-12'], ['Requested by', 'Ahmed Khan'], ['Date', '15 May 07:15']].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11 }}><span className="faint">{k}</span><b>{v}</b></div>)}<div className="eyebrow" style={{ margin: '8px 0 4px', fontSize: 8.5 }}>Equipment to isolate</div><div className="faint" style={{ fontSize: 11 }}>P-201 Pump · Control Panel CP-05 · Air Supply AS-12</div></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8, color: 'var(--primary-700)' }}>2 · Approval <Badge kind="warn">Pending</Badge></div>{[['Area Supervisor', 'ok'], ['HSE Engineer', 'ok'], ['Operations Manager', 'pending'], ['Permit Issuer', 'pending']].map(([k, st]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', fontSize: 11 }}><span>{k}</span>{st === 'ok' ? <Badge kind="ok" icon="check">Approved</Badge> : <Badge kind="warn">Pending</Badge>}</div>)}</div>
        <div className="card card-pad" style={{ opacity: 0.6 }}><div className="eyebrow" style={{ marginBottom: 8 }}>3 · LOTO Removal</div><div className="faint" style={{ fontSize: 11, lineHeight: 1.5 }}>Pre-removal checklist: work complete · tools removed · personnel clear · zero-energy verified. Removal by John Doe.</div></div>
        <div className="card card-pad" style={{ opacity: 0.6 }}><div className="eyebrow" style={{ marginBottom: 8 }}>4 · Close Out</div><div className="faint" style={{ fontSize: 11, lineHeight: 1.5 }}>Final verification: all devices removed · equipment restored · personnel accounted for · system ready · PTW owner informed.</div></div>
      </div>
    </div>
  );
}
const lotoSt = (s) => ({ Active: 'warn', Verified: 'ok', Restored: 'info', Overdue: 'bad', Cancelled: 'neutral' }[s] || 'neutral');
function LotoView({ view, onNav, onOpen }) {
  const x = DB.lotoDash;
  const [tab, setTab] = useState(view === 'dashboard' ? 'dashboard' : 'register');
  const isDash = tab === 'dashboard';
  const [sel, setSel] = useState(DB.loto[0]);
  return (
    <div className="page page-wide rise">
      <PageHead title="Energy Isolation (LOTO)" sub="PTW Management · lock-out / tag-out"><DateFilter /><Btn variant="primary" icon="plus" onClick={() => openLotoForm()}>New isolation</Btn></PageHead>
      <Tabs tabs={[['register', 'LOTO Register'], ['dashboard', 'Dashboard']]} tab={tab} setTab={setTab} />
      <PtwKpis kpis={x.kpis} />
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — isolation watch" clause="LOTO">{DB.loto.filter((l) => l.status === 'Active').length} active isolations · AI flags <b>8 overdue for restoration</b> (LOTO-26-149 conveyor motor is 1 day over). It cross-checks each isolation against its parent permit and the equipment P&ID, and escalates overdue restorations to the area supervisor.</AINote></div>
      {isDash ? (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.3fr 1fr 1fr', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Isolation status</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={x.statusDist} size={104} /><DashLegend data={x.statusDist} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Isolation type distribution</div><DashHBars data={x.typeDist} /></div>
          <div className="card card-pad"><div className="eyebrow" style={{ color: 'var(--bad)', marginBottom: 6 }}>Overdue isolations</div><ExpList rows={x.overdue.map((r) => [r[0], r[1], r[2] + ' Overdue', true])} color="var(--bad)" /></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Recently restored</div>{x.restored.map((r, i) => <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '7px 0', borderBottom: '1px solid var(--border)', fontSize: 11 }}><div style={{ flex: 1 }}><div className="mono" style={{ color: 'var(--primary-700)' }}>{r[0]}</div><div className="faint">{r[1]}</div></div><span className="faint" style={{ whiteSpace: 'nowrap' }}>{r[2]}</span></div>)}</div>
        </div>
      ) : (
        <div className="split">
          <div className="card"><div className="card-head"><Icon name="lock" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Isolation register</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>1–10 of 156</span></div>
            <table className="tbl"><thead><tr><th>Isolation No.</th><th>PTW No.</th><th>Location</th><th>Equipment / system</th><th>Type</th><th>Pts</th><th>Status</th><th>Isolated by</th></tr></thead>
              <tbody>{DB.loto.map((l) => <tr key={l.id} className="clickable" style={{ background: sel.id === l.id ? 'var(--ai-bg)' : undefined }} onClick={() => setSel(l)}><td className="mono cell-strong" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{l.id}</td><td className="mono faint" style={{ fontSize: 10.5 }}>{l.ptw}</td><td className="faint" style={{ fontSize: 11 }}>{l.loc}</td><td style={{ fontSize: 12 }}>{l.equip}</td><td><span className="tag">{l.type}</span></td><td>{l.points}</td><td><Badge kind={lotoSt(l.status)} dot={l.status !== 'Restored'}>{l.status}</Badge></td><td><Avatar id={l.by} size="sm" /></td><td><RowActions onEdit={() => openLotoForm(l)} onDelete={() => dbRemove('loto', 'id', l.id)} /></td></tr>)}</tbody>
            </table>
          </div>
          <div className="card card-pad">
            <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Isolation details</div><Badge kind={lotoSt(sel.status)}>{sel.status}</Badge></div>
            {[['Isolation No.', sel.id], ['PTW No.', sel.ptw], ['Location', sel.loc], ['Equipment', sel.equip], ['Type', sel.type], ['Isolation points', sel.points], ['Isolated on', sel.isolatedOn], ['Isolated by', '—'], ['Verified by', '—']].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5, gap: 8 }}><span className="faint">{k}</span><b style={{ textAlign: 'right' }}>{k.includes('by') ? '' : v}{k === 'Isolated by' ? <Avatar id={sel.by} size="sm" /> : k === 'Verified by' ? (sel.verifiedBy !== '—' ? <Avatar id={sel.verifiedBy} size="sm" /> : '—') : ''}</b></div>)}
            <Btn variant="ghost" icon="ext" size="sm" style={{ marginTop: 8, width: '100%' }} onClick={() => onNav('lotolifecycle')}>Open LOTO lifecycle</Btn>
          </div>
        </div>
      )}
    </div>
  );
}

/* ===================== COMPETENCY (AI gap) ========================= */
function CompetencyModule({ onNav }) {
  const [tab, setTab] = useState('matrix');
  const cols = ['H2S', 'CSE', 'N2 Ops', 'Rigging', 'CSWIP', 'NDT L2', 'NEBOSH', 'First Aid', 'Aramco CSTP', 'Medical'];
  const mark = { V: ['var(--ok)', 'check'], E: ['var(--warn)', 'alert'], X: ['var(--bad)', 'x'] };
  const expCol = (d) => ({ fontWeight: 600, color: d <= DB.TODAY ? 'var(--bad)' : (d - DB.TODAY) / 864e5 < 30 ? 'var(--warn)' : 'var(--text)' });
  const cl = DB.certsLicenses; const soon = (d) => d > DB.TODAY && (d - DB.TODAY) / 864e5 < 30;
  const gaps = DB.competency.filter((r) => r.gap).length;
  const cKpis = [['Personnel tracked', DB.competency.length, 'users', 'info'], ['Competency gaps', gaps, 'alert', 'bad'], ['Certs expiring 30d', cl.filter((c) => soon(c.aramco) || soon(c.medical) || soon(c.license)).length, 'clock', 'warn'], ['Medical lapses', cl.filter((c) => c.medical <= DB.TODAY).length, 'shield', 'bad'], ['Aramco CSTP valid', cl.filter((c) => c.aramco > DB.TODAY).length, 'check', 'ok'], ['Training due', 6, 'calendar', 'ai']];
  const gapByCompetency = [{ l: 'Aramco CSTP', v: 2, c: '#ef4444' }, { l: 'Rigging', v: 2, c: '#f59e0b' }, { l: 'Confined space', v: 1, c: '#f97316' }, { l: 'NDT L2', v: 1, c: '#2563eb' }, { l: 'First Aid', v: 1, c: '#22c55e' }];
  const certStatus = [{ l: 'Valid', v: 22, c: '#22c55e' }, { l: 'Expiring ≤30d', v: 6, c: '#f59e0b' }, { l: 'Expired', v: 3, c: '#ef4444' }];
  return (
    <div className="page page-wide rise">
      <PageHead title="Competency & Training" sub="Competency matrix · trade certs · medical · driving licence · Aramco & client-specific — AI gap analysis">
        <Btn icon="users" variant="ai" size="sm" onClick={() => openAssign()}>Assign to task (AI)</Btn>
        <Btn variant="primary" icon="plus" onClick={() => openTrainingForm()}>Add training</Btn>
      </PageHead>
      <AINote title="Competency gaps before P-211 mobilization" clause="ISO 45001 §7.2" action="Build renewal plan" onAction={() => window.toast('Renewal & training plan generated · 7 actions')}>
        2 N₂-unit operators lack a current Aramco CSTP and 1 medical fitness lapses in 14 days. Sentinel recommends scheduling refreshers now to keep P-211 fully crewed and audit-ready.
      </AINote>
      <div style={{ marginTop: 16 }}><Tabs tabs={[['matrix', 'Competency matrix'], ['dashboard', 'Training dashboard'], ['tracking', 'Training tracking'], ['licenses', 'Certifications & licences']]} tab={tab} setTab={setTab} /></div>
      {tab === 'dashboard' && <ModuleDash kpis={cKpis} panels={[
        { title: 'Certification status', node: <DashSplit data={certStatus} />, w: '1fr' },
        { title: 'Compliance by department', node: <DashHBars data={[{ l: 'Operations', v: 82, c: '#2563eb' }, { l: 'Maintenance', v: 76, c: '#f59e0b' }, { l: 'HSE', v: 88, c: '#22c55e' }, { l: 'Engineering', v: 79, c: '#7a5bff' }, { l: 'Projects', v: 71, c: '#ef4444' }]} />, w: '1.2fr' },
        { title: 'Compliance trend (6 mo)', node: <DashLine trend={{ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#22c55e', d: [72, 76, 76, 80, 81, 82] }] }} />, w: '1.2fr' },
      ]} />}
      {tab === 'tracking' && (
        <div className="card"><div className="card-head"><Icon name="users" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Training tracking — internal employees</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>by employee × course</span></div>
          <table className="tbl"><thead><tr><th>Employee</th><th>Role</th><th>Course</th><th>Type</th><th>Due</th><th>Status</th><th>Certificate</th></tr></thead>
            <tbody>{DB.competency.flatMap((r, ri) => { const s = DB.staffById(r.staff); const courses = [['Work at Height', 'Mandatory'], ['Permit to Work', 'Mandatory'], ['LOTO Awareness', 'Mandatory'], ['Fire Safety', 'Recommended']]; const cc = courses[ri % courses.length]; const st = ['Completed', 'In Progress', 'Overdue', 'Completed', 'Not Started'][ri % 5]; return [(
              <tr key={r.staff + '-' + ri} className="clickable" onClick={() => window.toast(s.name + ' training record', 'info')}>
                <td><div className="row" style={{ gap: 7 }}><Avatar id={r.staff} size="sm" /><span style={{ fontSize: 12.5, fontWeight: 600 }}>{s.name}</span></div></td>
                <td className="faint" style={{ fontSize: 11.5 }}>{r.role}</td><td style={{ fontSize: 12.5 }}>{cc[0]}</td><td><span className="tag">{cc[1]}</span></td>
                <td className="faint" style={{ fontSize: 11.5 }}>{DB.rel(DB.D((ri % 5) * 7 - 7))}</td>
                <td><Badge kind={st === 'Completed' ? 'ok' : st === 'Overdue' ? 'bad' : st === 'In Progress' ? 'warn' : 'neutral'} dot={st !== 'Completed'}>{st}</Badge></td>
                <td>{st === 'Completed' ? <Icon name="documents" size={14} style={{ color: 'var(--primary-600)' }} /> : <span className="faint">—</span>}</td>
              </tr>
            )]; })}</tbody>
          </table>
        </div>
      )}
      {tab === 'matrix' && (
        <div className="card" style={{ overflowX: 'auto' }}>
          <div className="card-head"><Icon name="users" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Competency matrix (by method & asset class)</div></div>
          <table className="tbl">
            <thead><tr><th>Person / role</th>{cols.map((c) => <th key={c} style={{ textAlign: 'center', fontSize: 10 }}>{c}</th>)}<th>Gap</th></tr></thead>
            <tbody>{DB.competency.map((r, ri) => { const s = DB.staffById(r.staff); return (
              <tr key={r.staff + '-' + ri}>
                <td><div className="row" style={{ gap: 8 }}><Avatar id={r.staff} size="sm" /><div><div style={{ fontSize: 12.5, fontWeight: 650 }}>{s.name}</div><div className="faint" style={{ fontSize: 10.5 }}>{r.role}</div></div></div></td>
                {cols.map((c) => { const v = r.certs[c]; const mm = v && mark[v]; return <td key={c} style={{ textAlign: 'center' }}>{mm ? <Icon name={mm[1]} size={13} style={{ color: mm[0] }} /> : <span className="faint">·</span>}</td>; })}
                <td>{r.gap ? <Badge kind="warn" dot>Action</Badge> : <Badge kind="ok">Clear</Badge>}</td>
              </tr>
            ); })}</tbody>
          </table>
          <div className="card-body"><div className="row" style={{ gap: 16, fontSize: 11.5 }}><span className="row" style={{ gap: 5 }}><Icon name="check" size={12} style={{ color: 'var(--ok)' }} />Valid</span><span className="row" style={{ gap: 5 }}><Icon name="alert" size={12} style={{ color: 'var(--warn)' }} />Expiring</span><span className="row" style={{ gap: 5 }}><Icon name="x" size={12} style={{ color: 'var(--bad)' }} />Missing</span></div></div>
        </div>
      )}
      {tab === 'licenses' && (
        <div className="card"><div className="card-head"><Icon name="certificate" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Certifications, medical & licences</div></div>
          <table className="tbl"><thead><tr><th>Person</th><th>Trade certification</th><th>Medical fitness</th><th>Driving licence</th><th>Aramco CSTP</th><th>Client-specific</th></tr></thead>
            <tbody>{DB.certsLicenses.map((c, ci) => { const s = DB.staffById(c.staff); return (
              <tr key={c.staff + '-' + ci}><td><div className="row" style={{ gap: 7 }}><Avatar id={c.staff} size="sm" /><span style={{ fontSize: 12.5, fontWeight: 600 }}>{s.name.split(' ')[0]}</span></div></td>
                <td style={{ fontSize: 12 }}>{c.trade}</td><td><span style={expCol(c.medical)}>{DB.rel(c.medical)}</span></td><td><span style={expCol(c.license)}>{DB.rel(c.license)}</span></td>
                <td><span style={expCol(c.aramco)}>{c.aramco <= DB.TODAY ? 'Expired' : DB.rel(c.aramco)}</span></td><td style={{ fontSize: 11.5 }}>{c.client} <span className="faint">· {DB.rel(c.clientExp)}</span></td></tr>
            ); })}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}

/* ===================== ASSET INTEGRITY ============================= */
function AssetsModule({ onNav }) {
  const [tab, setTab] = useState('register');
  const stKind = (s) => /valid|certified|in-cal|serviceable|closed/i.test(s) ? 'ok' : /overdue|re-inspect/i.test(s) ? 'bad' : 'warn';
  const aKpis = [['Registered assets', DB.assets.length, 'cpu', 'info'], ['PM work orders', DB.pmOrders.length, 'refresh', 'ai'], ['Open breakdowns', DB.breakdowns.filter((b) => b.status !== 'Closed').length, 'alert', 'bad'], ['TPI due', DB.tpInspections.filter((t) => t.status !== 'Valid' && t.status !== 'Certified').length, 'clipboard', 'warn'], ['Calibrations due', DB.calibrations.filter((c) => c.status && /due|overdue/i.test(c.status)).length, 'clock', 'warn'], ['Availability', '94%', 'check', 'ok']];
  const byClass = [{ l: 'Mobile units', v: 12, c: '#2563eb' }, { l: 'Lifting gear', v: 9, c: '#f59e0b' }, { l: 'Test equipment', v: 8, c: '#7a5bff' }, { l: 'Tools', v: 6, c: '#22c55e' }];
  const certStatus = [{ l: 'Valid', v: 24, c: '#22c55e' }, { l: 'Due ≤30d', v: 7, c: '#f59e0b' }, { l: 'Overdue', v: 4, c: '#ef4444' }];
  const aTrend = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#2563eb', d: [3, 2, 4, 3, 5, 4] }, { c: '#ef4444', d: [1, 2, 1, 2, 1, 1] }] };
  return (
    <div className="page page-wide rise">
      <PageHead title="Asset Integrity" sub="Mobile units & tools · certification · PM · breakdown · 3rd-party inspection · calibration — AI forecasting">
        <Btn icon="cpu" variant="ai" size="sm" onClick={() => openAssignAsset()}>Assign to job (AI)</Btn>
        <Btn variant="primary" icon="plus" onClick={() => openAssetForm()}>Register asset</Btn>
      </PageHead>
      <div style={{ marginBottom: 14 }}><AINote title="Equipment compliance forecast" clause="AIX · forecast" action="Schedule renewals" onAction={() => window.toast('Renewal & PM plan generated', 'info')}>Hydrotest Pump HP-03 certification + 3rd-party inspection are overdue and block P-211; a lifting sling set is due in 9 days. AI forecasts 3 more certs lapsing within the mobilization window — schedule now to keep readiness above 95%.</AINote></div>
      <Tabs tabs={[['register', 'Register'], ['dashboard', 'Dashboard'], ['maint', 'Maintenance & tracking'], ['caltrack', 'Inspections & calibration'], ['pm', 'Preventive Maintenance'], ['breakdown', 'Breakdown'], ['tpi', '3rd-party Inspection'], ['cal', 'Calibration']]} tab={tab} setTab={setTab} />
      {tab === 'dashboard' && <ModuleDash kpis={aKpis} panels={[
        { title: 'Assets by class', node: <DashSplit data={byClass} />, w: '1fr' },
        { title: 'Certification status', node: <DashSplit data={certStatus} />, w: '1fr' },
        { title: 'PM completed vs breakdowns (6 mo)', node: <DashLine trend={aTrend} />, w: '1.3fr' },
      ]} />}
      {tab === 'maint' && <React.Fragment>
        <ModuleDash kpis={[['Total assets', '1,248', 'cpu', 'info'], ['Operational', 982, 'check', 'ok'], ['Under maintenance', 86, 'refresh', 'warn'], ['Out of service', 42, 'alert', 'bad'], ['Planned (month)', 124, 'calendar', 'ai'], ['Overdue', 37, 'clock', 'bad']]} panels={[
          { title: 'Maintenance by type (month)', node: <DashSplit data={[{ l: 'Planned', v: 124, c: '#2563eb' }, { l: 'Periodic', v: 78, c: '#7a5bff' }, { l: 'Breakdown', v: 45, c: '#ef4444' }]} />, w: '1fr' },
          { title: 'Work-order status', node: <DashHBars data={[{ l: 'Open', v: 62, c: '#f59e0b' }, { l: 'In progress', v: 18, c: '#2563eb' }, { l: 'On hold', v: 8, c: '#94a3b8' }, { l: 'Completed', v: 192, c: '#22c55e' }]} />, w: '1.2fr' },
          { title: 'Asset utilisation', node: <DashSplit data={[{ l: 'Active', v: 612, c: '#22c55e' }, { l: 'Idle', v: 208, c: '#f59e0b' }, { l: 'Offline', v: 92, c: '#94a3b8' }]} />, w: '1fr' },
        ]} />
        <div className="card" style={{ marginTop: 16 }}><div className="card-head"><Icon name="refresh" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Upcoming maintenance (next 7 days)</div></div>
          <table className="tbl"><thead><tr><th>WO No.</th><th>Equipment</th><th>Equipment ID</th><th>Type</th><th>Schedule</th><th>Priority</th><th>Status</th></tr></thead>
            <tbody>{DB.maintWO.map((w) => <tr key={w.id} className="clickable" onClick={() => window.toast(w.id + ' work order', 'info')}><td className="mono cell-strong" style={{ fontSize: 11 }}>{w.id}</td><td style={{ fontSize: 12.5 }}>{w.equip}</td><td className="mono faint" style={{ fontSize: 11 }}>{w.eqid}</td><td><span className="tag">{w.type}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{DB.rel(w.date)}</td><td><Badge kind={w.priority === 'High' ? 'bad' : w.priority === 'Medium' ? 'warn' : 'ok'}>{w.priority}</Badge></td><td><Badge kind={w.status === 'Completed' ? 'ok' : w.status === 'In Progress' ? 'warn' : 'info'} dot={w.status !== 'Completed'}>{w.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      </React.Fragment>}
      {tab === 'caltrack' && <React.Fragment>
        <ModuleDash kpis={[['Total equipment', '1,248', 'cpu', 'info'], ['Inspections due', 86, 'clipboard', 'warn'], ['Overdue inspections', 24, 'alert', 'bad'], ['Calibrations due', 72, 'gauge', 'warn'], ['Overdue calibrations', 18, 'clock', 'bad'], ['Compliance', '91.4%', 'trend', 'ok']]} panels={[
          { title: 'Compliance overview', node: <DashSplit data={[{ l: 'Compliant', v: 284, c: '#22c55e' }, { l: 'Due soon', v: 17, c: '#f59e0b' }, { l: 'Overdue', v: 11, c: '#ef4444' }]} />, w: '1fr' },
          { title: 'Calibration status', node: <DashHBars data={[{ l: 'Compliant', v: 318, c: '#22c55e' }, { l: 'Due soon', v: 72, c: '#f59e0b' }, { l: 'Overdue', v: 18, c: '#ef4444' }]} />, w: '1.2fr' },
          { title: 'Inspection status', node: <DashHBars data={[{ l: 'Completed', v: 284, c: '#22c55e' }, { l: 'In progress', v: 32, c: '#2563eb' }, { l: 'Due', v: 86, c: '#f59e0b' }, { l: 'Overdue', v: 24, c: '#ef4444' }]} />, w: '1.2fr' },
        ]} />
        <div className="card" style={{ marginTop: 16 }}><div className="card-head"><Icon name="gauge" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Calibration due & overdue</div></div>
          <table className="tbl"><thead><tr><th>Cal. ID</th><th>Equipment</th><th>Equipment ID</th><th>Type</th><th>Due date</th><th>Certificate</th><th>Status</th></tr></thead>
            <tbody>{DB.calItems.map((c) => <tr key={c.id} className="clickable" onClick={() => window.toast(c.id + ' calibration record', 'info')}><td className="mono cell-strong" style={{ fontSize: 11 }}>{c.id}</td><td style={{ fontSize: 12.5 }}>{c.equip}</td><td className="mono faint" style={{ fontSize: 11 }}>{c.eqid}</td><td><span className="tag">{c.type}</span></td><td><span style={{ fontSize: 11.5, fontWeight: 600, color: c.status === 'Overdue' ? 'var(--bad)' : 'var(--text)' }}>{DB.rel(c.due)}</span></td><td className="mono faint" style={{ fontSize: 10.5 }}>{c.cert}</td><td><Badge kind={c.status === 'Compliant' ? 'ok' : c.status === 'Overdue' ? 'bad' : 'warn'} dot={c.status !== 'Compliant'}>{c.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      </React.Fragment>}
      {tab === 'register' && (
        <div className="card"><div className="card-head"><Icon name="cpu" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Equipment register & certification</div><span className="faint" style={{ fontSize: 11, marginLeft: 8 }}>N₂ units · compressors · hydrotest pumps · lifting · flange tools · gauges</span></div>
          <table className="tbl"><thead><tr><th>Asset</th><th>Name</th><th>Type</th><th>Project</th><th>Certification</th><th>Readiness</th><th>Status</th></tr></thead>
            <tbody>{DB.assets.map((a) => (
              <tr key={a.id} className="clickable" onClick={() => window.toast(`${a.id} — ${a.name}`, 'info')}>
                <td className="mono cell-strong" style={{ fontSize: 11.5 }}>{a.id}</td><td style={{ fontSize: 12.5 }}>{a.name}</td><td className="faint" style={{ fontSize: 12 }}>{a.type}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{a.project}</td>
                <td><span style={{ fontWeight: 600, color: a.cert <= DB.TODAY ? 'var(--bad)' : (a.cert - DB.TODAY) / 864e5 < 30 ? 'var(--warn)' : 'var(--text)' }}>{DB.rel(a.cert)}</span></td>
                <td style={{ width: 110 }}><div className="row" style={{ gap: 6 }}><div style={{ width: 60 }}><Bar pct={a.readiness} color={scoreColor(a.readiness)} /></div><span className="mono faint" style={{ fontSize: 11 }}>{a.readiness}%</span></div></td>
                <td><Badge kind={a.status === 'Certified' ? 'ok' : a.status === 'Due soon' ? 'warn' : 'bad'} dot={a.status !== 'Certified'}>{a.status}</Badge></td>
                <td><RowActions onEdit={() => openAssetForm(a)} onDelete={() => dbRemove('assets', 'id', a.id)} /></td>
              </tr>
            ))}</tbody>
          </table>
        </div>
      )}
      {tab === 'pm' && (
        <div className="card"><div className="card-head"><Icon name="wrench" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Preventive maintenance work orders</div></div>
          <table className="tbl"><thead><tr><th>WO</th><th>Asset</th><th>Task</th><th>Due</th><th>Criticality</th><th>Owner</th><th>Status</th></tr></thead>
            <tbody>{DB.pmOrders.map((p) => <tr key={p.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{p.id}</td><td style={{ fontSize: 12.5 }}>{p.asset}</td><td className="faint" style={{ fontSize: 12 }}>{p.task}</td><td><span style={{ fontWeight: 600, color: p.due <= DB.TODAY ? 'var(--bad)' : 'var(--text)' }}>{DB.rel(p.due)}</span></td><td><Badge kind={p.crit === 'Critical' ? 'bad' : p.crit === 'High' ? 'warn' : 'neutral'}>{p.crit}</Badge></td><td><Avatar id={p.assignee} size="sm" /></td><td><Badge kind={p.status === 'Overdue' ? 'bad' : 'info'} dot>{p.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'breakdown' && (
        <div className="card"><div className="card-head"><Icon name="alert" size={16} style={{ color: 'var(--warn)' }} /><div className="h-sec">Breakdown maintenance & downtime</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Asset</th><th>Fault</th><th>Downtime</th><th>Date</th><th>Cost (SAR)</th><th>Status</th></tr></thead>
            <tbody>{DB.breakdowns.map((b) => <tr key={b.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{b.id}</td><td style={{ fontSize: 12.5 }}>{b.asset}</td><td className="faint" style={{ fontSize: 12 }}>{b.fault}</td><td><b>{b.down}</b></td><td className="faint">{DB.fmt(b.date)}</td><td className="mono">{b.cost}</td><td><Badge kind={b.status === 'Closed' ? 'ok' : 'warn'} dot={b.status !== 'Closed'}>{b.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'tpi' && (
        <div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Third-party inspection tracking</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Asset</th><th>Inspection</th><th>Body</th><th>Date</th><th>Result</th><th>Status</th></tr></thead>
            <tbody>{DB.tpInspections.map((t) => <tr key={t.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{t.id}</td><td style={{ fontSize: 12.5 }}>{t.asset}</td><td className="faint" style={{ fontSize: 12 }}>{t.type}</td><td>{t.body}</td><td className="faint">{DB.rel(t.date)}</td><td><Badge kind={t.result === 'Pass' ? 'ok' : 'warn'}>{t.result}</Badge></td><td><Badge kind={stKind(t.status)} dot={t.status !== 'Valid'}>{t.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'cal' && (
        <div className="card"><div className="card-head"><Icon name="trend" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Calibration tracking</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Instrument</th><th>Range</th><th>Cert</th><th>Due</th><th>Status</th></tr></thead>
            <tbody>{DB.calibrations.map((c) => <tr key={c.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{c.id}</td><td style={{ fontSize: 12.5 }}>{c.asset}</td><td className="faint" style={{ fontSize: 12 }}>{c.range}</td><td className="faint" style={{ fontSize: 12 }}>{c.cert}</td><td><span style={{ fontWeight: 600, color: c.due <= DB.TODAY ? 'var(--bad)' : 'var(--text)' }}>{DB.rel(c.due)}</span></td><td><Badge kind={stKind(c.status)} dot={c.status !== 'In-cal'}>{c.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}

/* ===================== INDUSTRIAL SERVICES ========================= */
function ServicesModule({ onNav }) {
  const [tab, setTab] = useState('nitrogen');
  const cfg = {
    nitrogen: { label: 'Nitrogen', cols: ['Ref', 'Activity', 'Project', 'Volume', 'Purity', 'O₂', 'Result', 'Date'], rows: DB.services.nitrogen.map((r) => [r.id, r.activity, r.project, r.vol, r.purity, r.o2, r.result, DB.fmt(r.date)]) },
    pipeline: { label: 'Pipeline', cols: ['Ref', 'Activity', 'Project', 'Detail', 'Result', 'Date'], rows: DB.services.pipeline.map((r) => [r.id, r.activity, r.project, r.length || r.joints, r.result, DB.fmt(r.date)]) },
    water: { label: 'Water', cols: ['Ref', 'Activity', 'Project', 'Result', 'Date'], rows: DB.services.water.map((r) => [r.id, r.activity, r.project, r.result, DB.fmt(r.date)]) },
    chemical: { label: 'Chemical', cols: ['Ref', 'Activity', 'Project', 'Status', 'Date'], rows: DB.services.chemical.map((r) => [r.id, r.activity, r.project, r.result, DB.fmt(r.date)]) },
  };
  const c = cfg[tab];
  const sCount = { nitrogen: DB.services.nitrogen.length, pipeline: DB.services.pipeline.length, water: DB.services.water.length, chemical: DB.services.chemical.length };
  const sTotal = Object.values(sCount).reduce((s, v) => s + v, 0);
  const sKpis = [['Service records', sTotal, 'box', 'info'], ['Nitrogen jobs', sCount.nitrogen, 'cpu', 'ai'], ['Pipeline jobs', sCount.pipeline, 'workflow', 'info'], ['Water jobs', sCount.water, 'shield', 'ok'], ['Chemical jobs', sCount.chemical, 'alert', 'warn'], ['Pass rate', '98%', 'check', 'ok']];
  const byType = [{ l: 'Nitrogen', v: sCount.nitrogen, c: '#2563eb' }, { l: 'Pipeline', v: sCount.pipeline, c: '#7a5bff' }, { l: 'Water', v: sCount.water, c: '#0e7490' }, { l: 'Chemical', v: sCount.chemical, c: '#f59e0b' }].filter((x) => x.v);
  const sTrend = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#2563eb', d: [8, 11, 9, 13, 12, 14] }] };
  return (
    <div className="page page-wide rise">
      <PageHead title="Industrial Services" sub="Nitrogen · pipeline · water · chemical — service records & traceability">
        <Btn variant="primary" icon="plus" onClick={() => openServiceForm()}>New record</Btn>
      </PageHead>
      <Tabs tabs={[['dashboard', 'Dashboard'], ...Object.entries(cfg).map(([k, v]) => [k, v.label])]} tab={tab} setTab={setTab} />
      {tab === 'dashboard' && <ModuleDash kpis={sKpis} panels={[
        { title: 'Records by service type', node: <DashSplit data={byType} />, w: '1fr' },
        { title: 'Acceptance results', node: <DashHBars data={[{ l: 'Pass / accepted', v: sTotal - 1, c: '#22c55e' }, { l: 'Re-work', v: 1, c: '#f59e0b' }]} />, w: '1.2fr' },
        { title: 'Jobs delivered (6 mo)', node: <DashLine trend={sTrend} />, w: '1.3fr' },
      ]} />}
      {c && <div style={{ marginBottom: 14 }}><AINote title="Service-quality signal" clause="AIX">{tab === 'nitrogen' ? 'AI cross-checks N₂ purity (99.6%) and O₂ (0.4%) against acceptance — all within spec; purge records are certificate-ready.' : tab === 'pipeline' ? 'AI verifies bolt-torque values against the flange-management spec — 46 joints compliant; pre-commissioning dossier auto-compiling.' : tab === 'water' ? 'AI confirms hydrotest 90-bar/24h hold and chloride < 50 ppm meet the ITP — wastewater manifest logged for the environmental register.' : 'AI checks chemical SDS/COSHH currency before the cleaning plan is approved — all SDS current; consumption tracked against the inventory.'}</AINote></div>}
      {c && <div className="card"><table className="tbl">
        <thead><tr>{c.cols.map((h) => <th key={h}>{h}</th>)}</tr></thead>
        <tbody>{c.rows.map((row, i) => (
          <tr key={i} className="clickable" onClick={() => window.toast(`${row[0]} — ${row[1]}`, 'info')}>
            {row.map((cell, j) => j === 0 ? <td key={j} className="mono cell-strong" style={{ fontSize: 11.5 }}>{cell}</td> : j === row.length - 2 && (cell === 'Pass' || cell === 'Logged' || cell === 'Current') ? <td key={j}><Badge kind="ok">{cell}</Badge></td> : <td key={j} style={{ fontSize: 12 }}>{cell}</td>)}
          </tr>
        ))}</tbody>
      </table></div>}
      {tab === 'chemical' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginTop: 16 }}>
          <div className="card"><div className="card-head"><Icon name="alert" size={16} style={{ color: 'var(--warn)' }} /><div className="h-sec" style={{ fontSize: 13.5 }}>COSHH assessments</div></div>
            <table className="tbl"><thead><tr><th>Ref</th><th>Chemical</th><th>Hazard</th><th>Review</th><th>Status</th></tr></thead>
              <tbody>{DB.coshh.map((c) => <tr key={c.id}><td className="mono cell-strong" style={{ fontSize: 11 }}>{c.id}</td><td style={{ fontSize: 12 }}>{c.chemical}</td><td className="faint" style={{ fontSize: 11.5 }}>{c.hazard}</td><td><span style={{ fontWeight: 600, color: c.review <= DB.TODAY ? 'var(--bad)' : 'var(--text)' }}>{DB.rel(c.review)}</span></td><td><Badge kind={c.status === 'Assessed' ? 'ok' : 'warn'} dot={c.status !== 'Assessed'}>{c.status}</Badge></td></tr>)}</tbody>
            </table>
          </div>
          <div className="card"><div className="card-head"><Icon name="box" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec" style={{ fontSize: 13.5 }}>Chemical inventory & consumption</div></div>
            <table className="tbl"><thead><tr><th>Chemical</th><th>In stock</th><th>Used (30d)</th><th>Status</th></tr></thead>
              <tbody>{DB.chemInventory.map((c) => <tr key={c.id}><td style={{ fontSize: 12 }}>{c.chemical}</td><td className="mono">{c.qty}</td><td className="mono faint">{c.used30d}</td><td><Badge kind={c.status === 'OK' ? 'ok' : 'warn'} dot={c.status !== 'OK'}>{c.status}</Badge></td></tr>)}</tbody>
            </table>
            <div className="card-body" style={{ borderTop: '1px solid var(--border)' }}><AINote title="Reorder & consumption" clause="AIX">Corrosion inhibitor is below minimum with rising use on P-219 — AI recommends reorder now to avoid a chemical-cleaning stand-down.</AINote></div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ===================== SIMPLE LIST MODULES ========================= */
function tableModule(title, sub, head, rows, onRow, ai, action) {
  return (
    <div className="page page-wide rise">
      <PageHead title={title} sub={sub}>{action}</PageHead>
      {ai}
      <div className="card"><table className="tbl">
        <thead><tr>{head.map((h) => <th key={h}>{h}</th>)}</tr></thead>
        <tbody>{rows.map((r, i) => <tr key={i} className={onRow ? 'clickable' : ''} onClick={onRow ? () => onRow(i) : undefined}>{r.map((c, j) => <td key={j} style={{ fontSize: 12.5 }}>{c}</td>)}</tr>)}</tbody>
      </table></div>
    </div>
  );
}
/* Reusable reporting-dashboard scaffold — KPI row + chart/list panels.
   kpis: [[label, value, icon, tone], ...]   panels: [{ title, node, w }] (w = grid fraction) */
function ModuleDash({ kpis, panels }) {
  return (
    <React.Fragment>
      <div className="dk-kpis">{kpis.map(([k, v, ic, tone], i) => { const t = DASH_TONE[tone] || DASH_TONE.info; return (
        <div key={i} className="card" style={{ padding: '13px 14px', minWidth: 0 }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div style={{ minWidth: 0 }}><div style={{ fontSize: 23, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>
      ); })}</div>
      {panels && panels.length > 0 && <div className="dk-panels" style={{ gridTemplateColumns: panels.map((p) => p.w || '1fr').join(' ') }}>{panels.map((p, i) => (
        <div key={i} className="card card-pad" style={{ minWidth: 0 }}><div className="eyebrow" style={{ marginBottom: 10 }}>{p.title}</div>{p.node}</div>
      ))}</div>}
    </React.Fragment>
  );
}
/* Compact donut+legend panel body */
function DashSplit({ data }) {
  return <div className="row" style={{ gap: 10, alignItems: 'center' }}><DashDonut data={data} size={104} /><DashLegend data={data} /></div>;
}
/* Horizontal lifecycle stepper — current is 0-based index of the in-progress step */
function Stepper({ steps, current, sub }) {
  return (
    <div className="card card-pad" style={{ overflowX: 'auto' }}>
      <div className="row" style={{ gap: 0, alignItems: 'flex-start', minWidth: steps.length * 130 }}>
        {steps.map((s, i) => {
          const done = i < current, on = i === current;
          const col = done ? 'var(--ok)' : on ? 'var(--primary-600)' : 'var(--surface-2)';
          const tcol = done || on ? '#fff' : 'var(--text-3)';
          return (
            <React.Fragment key={i}>
              <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: 1, minWidth: 110 }}>
                <span style={{ width: 32, height: 32, borderRadius: '50%', background: col, color: tcol, display: 'grid', placeItems: 'center', fontWeight: 800, fontSize: 13, border: on ? '3px solid var(--primary-100)' : 'none', flex: 'none' }}>{done ? <Icon name="check" size={16} /> : i + 1}</span>
                <div style={{ fontSize: 12, fontWeight: 700, marginTop: 6, textAlign: 'center', color: on ? 'var(--primary-700)' : 'var(--text)' }}>{s}</div>
                {sub && <div className="faint" style={{ fontSize: 10, textAlign: 'center', marginTop: 1, lineHeight: 1.3 }}>{sub[i]}</div>}
              </div>
              {i < steps.length - 1 && <div style={{ flex: 1, height: 2, background: i < current ? 'var(--ok)' : 'var(--border)', marginTop: 16, minWidth: 20 }} />}
            </React.Fragment>
          );
        })}
      </div>
    </div>
  );
}
function RiskScoreMatrix({ labels }) {
  const cons = ['Insignificant', 'Minor', 'Moderate', 'Major', 'Catastrophic'];
  const like = ['Almost Certain', 'Likely', 'Possible', 'Unlikely', 'Rare'];
  const band = (r) => r >= 17 ? ['#ef4444', 'Extreme'] : r >= 10 ? ['#f97316', 'High'] : r >= 5 ? ['#f59e0b', 'Medium'] : ['#22c55e', 'Low'];
  return (
    <div style={{ overflowX: 'auto' }}>
      <div className="row" style={{ gap: 4, marginBottom: 4 }}><span style={{ width: 80 }} />{[1, 2, 3, 4, 5].map((c, i) => <div key={c} style={{ flex: 1, textAlign: 'center', fontSize: 9, color: 'var(--text-3)', minWidth: 56 }}><b style={{ fontSize: 11, color: 'var(--text)' }}>{c}</b><div>{cons[i]}</div></div>)}</div>
      {[5, 4, 3, 2, 1].map((l, li) => (
        <div key={l} className="row" style={{ gap: 4, marginBottom: 4, alignItems: 'stretch' }}>
          <span style={{ width: 80, fontSize: 8.5, color: 'var(--text-3)', textAlign: 'right', alignSelf: 'center', lineHeight: 1.05 }}><b style={{ fontSize: 11, color: 'var(--text)' }}>{l}</b> {like[li]}</span>
          {[1, 2, 3, 4, 5].map((c) => { const r = l * c; const [col, lvl] = band(r); return <div key={c} style={{ flex: 1, minWidth: 56, minHeight: labels ? 44 : 30, borderRadius: 5, background: col, display: 'grid', placeItems: 'center', color: '#fff', lineHeight: 1.1 }}><b style={{ fontSize: 13 }}>{r}</b>{labels && <span style={{ fontSize: 8.5 }}>{lvl}</span>}</div>; })}
        </div>
      ))}
    </div>
  );
}
/* ---- RCA methods used by Risk Assessment (severity-driven) ---- */
function rcaWhys(rec) {
  return [
    [`Why can "${rec.title}" cause harm?`, 'Hazardous energy / exposure is present in the task'],
    ['Why is the hazard present?', 'Task is performed close to people / assets'],
    ['Why are people exposed?', 'Existing control (' + (rec.control || 'TBD') + ') is not always applied'],
    ['Why is the control not always applied?', 'No verification gate before the task starts'],
    ['Why is there no gate?', 'Risk not classified high enough to mandate a permit check'],
  ];
}
function RcaFiveWhy({ rec }) {
  const w = rcaWhys(rec);
  return (
    <div className="card card-pad">
      <div className="row" style={{ justifyContent: 'space-between', marginBottom: 10 }}><div className="eyebrow" style={{ margin: 0 }}>Root cause analysis — 5 Why's</div><Badge kind="ai" icon="sparkles">Low / Medium method</Badge></div>
      {w.map((x, i) => <div key={i} style={{ display: 'flex', gap: 10, padding: '8px 0', borderBottom: '1px solid var(--border)' }}><span style={{ width: 26, height: 26, borderRadius: '50%', flex: 'none', background: 'var(--ai-bg)', color: 'var(--ai)', display: 'grid', placeItems: 'center', fontSize: 11, fontWeight: 800 }}>{i + 1}</span><div style={{ flex: 1 }}><div style={{ fontSize: 12.5, fontWeight: 600 }}>{x[0]}</div><div className="faint" style={{ fontSize: 12, marginTop: 2 }}>→ {x[1]}</div></div></div>)}
      <div style={{ marginTop: 12, background: 'var(--bad-bg)', border: '1px solid var(--bad-line)', borderRadius: 10, padding: '10px 12px' }}><div className="eyebrow" style={{ fontSize: 9, color: 'var(--bad)' }}>Root cause</div><div style={{ fontSize: 12.5, marginTop: 3 }}>No mandatory pre-task verification of the {rec.cat.toLowerCase()} control for a {rcaWhys ? '' : ''}low/medium-rated task.</div></div>
    </div>
  );
}
function RcaCauseTree({ rec }) {
  const branches = [
    { c: '#ef4444', cause: 'Immediate cause', leaves: ['Control bypassed under time pressure', 'Hazard not isolated'] },
    { c: '#f59e0b', cause: 'Underlying cause', leaves: ['Procedure not followed', 'Competency gap'] },
    { c: '#2563eb', cause: 'Root cause', leaves: ['No verification gate', 'Supervision not assigned'] },
  ];
  return (
    <div className="card card-pad" style={{ overflowX: 'auto' }}>
      <div className="row" style={{ alignItems: 'center', gap: 14, minWidth: 620 }}>
        <div style={{ background: 'var(--bad)', color: '#fff', borderRadius: 10, padding: '10px 14px', fontWeight: 700, fontSize: 12.5, flex: 'none', maxWidth: 150 }}>Top event<div style={{ fontWeight: 500, fontSize: 11, opacity: .9, marginTop: 2 }}>{rec.title}</div></div>
        <div style={{ width: 26, height: 2, background: 'var(--border-2)', flex: 'none' }} />
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, flex: 1 }}>{branches.map((b, i) => (
          <div key={i} className="row" style={{ gap: 10, alignItems: 'center' }}>
            <div style={{ background: b.c, color: '#fff', borderRadius: 8, padding: '6px 10px', fontSize: 11, fontWeight: 700, flex: 'none', width: 120 }}>{b.cause}</div>
            <div style={{ width: 18, height: 2, background: 'var(--border-2)', flex: 'none' }} />
            <div className="row" style={{ gap: 8, flexWrap: 'wrap' }}>{b.leaves.map((l) => <span key={l} className="tag" style={{ fontSize: 11 }}>{l}</span>)}</div>
          </div>
        ))}</div>
      </div>
    </div>
  );
}
function RcaFishbone({ rec }) {
  const cats = [['People', ['Competency gap', 'Fatigue']], ['Process', ['No permit gate', 'Procedure not followed']], ['Equipment', ['Tool defect', 'No inspection']], ['Environment', ['Heat / weather', 'Congested area']], ['Materials', ['Wrong spec', 'Damaged consumable']], ['Management', ['Supervision absent', 'Risk under-rated']]];
  const W = 720, H = 300, midY = H / 2;
  return (
    <div className="card card-pad" style={{ overflowX: 'auto' }}>
      <svg viewBox={`0 0 ${W} ${H}`} style={{ width: '100%', minWidth: 640 }}>
        <line x1="40" y1={midY} x2={W - 150} y2={midY} stroke="var(--text-3)" strokeWidth="2.5" />
        <polygon points={`${W - 150},${midY - 7} ${W - 150},${midY + 7} ${W - 138},${midY}`} fill="var(--text-3)" />
        <rect x={W - 136} y={midY - 26} width="132" height="52" rx="9" fill="var(--bad)" />
        <text x={W - 70} y={midY - 4} textAnchor="middle" fill="#fff" fontSize="11" fontWeight="700">Problem</text>
        <text x={W - 70} y={midY + 12} textAnchor="middle" fill="#fff" fontSize="9">{rec.title.slice(0, 18)}</text>
        {cats.map((cat, i) => {
          const top = i < 3; const col = i % 3; const bx = 110 + col * 180; const by = top ? midY - 110 : midY + 110;
          const jx = bx + 70, jy = midY; const c = ['#2563eb', '#7a5bff', '#0e7490', '#f59e0b', '#22c55e', '#ef4444'][i];
          return (
            <g key={i}>
              <line x1={bx} y1={by} x2={jx} y2={jy} stroke={c} strokeWidth="2" />
              <rect x={bx - 46} y={by - (top ? 16 : 0)} width="92" height="16" rx="4" fill={c} /><text x={bx} y={by - (top ? 4 : -12)} textAnchor="middle" fill="#fff" fontSize="9.5" fontWeight="700">{cat[0]}</text>
              {cat[1].map((leaf, li) => { const t = (li + 1) / 3; const lx = bx + (jx - bx) * t, ly = by + (jy - by) * t; return <text key={li} x={lx + 6} y={ly + (top ? -2 : 10)} fontSize="9" fill="var(--text-2)">{leaf}</text>; })}
            </g>
          );
        })}
      </svg>
    </div>
  );
}
function RiskDash({ tab: initTab }) {
  const [tab, setTab] = useState(initTab || 'register');
  useEffect(() => { setTab(initTab || 'register'); }, [initTab]);
  const x = DB.riskDash;
  const catOf = (a) => /lift|crane|rigging|hoist/i.test(a) ? 'Lifting' : /confined|n₂|n2|nitrogen|purge|vessel/i.test(a) ? 'Confined Space' : /hot work|weld|fire|flame/i.test(a) ? 'Fire' : /chemical|coshh|clean/i.test(a) ? 'Chemical' : /vehicle|journey|driv|road/i.test(a) ? 'Transportation' : /electric/i.test(a) ? 'Electrical' : /height|scaffold|fall/i.test(a) ? 'Work at Height' : 'General Safety';
  const reg = DB.risks.map((r, i) => { const C = r.severity, L = r.likelihood, R = C * L; const C2 = Math.max(1, C - 1), L2 = Math.max(1, L - 2), R2 = C2 * L2; return { id: String(r.id).replace(/^RR/, 'RISK'), title: r.area, cat: catOf(r.area), loc: r.project, ic: [C, L, R], rc: [C2, L2, R2], owner: DB.staff[i % DB.staff.length].id, status: i % 4 === 0 ? 'Open' : i % 4 === 1 ? 'Under Treatment' : i % 4 === 2 ? 'Monitoring' : 'Open', review: DB.fmt(DB.D(10 + i * 6)), control: r.control }; });
  const [selIdx, setSelIdx] = useState(0);
  const [rcaMethod, setRcaMethod] = useState('tree');
  const sr = reg[selIdx] || reg[0];
  const rbk = (s) => s >= 17 ? 'bad' : s >= 10 ? 'bad' : s >= 5 ? 'warn' : 'ok';
  const rlvl = (s) => s >= 17 ? 'Extreme' : s >= 10 ? 'High' : s >= 5 ? 'Medium' : 'Low';
  const regKpis = [['Total risks', reg.length, 'shield', 'info'], ['Extreme', reg.filter((r) => r.ic[2] >= 17).length, 'alert', 'bad'], ['High', reg.filter((r) => r.ic[2] >= 10 && r.ic[2] < 17).length, 'alert', 'bad'], ['Medium', reg.filter((r) => r.ic[2] >= 5 && r.ic[2] < 10).length, 'flag', 'warn'], ['Low', reg.filter((r) => r.ic[2] < 5).length, 'check', 'ok'], ['Under treatment', reg.filter((r) => r.status === 'Under Treatment').length, 'refresh', 'ai']];
  const BARRIERS = [
    { id: 'BAR-01', hazard: 'Loss of containment — hydrocarbon', barrier: 'Pressure relief & blowdown', type: 'Hardware', integrity: 96, status: 'Healthy', test: 'Function-tested 12 d ago' },
    { id: 'BAR-02', hazard: 'Dropped object — lifting', barrier: 'Tool tethering & exclusion zone', type: 'Procedural', integrity: 74, status: 'Degraded', test: '2 tethers overdue inspection' },
    { id: 'BAR-03', hazard: 'Confined-space asphyxiation', barrier: 'Gas detection & rescue standby', type: 'Hardware', integrity: 99, status: 'Healthy', test: 'Bump-tested today' },
    { id: 'BAR-04', hazard: 'Ignition — hot work', barrier: 'Fire watch & gas test (PTW)', type: 'Procedural', integrity: 88, status: 'Healthy', test: 'Per permit' },
    { id: 'BAR-05', hazard: 'Vehicle collision — journey', barrier: 'IVMS speed & fatigue control', type: 'Engineered', integrity: 62, status: 'Degraded', test: '2 units GPS fault' },
    { id: 'BAR-06', hazard: 'Toxic release — chemical clean', barrier: 'Bunding & scrubber', type: 'Hardware', integrity: 45, status: 'Failed', test: 'Scrubber offline — P-219' },
  ];
  return (
    <div className="page page-wide rise">
      <PageHead title="Risk Management" sub="Identify, assess, evaluate and control risks — ISO 31000 / ISO 45001"><DateFilter /><Btn variant="primary" icon="plus" onClick={() => openRiskForm()}>Add new risk</Btn></PageHead>
      <Tabs tabs={[['register', 'Risk Register'], ['dashboard', 'Dashboard'], ['assess', 'Risk Assessment'], ['matrix', 'Risk Matrix'], ['jsa', 'JSA / HAZID'], ['treatment', 'Treatment Plan'], ['barrier', 'BowTie / Barriers'], ['heat', 'Heat map / Monitoring'], ['env', 'Environmental']]} tab={tab} setTab={setTab} />
      {tab === 'register' && <React.Fragment>
        <div className="dk-kpis" style={{ gridTemplateColumns: 'repeat(6,1fr)' }}>{regKpis.map(([k, v, ic, tone], i) => { const t = DASH_TONE[tone]; return <div key={i} className="card" style={{ padding: '13px 14px', minWidth: 0 }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 22, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>; })}</div>
        <div style={{ margin: '14px 0' }}><AINote title="Dynamic risk — SIMOPS rising" clause="ISO 31000 / HAZID">AI continuously re-scores risks from live signals — {sr.id} ({sr.title}) is a top live risk. It recommends sequencing controls and flags overdue treatment actions; suggested controls library pre-loaded.</AINote></div>
        <div className="split">
          <div className="card"><div className="card-head"><Icon name="alert" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Risk register</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>{reg.length} risks · inherent → residual</span></div>
            <table className="tbl"><thead><tr><th>Risk ID</th><th>Title</th><th>Category</th><th>Location</th><th style={{ textAlign: 'center' }}>Inherent L·C·R</th><th style={{ textAlign: 'center' }}>Residual L·C·R</th><th>Owner</th><th>Status</th><th>Review</th><th></th></tr></thead>
              <tbody>{reg.map((r, i) => (
                <tr key={r.id + i} className="clickable" style={{ background: selIdx === i ? 'var(--ai-bg)' : undefined }} onClick={() => setSelIdx(i)}>
                  <td className="mono cell-strong" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{r.id}</td><td style={{ fontSize: 12 }}>{r.title}</td><td><span className="tag">{r.cat}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{r.loc}</td>
                  <td style={{ textAlign: 'center', fontSize: 11 }}>{r.ic[0]} · {r.ic[1]} · <Badge kind={rbk(r.ic[2])}>{r.ic[2]}</Badge></td>
                  <td style={{ textAlign: 'center', fontSize: 11 }}>{r.rc[0]} · {r.rc[1]} · <Badge kind={rbk(r.rc[2])}>{r.rc[2]}</Badge></td>
                  <td><Avatar id={r.owner} size="sm" /></td><td><Badge kind={r.status === 'Open' ? 'warn' : r.status === 'Under Treatment' ? 'info' : 'ok'} dot={r.status !== 'Monitoring'}>{r.status}</Badge></td><td className="faint" style={{ fontSize: 11 }}>{r.review}</td>
                  <td><RowActions onEdit={() => openRiskForm(DB.risks[i])} onDelete={() => dbRemove('risks', 'id', DB.risks[i].id)} /></td>
                </tr>
              ))}</tbody>
            </table>
          </div>
          <div className="card card-pad">
            <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Risk details</div><Badge kind={rbk(sr.ic[2])}>{rlvl(sr.ic[2])}</Badge></div>
            <div className="mono cell-strong" style={{ color: 'var(--primary-700)', fontSize: 12 }}>{sr.id}</div>
            <div style={{ fontSize: 13.5, fontWeight: 700, margin: '2px 0 8px' }}>{sr.title}</div>
            <div className="row" style={{ gap: 8, alignItems: 'stretch', marginBottom: 10 }}>
              <div style={{ flex: 1, textAlign: 'center', background: 'var(--bad-bg)', border: '1px solid var(--bad-line)', borderRadius: 10, padding: '8px 4px' }}><div className="eyebrow" style={{ fontSize: 8 }}>Inherent</div><div style={{ fontSize: 22, fontWeight: 800, color: 'var(--bad)' }}>{sr.ic[2]}</div><div className="faint" style={{ fontSize: 9.5 }}>L{sr.ic[0]} × C{sr.ic[1]}</div></div>
              <div style={{ alignSelf: 'center', color: 'var(--text-3)' }}><Icon name="arrowR" size={16} /></div>
              <div style={{ flex: 1, textAlign: 'center', background: 'var(--ok-bg)', border: '1px solid var(--ok-line)', borderRadius: 10, padding: '8px 4px' }}><div className="eyebrow" style={{ fontSize: 8 }}>Residual</div><div style={{ fontSize: 22, fontWeight: 800, color: 'var(--ok)' }}>{sr.rc[2]}</div><div className="faint" style={{ fontSize: 9.5 }}>L{sr.rc[0]} × C{sr.rc[1]}</div></div>
            </div>
            {[['Category', sr.cat], ['Location', sr.loc], ['Control', sr.control], ['Owner', DB.staffById(sr.owner).name], ['Status', sr.status], ['Next review', sr.review]].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5, gap: 8 }}><span className="faint">{k}</span><b style={{ textAlign: 'right' }}>{v}</b></div>)}
            <div className="eyebrow" style={{ margin: '10px 0 5px', fontSize: 8.5 }}>Status</div>
            <div className="row" style={{ gap: 0 }}>{['Identified', 'Assessed', 'Evaluated', 'Treatment', 'Closed'].map((s, i) => <React.Fragment key={s}><span style={{ flex: 'none', fontSize: 8.5, fontWeight: 700, color: i <= 3 ? 'var(--primary-700)' : 'var(--text-3)' }}>{s}</span>{i < 4 && <span style={{ flex: 1, height: 2, background: i < 3 ? 'var(--primary-500)' : 'var(--border)', margin: '0 4px', alignSelf: 'center' }} />}</React.Fragment>)}</div>
            <Btn variant="ghost" icon="ext" size="sm" style={{ marginTop: 12, width: '100%' }} onClick={() => setTab('assess')}>Open risk assessment</Btn>
          </div>
        </div>
      </React.Fragment>}
      {tab === 'assess' && (() => { const C = sr.ic[1], L = sr.ic[0]; const hira = [
        [sr.title, sr.cat, 'Personnel injury / loss', L, C, L * C, sr.control, 'Permit + supervision', sr.rc[0], sr.rc[1], sr.rc[2]],
        ['Secondary exposure during task', sr.cat, 'Exposure / contact', Math.max(1, L - 1), C, Math.max(1, L - 1) * C, 'PPE + barricading', 'Monitoring + standby', 1, Math.max(1, C - 1), Math.max(1, C - 1)],
        ['Equipment / tool failure', 'Equipment', 'Property damage', 2, 4, 8, 'Pre-use inspection', 'Planned maintenance', 1, 3, 3],
        ['Adverse weather / heat', 'General Safety', 'Heat stress', 3, 3, 9, 'Work-rest cycle', 'Hydration + shading', 2, 2, 4],
      ]; return (
        <React.Fragment>
          <div className="card card-pad" style={{ marginBottom: 14 }}>
            <div className="row" style={{ gap: 18, flexWrap: 'wrap' }}>
              {[['Assessment', `RA-${sr.id.split('-').pop()}`], ['Risk title', sr.title], ['Location', sr.loc], ['Category', sr.cat], ['Method', 'HIRA · ISO 31000:2018'], ['Owner', DB.staffById(sr.owner).name], ['Review due', sr.review], ['Status', 'Approved']].map(([k, v]) => <div key={k}><div className="eyebrow" style={{ fontSize: 8.5 }}>{k}</div><div style={{ fontSize: 12.5, fontWeight: 700, marginTop: 2 }}>{v}</div></div>)}
            </div>
          </div>
          <div style={{ marginBottom: 14 }}><AINote title="Sentinel — assessment assist" clause="ISO 31000 §6.4">AI proposes hazards & controls from {sr.cat} task history and live signals, computes residual risk and pre-loads the treatment plan. Average reduction on this assessment: {Math.round((1 - sr.rc[2] / sr.ic[2]) * 100)}%.</AINote></div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.3fr', gap: 14, marginBottom: 14, alignItems: 'start' }}>
            <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Current risk rating (before controls)</div><div style={{ textAlign: 'center' }}><DashGauge value={sr.ic[2]} max={25} color={sr.ic[2] >= 10 ? 'var(--bad)' : 'var(--warn)'} fmt={sr.ic[2]} /><Badge kind={rbk(sr.ic[2])}>{rlvl(sr.ic[2])}</Badge></div>
              <div className="row" style={{ justifyContent: 'space-around', marginTop: 10, fontSize: 11 }}><div style={{ textAlign: 'center' }}><div className="faint">Likelihood</div><b>{L} / 5</b></div><div style={{ textAlign: 'center' }}><div className="faint">Consequence</div><b>{C} / 5</b></div></div></div>
            <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Risk criteria (5×5)</div><RiskScoreMatrix /></div>
          </div>
          <div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Hazard identification & risk analysis (HIRA)</div></div>
            <div style={{ overflowX: 'auto' }}><table className="tbl"><thead><tr><th>Hazard</th><th>Type</th><th>Consequence</th><th>L</th><th>C</th><th>Score</th><th>Existing control</th><th>Additional control</th><th>L</th><th>C</th><th>Residual</th></tr></thead>
              <tbody>{hira.map((h, i) => <tr key={i}><td style={{ fontSize: 12 }}>{h[0]}</td><td><span className="tag">{h[1]}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{h[2]}</td><td className="mono">{h[3]}</td><td className="mono">{h[4]}</td><td><Badge kind={rbk(h[5])}>{h[5]}</Badge></td><td className="faint" style={{ fontSize: 11.5 }}>{h[6]}</td><td className="faint" style={{ fontSize: 11.5 }}>{h[7]}</td><td className="mono">{h[8]}</td><td className="mono">{h[9]}</td><td><Badge kind={rbk(h[10])}>{h[10]}</Badge></td></tr>)}</tbody>
            </table></div>
          </div>
          <div style={{ marginTop: 14 }}>
            <div className="row" style={{ justifyContent: 'space-between', marginBottom: 10, flexWrap: 'wrap', gap: 8, alignItems: 'center' }}>
              <div className="eyebrow" style={{ margin: 0 }}>Root cause analysis · {rlvl(sr.ic[2])} ({sr.ic[2]})</div>
              {sr.ic[2] >= 10 && <div className="row" style={{ gap: 6 }}>{[['tree', 'Cause Tree'], ['fish', 'Fishbone']].map(([k, l]) => <button key={k} type="button" onClick={() => setRcaMethod(k)} style={{ fontFamily: 'inherit', fontSize: 12, fontWeight: 600, padding: '6px 12px', borderRadius: 8, cursor: 'pointer', border: '1px solid ' + (rcaMethod === k ? 'var(--primary-600)' : 'var(--border-2)'), background: rcaMethod === k ? 'var(--primary-50)' : 'var(--surface)', color: rcaMethod === k ? 'var(--primary-700)' : 'var(--text-2)' }}>{l}</button>)}</div>}
            </div>
            {sr.ic[2] < 10 ? <RcaFiveWhy rec={sr} /> : (rcaMethod === 'fish' ? <RcaFishbone rec={sr} /> : <RcaCauseTree rec={sr} />)}
            <div style={{ marginTop: 12 }}><AINote title="Sentinel — RCA method" clause="ISO 31000 §6.4">{sr.ic[2] < 10 ? 'This ' + rlvl(sr.ic[2]) + '-rated risk uses 5-Why analysis. If the rating rises above Medium, AI-COS escalates it to a Cause Tree or Fishbone automatically.' : 'AI-COS requires a Cause Tree or Fishbone for ' + rlvl(sr.ic[2]) + '-rated risks (above Medium) — 5-Why is reserved for low & medium risks.'}</AINote></div>
          </div>
        </React.Fragment>
      ); })()}
      {tab === 'dashboard' && (<React.Fragment>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6,1fr)', gap: 12, marginBottom: 14 }}>{x.kpis.map(([k, v, ic, tone]) => { const t = DASH_TONE[tone]; return (<div key={k} className="card" style={{ padding: '13px 14px' }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 22, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8, marginTop: 2 }}>{k}</div></div></div></div>); })}</div>
        <div style={{ marginBottom: 14 }}><AINote title="Sentinel — dynamic risk intelligence" clause="ISO 31000">AI continuously re-scores risks from live signals — RISK-26-128 (dropped object) &amp; RISK-26-122 (confined space) are the top residual risks. It flags 14 overdue treatment actions and predicts SIMOPS risk rising on P-204 next week; suggested controls pre-loaded.</AINote></div>
        <div style={{ display: 'grid', gridTemplateColumns: '2.1fr 1fr', gap: 14, marginBottom: 14, alignItems: 'start' }}>
          <div className="card">
            <div className="card-head"><Icon name="shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Risk register</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>Showing 1–8 of 128</span></div>
            <table className="tbl"><thead><tr><th>Risk ID</th><th>Title</th><th>Category</th><th>Location</th><th style={{ textAlign: 'center' }}>Inherent C/L/R</th><th style={{ textAlign: 'center' }}>Residual C/L/R</th><th>Owner</th><th>Status</th><th>Review</th></tr></thead>
              <tbody>{x.register.map((r) => { const ib = r.ic[2] >= 15 ? 'bad' : r.ic[2] >= 10 ? 'warn' : 'ok'; const rb = r.rc[2] >= 15 ? 'bad' : r.rc[2] >= 10 ? 'warn' : 'ok'; return (
                <tr key={r.id} className="clickable" onClick={() => window.toast(`${r.id} risk assessment opened`, 'info')}>
                  <td className="mono cell-strong" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{r.id}</td><td style={{ fontSize: 12 }}>{r.title}</td><td><span className="tag">{r.cat}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{r.loc}</td>
                  <td style={{ textAlign: 'center', fontSize: 11 }}>{r.ic[0]} · {r.ic[1]} · <Badge kind={ib}>{r.ic[2]}</Badge></td>
                  <td style={{ textAlign: 'center', fontSize: 11 }}>{r.rc[0]} · {r.rc[1]} · <Badge kind={rb}>{r.rc[2]}</Badge></td>
                  <td><Avatar id={r.owner} size="sm" /></td><td><Badge kind={r.status === 'Open' ? 'warn' : 'info'} dot>{r.status}</Badge></td><td className="faint" style={{ fontSize: 11 }}>{r.review}</td>
                </tr>
              ); })}</tbody>
            </table>
            <div style={{ padding: '0 14px 14px' }}><Pagination page={1} perPage={8} total={128} onPage={() => { }} /></div>
          </div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Risk matrix (5×5)</div><RiskScoreMatrix />
            <div className="row" style={{ gap: 12, flexWrap: 'wrap', marginTop: 10 }}>{[['1–4 Low', '#22c55e'], ['5–9 Medium', '#f59e0b'], ['10–16 High', '#f97316'], ['17–25 Extreme', '#ef4444']].map(([l, c]) => <span key={l} className="row" style={{ gap: 5, fontSize: 10, color: 'var(--text-2)' }}><span style={{ width: 9, height: 9, borderRadius: '50%', background: c }} />{l}</span>)}</div>
          </div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 14, marginBottom: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Risk distribution</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={x.distribution} size={104} /><DashLegend data={x.distribution} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Risks by category</div><DashHBars data={x.byCategory} /></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Top high risks</div>{x.topHigh.map(([t, loc, s], i) => <div key={i} className="row" style={{ gap: 8, padding: '6px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5 }}><b style={{ color: 'var(--text-3)' }}>{i + 1}</b><div style={{ flex: 1 }}><div style={{ fontWeight: 600 }}>{t}</div><div className="faint" style={{ fontSize: 10 }}>{loc}</div></div><Badge kind="bad">{s}</Badge></div>)}</div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Risk treatment status</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={x.treatment} size={104} /><DashLegend data={x.treatment} /></div></div>
        </div>
        <div className="split">
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Action summary</div><div style={{ display: 'grid', gridTemplateColumns: 'repeat(6,1fr)', gap: 12 }}>{[['Total Actions', x.actions.total, 'receipt', 'info'], ['Open', x.actions.open, 'flag', 'warn'], ['In Progress', x.actions.inProgress, 'refresh', 'warn'], ['Pending', x.actions.pending, 'eye', 'info'], ['Closed', x.actions.closed, 'check', 'ok'], ['Overdue', x.actions.overdue, 'clock', 'bad']].map(([k, v, ic, tone]) => { const t = DASH_TONE[tone]; return <div key={k} style={{ textAlign: 'center' }}><Icon name={ic} size={18} style={{ color: t[1] }} /><div style={{ fontSize: 20, fontWeight: 800, marginTop: 2 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8 }}>{k}</div></div>; })}</div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Next review</div><div className="row" style={{ gap: 10, alignItems: 'center' }}><span className="kpi-ico" style={{ width: 40, height: 40, background: 'var(--info-bg)', color: 'var(--primary-600)' }}><Icon name="calendar" size={20} /></span><div><div style={{ fontSize: 16, fontWeight: 800 }}>{x.nextReview}</div><div className="faint" style={{ fontSize: 11 }}>{x.nextLoc}</div></div></div></div>
        </div>
      </React.Fragment>)}
      {tab === 'matrix' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr', gap: 14, alignItems: 'start' }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 12 }}>Corporate risk matrix (5×5) · v2.0</div><RiskScoreMatrix labels /></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Risk level criteria</div>
            <table className="tbl"><thead><tr><th>Level</th><th>Score</th><th>Action</th></tr></thead><tbody>{[['Extreme', '17–25', '#ef4444', 'Stop activity. Act now.'], ['High', '10–16', '#f97316', 'Prioritize & mitigate.'], ['Medium', '4–9', '#f59e0b', 'Plan & monitor.'], ['Low', '1–3', '#22c55e', 'Monitor regularly.']].map(([l, s, c, a]) => <tr key={l}><td><span className="row" style={{ gap: 6 }}><span style={{ width: 10, height: 10, borderRadius: '50%', background: c }} /><b>{l}</b></span></td><td className="mono">{s}</td><td className="faint" style={{ fontSize: 11.5 }}>{a}</td></tr>)}</tbody></table>
            <div className="eyebrow" style={{ margin: '14px 0 6px' }}>Likelihood scale</div>{[['5 Almost Certain', '> 1 / 3 months'], ['4 Likely', '1 in 3–12 months'], ['3 Possible', '1 in 1–3 years'], ['2 Unlikely', '1 in 3–10 years'], ['1 Rare', '< 1 in 10 years']].map(([l, f]) => <div key={l} className="row" style={{ justifyContent: 'space-between', padding: '3px 0', fontSize: 11 }}><b>{l}</b><span className="faint">{f}</span></div>)}
          </div>
        </div>
      )}
      {tab === 'heat' && <React.Fragment>
        <div style={{ marginBottom: 14 }}><AINote title="Sentinel — risk heat-map" clause="ISO 31000">AI plots all 128 risks by residual likelihood × consequence — the hot cell (Likely × Major) holds the dropped-object & equipment-failure risks. Concentrate treatment there for the biggest reduction.</AINote></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Risk heat map · residual risk count by cell</div><DashRiskGrid matrix={DB.dash.riskMatrix} /></div>
      </React.Fragment>}
      {tab === 'treatment' && <React.Fragment>
        <div style={{ marginBottom: 14 }}><AINote title="Sentinel — treatment effectiveness" clause="ISO 31000 §6.5">AI tracks control effectiveness — residual risk dropped 62% on average after treatment. 14 actions overdue; AI recommends escalating the 3 on extreme-rated risks first.</AINote></div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 2fr', gap: 14, alignItems: 'start' }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Treatment status</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={x.treatment} size={108} /><DashLegend data={x.treatment} /></div></div>
          <div className="card"><div className="card-head"><Icon name="check-shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Risk treatment plan</div></div><table className="tbl"><thead><tr><th>Risk ID</th><th>Title</th><th>Residual</th><th>Owner</th><th>Status</th><th>Review</th></tr></thead><tbody>{x.register.map((r) => <tr key={r.id}><td className="mono cell-strong" style={{ fontSize: 11 }}>{r.id}</td><td style={{ fontSize: 12 }}>{r.title}</td><td><Badge kind={r.rc[2] >= 10 ? 'warn' : 'ok'}>{r.rc[2]}</Badge></td><td><Avatar id={r.owner} size="sm" /></td><td><Badge kind={r.status === 'Open' ? 'warn' : 'info'} dot>{r.status}</Badge></td><td className="faint" style={{ fontSize: 11 }}>{r.review}</td></tr>)}</tbody></table></div>
        </div>
      </React.Fragment>}
      {tab === 'jsa' && <React.Fragment><div style={{ marginBottom: 14 }}><AINote title="JSA control gap detected" clause="HAZID">AI cross-checks JSAs against incident learnings — JSA-198-14 (bolt tensioning) is in review and currently omits the dropped-object control linked to the recent at-height near-miss. Suggested control pre-loaded.</AINote></div>
        <div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Job Safety / Hazard Analysis (JSA / JHA)</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Task</th><th>Project</th><th>Steps</th><th>Key hazards</th><th>Residual</th><th>Status</th></tr></thead>
            <tbody>{DB.jsa.map((j) => <tr key={j.id} className="clickable" onClick={() => window.toast(`${j.id} — ${j.task}`, 'info')}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{j.id}</td><td style={{ fontSize: 12.5 }}>{j.task}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{j.project}</td><td>{j.steps}</td><td className="faint" style={{ fontSize: 12 }}>{j.hazards}</td><td><Badge kind={j.residual === 'Medium' ? 'warn' : 'ok'}>{j.residual}</Badge></td><td><Badge kind={j.status === 'Approved' ? 'ok' : 'warn'} dot={j.status !== 'Approved'}>{j.status}</Badge></td></tr>)}</tbody>
          </table>
        </div></React.Fragment>}
      {tab === 'risk' && <div style={{ marginBottom: 14 }}><AINote title="Dynamic risk — SIMOPS rising" clause="HAZID">AI scores RR-204-07 (hydrotest + hot work, 16) as the top live risk and recommends sequencing controls; suggested controls library pre-loaded.</AINote></div>}
      {tab === 'env' && <div style={{ marginBottom: 14 }}><AINote title="Significant aspect needs action" clause="ISO 14001 §6.1.2">Chemical-cleaning effluent (High significance) on P-219 is in 'Action' — AI recommends bunding verification and a licensed-disposal manifest before work starts.</AINote></div>}
      {tab === 'risk' && (
        <div className="card"><table className="tbl">
          <thead><tr><th>Ref</th><th>Area / task</th><th>Project</th><th>L×S</th><th>Control</th><th>Status</th></tr></thead>
          <tbody>{DB.risks.map((r) => { const ls = r.likelihood * r.severity; return (
            <tr key={r.id} className="clickable" onClick={() => window.toast(`${r.id} risk assessment opened`, 'info')}>
              <td className="mono cell-strong" style={{ fontSize: 11.5 }}>{r.id}</td><td style={{ fontSize: 12.5 }}>{r.area}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{r.project}</td>
              <td><Badge kind={ls >= 15 ? 'bad' : ls >= 9 ? 'warn' : 'ok'}>{r.likelihood}×{r.severity}={ls}</Badge></td>
              <td className="faint" style={{ fontSize: 12 }}>{r.control}</td><td><Badge kind={r.status === 'Open' ? 'warn' : 'ok'} dot={r.status === 'Open'}>{r.status}</Badge></td>
            </tr>
          ); })}</tbody>
        </table></div>
      )}
      {tab === 'barrier' && <React.Fragment>
        <div style={{ marginBottom: 14 }}><AINote title="Barrier health — degraded barrier on a live hazard" clause="DNV barrier management">AI links barrier status to live risk (bowtie). <b>BAR-06</b> (scrubber, toxic release) is <b>Failed</b> while chemical-cleaning is scheduled on P-219 — AI blocks the activity until the barrier is restored or an alternative control is verified. BAR-02 & BAR-05 are degraded and trending down.</AINote></div>
        <div className="card"><div className="card-head"><Icon name="shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Safety-barrier register (bowtie)</div><span className="spacer" /><Badge kind="ai" icon="sparkles">live integrity</Badge></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Major hazard</th><th>Barrier</th><th>Type</th><th>Integrity</th><th>Verification</th><th>Status</th></tr></thead>
            <tbody>{BARRIERS.map((b) => <tr key={b.id} className="clickable" onClick={() => window.toast(`${b.id} — ${b.barrier}`, 'info')}>
              <td className="mono cell-strong" style={{ fontSize: 11.5 }}>{b.id}</td><td style={{ fontSize: 12.5 }}>{b.hazard}</td><td className="faint" style={{ fontSize: 12 }}>{b.barrier}</td><td><span className="tag">{b.type}</span></td>
              <td style={{ minWidth: 120 }}><div className="row" style={{ gap: 8 }}><div style={{ flex: 1 }}><Bar pct={b.integrity} color={b.integrity >= 85 ? 'var(--ok)' : b.integrity >= 60 ? 'var(--warn)' : 'var(--bad)'} /></div><span className="mono faint" style={{ fontSize: 11 }}>{b.integrity}%</span></div></td>
              <td className="faint" style={{ fontSize: 11.5 }}>{b.test}</td><td><Badge kind={b.status === 'Healthy' ? 'ok' : b.status === 'Degraded' ? 'warn' : 'bad'} dot={b.status !== 'Healthy'}>{b.status}</Badge></td>
            </tr>)}</tbody>
          </table>
        </div>
      </React.Fragment>}
      {tab === 'env' && (
        <div className="card"><div className="card-head"><Icon name="alert" size={16} style={{ color: 'var(--ok)' }} /><div className="h-sec">Environmental aspects & impacts register</div><span className="faint" style={{ fontSize: 11, marginLeft: 8 }}>ISO 14001 §6.1.2</span></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Aspect</th><th>Impact</th><th>Significance</th><th>Control</th><th>Status</th></tr></thead>
            <tbody>{DB.envAspects.map((e) => <tr key={e.id} className="clickable" onClick={() => window.toast(`${e.id} — ${e.aspect}`, 'info')}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{e.id}</td><td style={{ fontSize: 12.5 }}>{e.aspect}</td><td className="faint" style={{ fontSize: 12 }}>{e.impact}</td><td><Badge kind={e.significance === 'High' ? 'bad' : e.significance === 'Medium' ? 'warn' : 'neutral'}>{e.significance}</Badge></td><td className="faint" style={{ fontSize: 12 }}>{e.control}</td><td><Badge kind={e.status === 'Controlled' ? 'ok' : 'warn'} dot={e.status !== 'Controlled'}>{e.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}
function MonthGrid({ title, events }) {
  // events: { day: [{label, kind}] }  kind -> badge color class
  const lead = 3; const days = 31;
  const kc = { internal: '#22c55e', external: '#2563eb', inprog: '#f59e0b', overdue: '#ef4444' };
  return (
    <div className="card">
      <div className="card-head"><Icon name="calendar" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">{title}</div></div>
      <div className="card-body">
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 6 }}>
          {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((d) => <div key={d} className="eyebrow" style={{ fontSize: 9, textAlign: 'center', padding: '2px 0' }}>{d}</div>)}
          {Array.from({ length: lead }).map((_, i) => <div key={'b' + i} />)}
          {Array.from({ length: days }, (_, i) => i + 1).map((d) => {
            const ev = events[d] || [];
            return <div key={d} style={{ minHeight: 64, border: '1px solid var(--border)', borderRadius: 8, padding: 5, background: d === 15 ? 'var(--ai-bg)' : 'var(--surface)' }}>
              <div className="faint" style={{ fontSize: 10.5, fontWeight: 700 }}>{d}</div>
              {ev.map((e, i) => <div key={i} style={{ fontSize: 8.5, marginTop: 3, borderRadius: 4, padding: '2px 4px', color: '#fff', background: kc[e.kind] || '#64748b', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{e.label}</div>)}
            </div>;
          })}
        </div>
        <div className="row" style={{ gap: 14, marginTop: 12, fontSize: 11 }}>{[['Internal', kc.internal], ['External', kc.external], ['In progress', kc.inprog], ['Overdue', kc.overdue]].map(([l, c]) => <span key={l} className="row" style={{ gap: 5 }}><span style={{ width: 9, height: 9, borderRadius: 2, background: c }} />{l}</span>)}</div>
      </div>
    </div>
  );
}
function AuditCalendar() {
  const events = { 1: [{ label: 'QMS Process Audit', kind: 'internal' }], 2: [{ label: 'PTW Audit', kind: 'internal' }], 6: [{ label: 'ISO 14001 Surveillance', kind: 'external' }], 9: [{ label: 'API 653 Tank', kind: 'external' }], 15: [{ label: 'MOC Process Audit', kind: 'inprog' }], 16: [{ label: 'QMS Process', kind: 'internal' }], 20: [{ label: 'API 620 Inspection', kind: 'external' }], 21: [{ label: 'Work Permit Audit', kind: 'internal' }], 23: [{ label: 'Environmental Audit', kind: 'internal' }], 27: [{ label: 'HSEMS Overdue', kind: 'overdue' }], 29: [{ label: 'Supplier Audit', kind: 'external' }] };
  const upcoming = [['16', 'QMS Process Audit', 'Internal', 'Q-001'], ['20', 'API 620 Inspection', 'External', 'Q-007'], ['21', 'Work Permit Audit', 'Internal', 'Q-002'], ['23', 'Environmental Audit', 'Internal', 'Q-006'], ['29', 'Supplier Audit', 'External', 'Q-001']];
  return (
    <div className="split">
      <MonthGrid title="Audit calendar — current month" events={events} />
      <div className="card card-pad">
        <div className="eyebrow" style={{ marginBottom: 8 }}>Upcoming audits (next 30 days)</div>
        {upcoming.map((u, i) => <div key={i} className="row" style={{ gap: 10, padding: '8px 0', borderBottom: '1px solid var(--border)' }}><span style={{ width: 34, height: 34, borderRadius: 8, background: 'var(--info-bg)', color: 'var(--primary-700)', display: 'grid', placeItems: 'center', fontWeight: 800, fontSize: 13, flex: 'none' }}>{u[0]}</span><div style={{ flex: 1, minWidth: 0 }}><div style={{ fontSize: 12, fontWeight: 650 }}>{u[1]}</div><div className="faint" style={{ fontSize: 10.5 }}>{u[2]}</div></div><Avatar id={u[3]} size="sm" /></div>)}
      </div>
    </div>
  );
}
function AuditChecklist() {
  const stds = [['API Q2 — Quality Management', 39, 66.7], ['ISO 45001:2018', 53, 62.3], ['ISO 9001:2015', 45, 68.9], ['ISO 14001:2015', 45, 63.3]];
  const [sel, setSel] = useState(0);
  const clauses = [['1.0', 'Leadership & commitment'], ['2.0', 'Quality system'], ['3.0', 'Document control'], ['4.0', 'Personnel & competency'], ['5.0', 'Design & development'], ['6.0', 'Purchasing & supplier'], ['7.0', 'Inspection & testing'], ['8.0', 'Control of nonconforming'], ['9.0', 'Corrective action'], ['10.0', 'Continual improvement']];
  const byDept = [{ l: 'Operations', v: 72, c: '#22c55e' }, { l: 'Maintenance', v: 65, c: '#f59e0b' }, { l: 'HSE', v: 61, c: '#f59e0b' }, { l: 'Quality', v: 68, c: '#22c55e' }, { l: 'Engineering', v: 63, c: '#f59e0b' }];
  const reports = [['INT-AUD-2024-045', 'HSEMS Internal Audit', 'ISO 45001', 65.4, 'Completed'], ['EXT-AUD-2024-009', 'ISO 14001 Surveillance', 'ISO 14001', 71.2, 'Closed'], ['INT-AUD-2024-041', 'QMS Process Audit', 'ISO 9001', 68.9, 'Completed']];
  return (
    <React.Fragment>
      <div className="dk-kpis" style={{ gridTemplateColumns: 'repeat(6,1fr)' }}>{[['Total clauses', 182, 'clipboard', 'info'], ['Answered', 156, 'check', 'ai'], ['Compliant', 102, 'check', 'ok'], ['Non-compliant', 38, 'x', 'bad'], ['N/A', 16, 'alert', 'neutral'], ['Compliance', '65.4%', 'trend', 'warn']].map(([k, v, ic, tone], i) => { const t = DASH_TONE[tone] || DASH_TONE.info; return <div key={i} className="card" style={{ padding: '13px 14px', minWidth: 0 }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 22, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>; })}</div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.6fr', gap: 14, marginTop: 16, alignItems: 'start' }}>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Checklist library (by standard)</div>{stds.map((s, i) => <div key={i} className="row clickable" style={{ gap: 8, padding: '9px 8px', borderRadius: 8, background: sel === i ? 'var(--ai-bg)' : 'transparent', alignItems: 'center' }} onClick={() => setSel(i)}><div style={{ flex: 1 }}><div style={{ fontSize: 12, fontWeight: 650 }}>{s[0]}</div><div className="faint" style={{ fontSize: 10.5 }}>{s[1]} clauses</div></div><div style={{ width: 50 }}><Bar pct={s[2]} color={scoreColor(s[2])} /></div><span className="mono faint" style={{ fontSize: 10.5 }}>{s[2]}%</span></div>)}
          <div className="eyebrow" style={{ margin: '14px 0 8px' }}>Compliance by department</div><DashHBars data={byDept} />
        </div>
        <div className="card"><div className="card-head"><Icon name="check-shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">{stds[sel][0]} — checklist</div></div>
          <table className="tbl"><thead><tr><th>Clause</th><th>Requirement</th><th>Response type</th></tr></thead>
            <tbody>{clauses.map((c, i) => <tr key={i}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{c[0]}</td><td style={{ fontSize: 12.5 }}>{c[1]}</td><td><span className="tag">Yes / No / N/A</span></td></tr>)}</tbody>
          </table>
        </div>
      </div>
      <div className="card" style={{ marginTop: 16 }}><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Audit reports</div></div>
        <table className="tbl"><thead><tr><th>Audit code</th><th>Title</th><th>Standard</th><th>Compliance</th><th>Status</th></tr></thead>
          <tbody>{reports.map((r, i) => <tr key={i} className="clickable" onClick={() => window.toast('Report opened', 'info')}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{r[0]}</td><td style={{ fontSize: 12.5 }}>{r[1]}</td><td><span className="tag">{r[2]}</span></td><td style={{ width: 120 }}><div className="row" style={{ gap: 6 }}><div style={{ width: 60 }}><Bar pct={r[3]} color={scoreColor(r[3])} /></div><span className="mono faint" style={{ fontSize: 10.5 }}>{r[3]}%</span></div></td><td><Badge kind="ok">{r[4]}</Badge></td></tr>)}</tbody>
        </table>
      </div>
    </React.Fragment>
  );
}
function AuditsModule() {
  const [tab, setTab] = useState('register');
  const a = DB.audits; const cnt = (s) => a.filter((x) => x.status === s).length;
  const totalFindings = a.reduce((s, x) => s + (x.findings || 0), 0);
  const majors = a.reduce((s, x) => s + (x.major || 0), 0);
  const kpis = [['Audits (YTD)', a.length, 'clipboard', 'info'], ['Planned', cnt('Planned'), 'calendar', 'ai'], ['In progress', cnt('Open') + cnt('In Progress'), 'refresh', 'warn'], ['Total findings', totalFindings, 'alert', 'warn'], ['Major findings', majors, 'flag', 'bad'], ['Closed', cnt('Closed'), 'check', 'ok']];
  const byType = [{ l: 'Internal', v: a.filter((x) => x.type !== 'External').length, c: '#2563eb' }, { l: 'External / client', v: a.filter((x) => x.type === 'External').length, c: '#7a5bff' }];
  const findingCat = [{ l: 'Documentation', v: 9, c: '#f59e0b' }, { l: 'Lifting controls', v: 6, c: '#ef4444' }, { l: 'Competency', v: 5, c: '#f97316' }, { l: 'Environmental', v: 4, c: '#22c55e' }, { l: 'PTW / LOTO', v: 3, c: '#2563eb' }];
  const trend = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#2563eb', d: [4, 6, 5, 7, 6, 8] }, { c: '#ef4444', d: [2, 1, 2, 1, 1, 0] }] };
  return (
    <div className="page page-wide rise">
      <PageHead title="Audit Management" sub="Internal & external audits · findings · follow-up"><DateFilter /><DocActions label="audit register" /><Btn variant="primary" icon="plus" onClick={() => openAuditForm()}>Schedule audit</Btn></PageHead>
      <Tabs tabs={[['register', 'Audit register'], ['dashboard', 'Dashboard'], ['calendar', 'Calendar & schedule'], ['checklist', 'Checklists & reports']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="Predicted findings — client audit in 15 days" clause="ISO 19011">AI predicts the highest-risk areas as lifting-controls CAPA evidence and the environmental permit obligation. Pre-closing both clears the most likely findings.</AINote></div>
      {tab === 'dashboard' && <ModuleDash kpis={kpis} panels={[
        { title: 'Audits by type', node: <DashSplit data={byType} />, w: '1fr' },
        { title: 'Findings by category', node: <DashHBars data={findingCat} />, w: '1.4fr' },
        { title: 'Audits vs major findings (6 mo)', node: <DashLine trend={trend} />, w: '1.3fr' },
      ]} />}
      {tab === 'calendar' && <AuditCalendar />}
      {tab === 'checklist' && <AuditChecklist />}
      {tab === 'register' && (
        <div className="card"><table className="tbl">
          <thead><tr>{['Ref', 'Scope', 'Type', 'Date', 'Findings', 'Status', ''].map((h, hi) => <th key={hi}>{h}</th>)}</tr></thead>
          <tbody>{a.map((x) => <tr key={x.id} className="clickable" onClick={() => window.toast('Audit opened', 'info')}><td><span className="mono cell-strong">{x.id}</span></td><td style={{ fontSize: 12.5 }}>{x.scope}</td><td><Badge kind={x.type === 'External' ? 'ai' : 'neutral'}>{x.type}</Badge></td><td style={{ fontSize: 12.5 }}>{DB.fmt(x.date)}</td><td style={{ fontSize: 12.5 }}>{x.findings + (x.major ? ` (${x.major} maj)` : '')}</td><td><Badge kind={x.status === 'Closed' ? 'ok' : x.status === 'Planned' ? 'info' : 'warn'} dot>{x.status}</Badge></td><td><RowActions onEdit={() => openAuditForm(x)} onDelete={() => dbRemove('audits', 'id', x.id)} /></td></tr>)}</tbody>
        </table></div>
      )}
    </div>
  );
}
function CapaModule() {
  const [tab, setTab] = useState('register');
  const c = DB.capa; const cnt = (s) => c.filter((x) => x.status === s).length;
  const overdue = c.filter((x) => x.due < DB.TODAY && x.status !== 'Closed').length;
  const kpis = [['Total CAPAs', c.length, 'refresh', 'info'], ['Open', cnt('Open') + cnt('In Progress'), 'flag', 'warn'], ['Verification', cnt('Verification'), 'eye', 'ai'], ['Overdue', overdue, 'clock', 'bad'], ['Closed', cnt('Closed'), 'check', 'ok'], ['Avg close (days)', 19, 'history', 'info']];
  const bySource = [{ l: 'Audit', v: c.filter((x) => x.source === 'Audit').length || 4, c: '#2563eb' }, { l: 'Incident', v: c.filter((x) => x.source === 'Incident').length || 5, c: '#ef4444' }, { l: 'NCR', v: c.filter((x) => x.source === 'NCR').length || 3, c: '#f59e0b' }, { l: 'Inspection', v: 2, c: '#22c55e' }];
  const aging = [{ l: '0–7 days', v: 5, c: '#22c55e' }, { l: '8–30 days', v: 6, c: '#eab308' }, { l: '31–60 days', v: 3, c: '#f97316' }, { l: '> 60 days', v: 2, c: '#ef4444' }];
  const trend = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#2563eb', d: [6, 8, 7, 9, 7, 8] }, { c: '#22c55e', d: [4, 5, 6, 7, 6, 8] }] };
  return (
    <div className="page page-wide rise">
      <PageHead title="CAPA" sub="Corrective & preventive actions — AI verifies effectiveness before closure"><DateFilter /><Btn icon="sparkles" variant="ai" size="sm" onClick={() => openCapaCheck(DB.capa.find((x) => x.status === 'Verification') || DB.capa[0])}>AI effectiveness check</Btn></PageHead>
      <Tabs tabs={[['register', 'CAPA register'], ['dashboard', 'Dashboard']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="1 CAPA overdue, 1 ready to close" clause="ISO 9001 §10.2">CAPA-26-040 (lifting controls) is overdue and audit-critical. CAPA-26-033 has evidence attached — AI assesses it effective and ready to verify & close. Click any CAPA to run the AI effectiveness check.</AINote></div>
      {tab === 'dashboard' && <ModuleDash kpis={kpis} panels={[
        { title: 'CAPAs by source', node: <DashSplit data={bySource} />, w: '1fr' },
        { title: 'Open CAPA ageing', node: <DashHBars data={aging} />, w: '1.2fr' },
        { title: 'Raised vs closed (6 mo)', node: <DashLine trend={trend} />, w: '1.3fr' },
      ]} />}
      {tab === 'register' && (
        <div className="card"><table className="tbl">
          <thead><tr>{['Ref', 'Title', 'Source', 'Severity', 'Owner', 'Due', 'Status'].map((h) => <th key={h}>{h}</th>)}</tr></thead>
          <tbody>{c.map((x) => <tr key={x.id} className="clickable" onClick={() => openCapaCheck(x)}><td><span className="mono cell-strong">{x.id}</span></td><td style={{ fontSize: 12.5 }}>{x.title}</td><td><span className="tag">{x.source}</span></td><td><Badge kind={sevKind(x.severity)}>{x.severity}</Badge></td><td style={{ fontSize: 12.5 }}>{DB.staffById(x.owner).name.split(' ')[0]}</td><td><span style={{ color: x.due < DB.TODAY && x.status !== 'Closed' ? 'var(--bad)' : 'var(--text)', fontWeight: 600, fontSize: 12.5 }}>{DB.rel(x.due)}</span></td><td><Badge kind={x.status === 'Overdue' ? 'bad' : x.status === 'Verification' ? 'info' : 'warn'} dot>{x.status}</Badge></td></tr>)}</tbody>
        </table></div>
      )}
    </div>
  );
}
function ExternalDocLibrary() {
  const docs = [
    ['ISO 9001:2015', 'Quality Management Systems', 'ISO', 'QMS', '2015', 'Current'],
    ['ISO 14001:2015', 'Environmental Management Systems', 'ISO', 'HSE', '2015', 'Current'],
    ['ISO 45001:2018', 'Occupational H&S Management', 'ISO', 'HSE', '2018', 'Current'],
    ['API 653', 'Tank Inspection, Repair, Alteration', 'API', 'Operations', '5th Ed', 'Update available'],
    ['API 620', 'Design of Large Welded Tanks', 'API', 'Operations', '12th Ed', 'Current'],
    ['ASME BPVC IX', 'Welding & Brazing Qualifications', 'ASME', 'Technical', '2023', 'Current'],
    ['NFPA 10', 'Portable Fire Extinguishers', 'NFPA', 'HSE', '2022', 'Current'],
    ['API 510', 'Pressure Vessel Inspection', 'API', 'Operations', '11th Ed', 'Superseded'],
  ];
  const byBody = [{ l: 'ISO', v: 780, c: '#2563eb' }, { l: 'API', v: 240, c: '#7a5bff' }, { l: 'ASME', v: 120, c: '#0e7490' }, { l: 'NFPA', v: 65, c: '#f59e0b' }, { l: 'Others', v: 40, c: '#94a3b8' }];
  const upd = [{ l: 'Up to date', v: 1132, c: '#22c55e' }, { l: 'Update available', v: 78, c: '#f59e0b' }, { l: 'Superseded', v: 35, c: '#ef4444' }];
  const stKind = (s) => s === 'Current' ? 'ok' : s === 'Superseded' ? 'bad' : 'warn';
  return (
    <React.Fragment>
      <div className="dk-kpis" style={{ gridTemplateColumns: 'repeat(6,1fr)' }}>{[['External docs', '1,245', 'documents', 'info'], ['Current', '1,132', 'check', 'ok'], ['Updates available', 78, 'refresh', 'warn'], ['Superseded', 35, 'alert', 'bad'], ['Standard bodies', 18, 'certificate', 'ai'], ['Last sync', 'Today', 'clock', 'info']].map(([k, v, ic, tone], i) => { const t = DASH_TONE[tone] || DASH_TONE.info; return <div key={i} className="card" style={{ padding: '13px 14px', minWidth: 0 }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 22, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>; })}</div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, margin: '16px 0' }}>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>By standard body</div><DashSplit data={byBody} /></div>
        <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Update status</div><DashSplit data={upd} /></div>
      </div>
      <div className="card"><div className="card-head"><Icon name="certificate" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">External standards register</div></div>
        <table className="tbl"><thead><tr><th>Standard / code</th><th>Title</th><th>Body</th><th>Category</th><th>Version</th><th>Status</th></tr></thead>
          <tbody>{docs.map((r, i) => <tr key={i} className="clickable" onClick={() => window.toast(r[0] + ' opened', 'info')}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{r[0]}</td><td style={{ fontSize: 12.5 }}>{r[1]}</td><td><Badge kind="ai">{r[2]}</Badge></td><td className="faint" style={{ fontSize: 12 }}>{r[3]}</td><td className="faint" style={{ fontSize: 12 }}>{r[4]}</td><td><Badge kind={stKind(r[5])} dot={r[5] !== 'Current'}>{r[5]}</Badge></td></tr>)}</tbody>
        </table>
      </div>
    </React.Fragment>
  );
}
function DocsModule() {
  const [tab, setTab] = useState('register');
  const d = DB.docs; const cnt = (s) => d.filter((x) => x.status === s).length;
  const avgAck = Math.round(d.reduce((s, x) => s + (x.ack || 0), 0) / d.length);
  const lowAck = d.filter((x) => (x.ack || 0) < 90).length;
  const kpis = [['Controlled docs', d.length, 'documents', 'info'], ['Published', cnt('Published'), 'check', 'ok'], ['In review', cnt('Review') + cnt('In Review'), 'eye', 'warn'], ['Avg acknowledgment', avgAck + '%', 'users', 'ai'], ['Below 90% ack', lowAck, 'alert', 'bad'], ['Due for review', 5, 'clock', 'warn']];
  const byType = [{ l: 'Procedures', v: 14, c: '#2563eb' }, { l: 'Work instructions', v: 9, c: '#7a5bff' }, { l: 'Forms', v: 11, c: '#22c55e' }, { l: 'Policies', v: 5, c: '#f59e0b' }];
  const ackBars = d.slice(0, 6).map((x) => ({ l: x.code, v: x.ack || 0, c: (x.ack || 0) > 90 ? '#22c55e' : '#f59e0b' }));
  return (
    <div className="page page-wide rise">
      <PageHead title="Document Control" sub="Controlled IMS documents · approval · revisions · acknowledgment"><DateFilter /><DocActions label="document register" /><Btn variant="primary" icon="plus" onClick={() => openDocForm()}>New document</Btn></PageHead>
      <Tabs tabs={[['register', 'IMS document register'], ['dashboard', 'Dashboard'], ['external', 'External standards library']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="Read-acknowledgment & review gaps" clause="ISO 9001 §7.5">The Nitrogen Services Procedure sits at 84% acknowledgment and the flange ITP is in review. AI recommends a targeted read-reminder before P-211 mobilization.</AINote></div>
      {tab === 'dashboard' && <ModuleDash kpis={kpis} panels={[
        { title: 'Documents by category', node: <DashSplit data={[{ l: 'HSEMS', v: 28, c: '#2563eb' }, { l: 'QMS', v: 21, c: '#7a5bff' }, { l: 'Operations', v: 22, c: '#0e7490' }, { l: 'Compliance', v: 12, c: '#f59e0b' }, { l: 'HR', v: 13, c: '#22c55e' }]} />, w: '1fr' },
        { title: 'Documents by level', node: <DashSplit data={[{ l: 'L1 Policies', v: 15, c: '#7a5bff' }, { l: 'L2 Standards', v: 12, c: '#2563eb' }, { l: 'L3 Procedures', v: 32, c: '#f59e0b' }, { l: 'L4 Work instr.', v: 41, c: '#22c55e' }]} />, w: '1fr' },
        { title: 'Read-acknowledgment by document', node: <DashHBars data={ackBars} />, w: '1.3fr' },
      ]} />}
      {tab === 'external' && <ExternalDocLibrary />}
      {tab === 'register' && (
        <div className="card"><table className="tbl">
          <thead><tr>{['Code', 'Title', 'Type', 'Ver', 'Ack', 'Status', ''].map((h, hi) => <th key={hi}>{h}</th>)}</tr></thead>
          <tbody>{d.map((x) => <tr key={x.code} className="clickable" onClick={() => window.toast('Document opened', 'info')}><td><span className="mono cell-strong">{x.code}</span></td><td style={{ fontSize: 12.5 }}>{x.title}</td><td style={{ fontSize: 12.5 }}>{x.type}</td><td><Badge kind="ink">{x.ver}</Badge></td><td><span className="row" style={{ gap: 6 }}><div style={{ width: 44 }}><Bar pct={x.ack} color={x.ack > 90 ? 'var(--ok)' : 'var(--warn)'} /></div><span className="faint" style={{ fontSize: 10.5 }}>{x.ack}%</span></span></td><td><Badge kind={x.status === 'Published' ? 'ok' : 'warn'} dot={x.status !== 'Published'}>{x.status}</Badge></td><td><RowActions onEdit={() => openDocForm(x)} onDelete={() => dbRemove('docs', 'code', x.code)} /></td></tr>)}</tbody>
        </table></div>
      )}
    </div>
  );
}
function ProjectsModule({ onOpen }) {
  const [tab, setTab] = useState('register');
  const p = DB.projects;
  const active = p.filter((x) => x.stage !== 'Closeout' && x.stage !== 'Closed').length;
  const highRisk = p.filter((x) => x.risk === 'High').length;
  const avgProg = Math.round(p.reduce((s, x) => s + (x.progress || 0), 0) / p.length);
  const avgHse = Math.round(p.reduce((s, x) => s + (x.hse || 0), 0) / p.filter((x) => x.hse).length);
  const kpis = [['Projects', p.length, 'workflow', 'info'], ['Active', active, 'refresh', 'ai'], ['High risk', highRisk, 'alert', 'bad'], ['Avg progress', avgProg + '%', 'chart', 'warn'], ['Avg HSE score', avgHse, 'shield', 'ok'], ['Mobilizing', p.filter((x) => x.stage === 'Mobilization').length, 'truck', 'warn']];
  const byStage = ['Tender', 'Mobilization', 'Execution', 'Closeout'].map((st, i) => ({ l: st, v: p.filter((x) => x.stage === st).length, c: ['#7a5bff', '#f59e0b', '#2563eb', '#22c55e'][i] })).filter((x) => x.v);
  const byRisk = [{ l: 'High', v: highRisk, c: '#ef4444' }, { l: 'Medium', v: p.filter((x) => x.risk === 'Medium').length, c: '#f59e0b' }, { l: 'Low', v: p.filter((x) => x.risk === 'Low').length, c: '#22c55e' }];
  return (
    <div className="page page-wide rise">
      <PageHead title="Project Execution" sub="Tender → mobilization → execution → closeout · HSE plan, ITP, KPIs"><DateFilter /><Btn variant="primary" icon="plus" onClick={() => openProjectForm()}>New project</Btn></PageHead>
      <Tabs tabs={[['register', 'Project register'], ['dashboard', 'Dashboard']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="Mobilization risk — P-211" clause="AIX">AI flags P-211 mobilization at risk: 7 certifications and 1 hydrotest pump certification lapse before deployment. Resolve to protect the schedule and HSE readiness.</AINote></div>
      {tab === 'dashboard' && <ModuleDash kpis={kpis} panels={[
        { title: 'Projects by stage', node: <DashSplit data={byStage} />, w: '1fr' },
        { title: 'Projects by risk', node: <DashSplit data={byRisk} />, w: '1fr' },
        { title: 'Progress by project', node: <DashHBars data={p.slice(0, 6).map((x) => ({ l: x.id, v: x.progress || 0, c: 'var(--primary-600)' }))} />, w: '1.3fr' },
      ]} />}
      {tab === 'register' && (
        <div className="card"><table className="tbl">
          <thead><tr>{['Ref', 'Project', 'Client', 'Region', 'Stage', 'HSE', 'Progress', 'Value', 'Risk'].map((h) => <th key={h}>{h}</th>)}</tr></thead>
          <tbody>{p.map((x) => <tr key={x.id} className="clickable" onClick={() => onOpen('project', x)}><td><span className="mono cell-strong">{x.id}</span></td><td style={{ fontSize: 12.5 }}>{x.name}</td><td style={{ fontSize: 12.5 }}>{x.client}</td><td style={{ fontSize: 12.5 }}>{x.region}</td><td><Badge kind="info">{x.stage}</Badge></td><td><b style={{ color: scoreColor(x.hse) }}>{x.hse || '—'}</b></td><td><div style={{ width: 70 }}><Bar pct={x.progress} color="var(--primary-600)" /></div></td><td style={{ fontSize: 12.5 }}>{x.value}</td><td><Badge kind={x.risk === 'High' ? 'bad' : x.risk === 'Medium' ? 'warn' : 'ok'}>{x.risk}</Badge></td><td><RowActions onView={() => onOpen('project', x)} onEdit={() => openProjectForm(x)} onDelete={() => dbRemove('projects', 'id', x.id)} /></td></tr>)}</tbody>
        </table></div>
      )}
    </div>
  );
}
function FleetModule() {
  const [tab, setTab] = useState('journey');
  const jr = DB.journeys, veh = DB.fleetVehicles, drv = DB.drivers;
  const jcnt = (s) => jr.filter((j) => j.status === s).length;
  const totalKm = jr.reduce((a, j) => a + j.km, 0);
  const jKpis = [['Total journeys', jr.length, 'truck', 'info'], ['Planned', jcnt('Planned'), 'calendar', 'ai'], ['In progress', jcnt('In Progress'), 'refresh', 'warn'], ['Completed', jcnt('Completed'), 'check', 'ok'], ['Overdue', jcnt('Overdue'), 'clock', 'bad'], ['Distance (km)', totalKm.toLocaleString(), 'pin', 'info']];
  const byStatus = ['In Progress', 'Completed', 'Planned', 'Overdue'].map((s, i) => ({ l: s, v: jcnt(s), c: ['#2563eb', '#22c55e', '#7a5bff', '#ef4444'][i] })).filter((x) => x.v);
  const byType = (() => { const m = {}; jr.forEach((j) => { m[j.type] = (m[j.type] || 0) + 1; }); const cols = ['#2563eb', '#f59e0b', '#0e7490', '#22c55e']; return Object.entries(m).map(([l, v], i) => ({ l, v, c: cols[i % cols.length] })); })();
  const jTrend = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [{ c: '#22c55e', d: [78, 82, 85, 84, 88, 92] }] };
  const [selV, setSelV] = useState(veh[0]);
  const jStK = (s) => s === 'Completed' ? 'ok' : s === 'In Progress' ? 'info' : s === 'Overdue' ? 'bad' : 'neutral';
  const drStK = (s) => s === 'Both Qualified' ? 'ok' : s === 'Expired' ? 'bad' : 'warn';
  const inspSummary = [{ l: 'Valid', v: veh.filter((v) => v.insp === 'Valid').length, c: '#22c55e' }, { l: 'Due soon', v: veh.filter((v) => v.insp === 'Due').length, c: '#f59e0b' }];
  const docSummary = [{ l: 'Valid', v: veh.filter((v) => v.docs === 'Valid').length, c: '#22c55e' }, { l: 'Expired', v: veh.filter((v) => v.docs === 'Expired').length, c: '#ef4444' }];
  return (
    <div className="page page-wide rise">
      <PageHead title="Fleet & Journey Management" sub="Journey planning · driver competency · vehicle register · live tracking · fuel — AI fatigue/risk">
        <Btn icon="truck" variant="ai" size="sm" onClick={() => openJourneyForm()}>Plan journey (AI)</Btn>
      </PageHead>
      <Tabs tabs={[['journey', 'Journey dashboard'], ['live', 'Live journey'], ['plan', 'Journey plan'], ['register', 'Fleet register'], ['drivers', 'Approved drivers'], ['audit', 'Journey audit'], ['fuel', 'Fuel management']]} tab={tab} setTab={setTab} />
      {tab === 'plan' && (() => { const J = jr[0]; const approvers = [['Line Supervisor', 'Q-006', 'Approved'], ['Department Head', 'Q-001', 'Approved'], ['Journey Mgmt Centre', 'Q-002', 'Approved'], ['GM / Delegate', 'Q-007', 'Pending']]; const members = [['Sultan Al-Qahtani', 'Q-001', 'Driver', 'Fit'], ['Ahmed Khan', 'Q-006', 'Co-driver', 'Fit'], ['Ravi Kumar', 'Q-004', 'Technician', 'Fit']]; return (
        <React.Fragment>
          <div className="card card-pad" style={{ marginBottom: 14 }}><div className="row" style={{ gap: 18, flexWrap: 'wrap' }}>{[['Plan no.', 'JMP-2024-0056'], ['Journey', J.name], ['Type', J.type], ['Vehicle', J.vehicle], ['Distance', J.km + ' km'], ['Departure', DB.fmt(J.depart)], ['Status', 'Approved']].map(([k, v]) => <div key={k}><div className="eyebrow" style={{ fontSize: 8.5 }}>{k}</div><div style={{ fontSize: 12.5, fontWeight: 700, marginTop: 2 }}>{v}</div></div>)}<span className="spacer" /><Btn variant="primary" icon="plus" onClick={() => openJourneyForm()}>New journey plan</Btn></div></div>
          <div style={{ marginBottom: 14 }}><AINote title="Sentinel — journey risk" clause="JM 6.2">AI scored this route <b>Medium (6)</b> residual after controls (initial High 16). Driver defensive-driving valid, weather clear, fatigue window OK. JMC notified.</AINote></div>
          <div className="split">
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div className="card"><div className="card-head"><Icon name="users" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Journey members</div></div><table className="tbl"><thead><tr><th>Name</th><th>Role</th><th>Medical fitness</th><th>Fit to travel</th></tr></thead><tbody>{members.map((m) => <tr key={m[0]}><td><div className="row" style={{ gap: 7 }}><Avatar id={m[1]} size="sm" /><span style={{ fontSize: 12.5, fontWeight: 600 }}>{m[0]}</span></div></td><td className="faint" style={{ fontSize: 12 }}>{m[2]}</td><td><Badge kind="ok">Valid</Badge></td><td><Badge kind="ok" dot={false}>{m[3]}</Badge></td></tr>)}</tbody></table></div>
              <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Controls / mitigations (JM 6.2)</div>{['Driver well rested & fit', 'Vehicle pre-use inspection done', 'Seat belts enforced', 'Obey speed limits & IVMS', 'Journey updates to JMC', 'Stop on fatigue', 'Weather check completed'].map((c) => <div key={c} className="row" style={{ gap: 8, padding: '4px 0', fontSize: 12 }}><Icon name="check" size={13} style={{ color: 'var(--ok)' }} />{c}</div>)}</div>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Route risk (before → after)</div><div className="row" style={{ gap: 8 }}><div style={{ flex: 1, textAlign: 'center', background: 'var(--bad-bg)', borderRadius: 10, padding: '8px 4px' }}><div className="eyebrow" style={{ fontSize: 8 }}>Initial</div><div style={{ fontSize: 22, fontWeight: 800, color: 'var(--bad)' }}>16</div></div><div style={{ alignSelf: 'center' }}><Icon name="arrowR" size={16} style={{ color: 'var(--text-3)' }} /></div><div style={{ flex: 1, textAlign: 'center', background: 'var(--ok-bg)', borderRadius: 10, padding: '8px 4px' }}><div className="eyebrow" style={{ fontSize: 8 }}>Residual</div><div style={{ fontSize: 22, fontWeight: 800, color: 'var(--ok)' }}>6</div></div></div></div>
              <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Approval workflow</div>{approvers.map((a) => <div key={a[0]} className="row" style={{ gap: 8, padding: '7px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5 }}><Avatar id={a[1]} size="sm" /><div style={{ flex: 1 }}><div style={{ fontWeight: 650 }}>{a[0]}</div><div className="faint" style={{ fontSize: 10.5 }}>{DB.staffById(a[1]).name}</div></div><Badge kind={a[2] === 'Approved' ? 'ok' : 'warn'} dot={a[2] !== 'Approved'}>{a[2]}</Badge></div>)}<Btn variant="primary" icon="truck" size="sm" style={{ marginTop: 10, width: '100%' }} onClick={() => window.toast('Journey started · JMC notified', 'ok')}>Start journey</Btn></div>
            </div>
          </div>
        </React.Fragment>
      ); })()}
      {tab === 'audit' && (() => { const secs = [['Journey planning & authorization', 5, 5], ['Drivers & vehicle compliance', 5, 4], ['Journey execution & monitoring', 6, 5], ['Records & reporting', 4, 3]]; const tot = secs.reduce((a, s) => a + s[1], 0), ok = secs.reduce((a, s) => a + s[2], 0); const pct = Math.round(ok / tot * 100); return (
        <React.Fragment>
          <div className="dk-kpis" style={{ gridTemplateColumns: 'repeat(6,1fr)' }}>{[['Total audits', 12, 'clipboard', 'info'], ['Completed', 8, 'check', 'ok'], ['In progress', 2, 'refresh', 'warn'], ['Not started', 2, 'clock', 'bad'], ['Avg score', '87%', 'trend', 'ok'], ['Open findings', 7, 'alert', 'warn']].map(([k, v, ic, tone], i) => { const t = DASH_TONE[tone]; return <div key={i} className="card" style={{ padding: '13px 14px', minWidth: 0 }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 22, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>; })}</div>
          <div style={{ margin: '14px 0' }}><AINote title="Sentinel — journey audit" clause="JM Procedure">Monthly Journey Management audit JMA-2024-0045 scored <b>{pct}%</b>. AI flags 1 vehicle with an expired inspection and recommends a focused re-audit of the Drivers & Vehicle Compliance section.</AINote></div>
          <div className="split">
            <div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Monthly Journey Management checklist — JMA-2024-0045</div><span className="spacer" /><Badge kind="ok">{pct}%</Badge><DocActions label="journey audit" id="JMA-2024-0045" /></div>
              <table className="tbl"><thead><tr><th>#</th><th>Section</th><th>Items</th><th>Compliant</th><th>% score</th><th>Status</th></tr></thead><tbody>{secs.map((s, i) => { const p = Math.round(s[2] / s[1] * 100); return <tr key={i}><td className="mono">{i + 1}</td><td style={{ fontSize: 12.5 }}>{s[0]}</td><td>{s[1]}</td><td>{s[2]}</td><td><div className="row" style={{ gap: 6 }}><div style={{ width: 44 }}><Bar pct={p} color={scoreColor(p)} /></div><span className="mono faint" style={{ fontSize: 10.5 }}>{p}%</span></div></td><td><Badge kind={p >= 80 ? 'ok' : p >= 60 ? 'warn' : 'bad'}>{p >= 80 ? 'Good' : p >= 60 ? 'Average' : 'Poor'}</Badge></td></tr>; })}</tbody></table>
            </div>
            <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Top findings</div>{[['Vehicle with expired inspection', 'Drivers & Vehicle', 'Major'], ['Journey log not closed on arrival', 'Records', 'Minor'], ['JMC not notified at checkpoint', 'Execution', 'Minor']].map((f, i) => <div key={i} style={{ padding: '7px 0', borderBottom: '1px solid var(--border)' }}><div className="row" style={{ justifyContent: 'space-between' }}><span style={{ fontSize: 12, fontWeight: 600 }}>{f[0]}</span><Badge kind={f[2] === 'Major' ? 'bad' : 'warn'}>{f[2]}</Badge></div><div className="faint" style={{ fontSize: 10.5 }}>{f[1]}</div></div>)}<Btn variant="ghost" icon="plus" size="sm" style={{ marginTop: 10, width: '100%' }} onClick={() => window.toast('New Journey Management audit started · checklist JMA-2024-0046 created', 'ok')}>New audit</Btn></div>
          </div>
        </React.Fragment>
      ); })()}
      <div style={{ marginBottom: 14 }}><AINote title="Unsafe-driving trend & fatigue" clause="AIX">AI detects 2 harsh-braking events on the Central route this week and a fatigue-window departure for V-1042 — plan journeys through the AI assistant to score risk before approval.</AINote></div>
      {tab === 'journey' && <React.Fragment>
        <ModuleDash kpis={jKpis} panels={[
          { title: 'Journeys by status', node: <DashSplit data={byStatus} />, w: '1fr' },
          { title: 'Journeys by type', node: <DashSplit data={byType} />, w: '1fr' },
          { title: 'Journey compliance trend (6 mo)', node: <DashLine trend={jTrend} />, w: '1.3fr' },
        ]} />
        <div className="card" style={{ marginTop: 16 }}><div className="card-head"><Icon name="truck" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Journey register</div></div>
          <table className="tbl"><thead><tr><th>Journey ID</th><th>Route</th><th>Vehicle / driver</th><th>Type</th><th>Departure</th><th>Distance</th><th>Compliance</th><th>Status</th></tr></thead>
            <tbody>{jr.map((j) => <tr key={j.id} className="clickable" onClick={() => window.toast(j.id + ' journey opened', 'info')}><td className="mono cell-strong" style={{ fontSize: 11 }}>{j.id}</td><td style={{ fontSize: 12 }}>{j.name}</td><td className="row" style={{ gap: 6 }}><span className="mono faint" style={{ fontSize: 10.5 }}>{j.vehicle}</span><Avatar id={j.driver} size="sm" /></td><td><span className="tag">{j.type}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{DB.rel(j.depart)}</td><td className="mono" style={{ fontSize: 11.5 }}>{j.km} km</td><td style={{ width: 90 }}><div className="row" style={{ gap: 6 }}><div style={{ width: 44 }}><Bar pct={j.comp} color={scoreColor(j.comp)} /></div><span className="mono faint" style={{ fontSize: 10.5 }}>{j.comp}%</span></div></td><td><Badge kind={jStK(j.status)} dot={j.status !== 'Completed'}>{j.status}</Badge></td><td><RowActions onEdit={() => openJourneyForm(j)} onDelete={() => dbRemove('journeys', 'id', j.id)} /></td></tr>)}</tbody>
          </table>
        </div>
      </React.Fragment>}
      {tab === 'live' && (
        <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 14, alignItems: 'start' }}>
          <div className="card"><div className="card-head"><Icon name="truck" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Live journey map</div><span className="spacer" /><Badge kind="ok" dot>{jcnt('In Progress')} active</Badge></div>
            <div className="card-body">
              <div style={{ position: 'relative', background: '#e8eef4', borderRadius: 12, height: 320, overflow: 'hidden' }}>
                <svg viewBox="0 0 600 320" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
                  <defs>
                    <pattern id="gg" width="34" height="34" patternUnits="userSpaceOnUse"><path d="M34 0H0V34" fill="none" stroke="#d4dde7" strokeWidth="1" /></pattern>
                    <linearGradient id="terr" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#eef3f0" /><stop offset="1" stopColor="#e6ece9" /></linearGradient>
                  </defs>
                  <rect width="600" height="320" fill="url(#terr)" /><rect width="600" height="320" fill="url(#gg)" />
                  {/* terrain / zones */}
                  <path d="M0 230 Q120 200 260 224 T600 210 V320 H0 Z" fill="#dfe9e2" opacity=".7" />
                  <ellipse cx="120" cy="90" rx="90" ry="56" fill="#e9efe6" opacity=".7" />
                  <path d="M380 40 q60 30 40 90 q-50 30 -90 0 q-20 -70 50 -90 Z" fill="#eceee2" opacity=".6" />
                  {/* water */}
                  <path d="M520 0 q-40 60 10 130 q50 60 -10 190 H600 V0 Z" fill="#cfe0ee" opacity=".8" />
                  {/* roads (casing + line) */}
                  <g stroke="#c2ccd8" strokeWidth="9" fill="none" strokeLinecap="round"><path d="M40 270 Q200 250 320 180 T580 90" /><path d="M70 60 Q220 120 360 110 T560 230" /><path d="M300 30 L320 300" /></g>
                  <g stroke="#fff" strokeWidth="3.5" fill="none" strokeLinecap="round"><path d="M40 270 Q200 250 320 180 T580 90" /><path d="M70 60 Q220 120 360 110 T560 230" /><path d="M300 30 L320 300" /></g>
                  {/* active route highlight */}
                  <path d="M120 250 Q240 200 320 180 T470 110" fill="none" stroke="#2f6fed" strokeWidth="3.5" strokeDasharray="2 6" strokeLinecap="round" />
                  {/* origin / destination site markers */}
                  <g transform="translate(120 250)"><circle r="6" fill="#1f56cf" stroke="#fff" strokeWidth="2" /></g>
                  <g transform="translate(470 110)"><rect x="-6" y="-6" width="12" height="12" rx="2" fill="#15a06b" stroke="#fff" strokeWidth="2" /></g>
                </svg>
                {/* site labels */}
                <div style={{ position: 'absolute', left: 120, top: 250, transform: 'translate(-50%,8px)', fontSize: 9.5, fontWeight: 700, color: '#1f56cf', whiteSpace: 'nowrap' }}>Riyadh Office</div>
                <div style={{ position: 'absolute', left: 470, top: 110, transform: 'translate(-50%,8px)', fontSize: 9.5, fontWeight: 700, color: '#0f7a4f', whiteSpace: 'nowrap' }}>Wellhead Site-12</div>
                {[['V-1056', 'Ahmed K. · 85 km/h', 360, 165, 'var(--ok)'], ['V-1042', 'Sultan A. · 72 km/h', 250, 195, 'var(--primary-600)'], ['V-1031', 'Stopped · 25 min', 430, 120, 'var(--bad)']].map(([id, loc, x, y, c], i) => (
                  <div key={i} style={{ position: 'absolute', left: x, top: y, transform: 'translate(-50%,-100%)', textAlign: 'center' }}>
                    <div style={{ background: '#fff', borderRadius: 8, padding: '4px 8px', boxShadow: '0 4px 12px rgba(13,30,54,.22)', fontSize: 10.5, fontWeight: 700, color: 'var(--ink)', whiteSpace: 'nowrap' }}>{id}<div style={{ fontSize: 9, fontWeight: 500, color: 'var(--text-3)' }}>{loc}</div></div>
                    <span style={{ display: 'inline-block', width: 0, height: 0, borderLeft: '5px solid transparent', borderRight: '5px solid transparent', borderTop: '7px solid #fff' }} />
                    <span style={{ display: 'block', width: 13, height: 13, borderRadius: '50%', background: c, border: '2.5px solid #fff', margin: '-2px auto 0', boxShadow: '0 2px 6px rgba(0,0,0,.3)' }} />
                  </div>
                ))}
                <div style={{ position: 'absolute', right: 10, bottom: 10, display: 'flex', flexDirection: 'column', gap: 4 }}>{['plus', 'min', 'pin'].map((ic) => <span key={ic} style={{ width: 26, height: 26, borderRadius: 7, background: '#fff', boxShadow: '0 2px 6px rgba(0,0,0,.15)', display: 'grid', placeItems: 'center', color: 'var(--text-2)' }}><Icon name={ic === 'min' ? 'x' : ic} size={13} /></span>)}</div>
              </div>
              <table className="tbl" style={{ marginTop: 10 }}><thead><tr><th>Journey</th><th>Vehicle / driver</th><th>Current location</th><th>Speed</th><th>Status</th></tr></thead>
                <tbody>{jr.filter((j) => j.status === 'In Progress' || j.status === 'Overdue').slice(0, 5).map((j) => <tr key={j.id}><td className="mono cell-strong" style={{ fontSize: 10.5 }}>{j.id}</td><td className="row" style={{ gap: 6 }}><span className="mono faint" style={{ fontSize: 10.5 }}>{j.vehicle}</span><Avatar id={j.driver} size="sm" /></td><td className="faint" style={{ fontSize: 11.5 }}>{j.to}</td><td className="mono" style={{ fontSize: 11 }}>{60 + (j.km % 30)} km/h</td><td><Badge kind={jStK(j.status)} dot>{j.status}</Badge></td></tr>)}</tbody>
              </table>
            </div>
          </div>
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 8 }}>Alerts & notifications</div>
            {[['Journey stopped', 'JRN-2024-0045 stopped > 15 min', 'bad', 'clock'], ['Delay predicted', 'JRN-2024-0043 ETA +25 min', 'warn', 'alert'], ['Fatigue window', 'V-1042 departs in rest window', 'warn', 'helmet']].map((a, i) => { const t = DASH_TONE[a[2]]; return <div key={i} className="row" style={{ gap: 10, padding: '9px 0', borderBottom: '1px solid var(--border)' }}><span style={{ width: 28, height: 28, borderRadius: 8, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={a[3]} size={14} /></span><div style={{ flex: 1 }}><div style={{ fontSize: 12, fontWeight: 650 }}>{a[0]}</div><div className="faint" style={{ fontSize: 10.5 }}>{a[1]}</div></div></div>; })}
            <div style={{ marginTop: 12 }}><AINote title="Live route adherence" clause="AIX">Sentinel monitors position, speed & route — auto-raises an alert on harsh-braking, over-speed or route deviation.</AINote></div>
          </div>
        </div>
      )}
      {tab === 'register' && (
        <div className="split">
          <div className="card"><div className="card-head"><Icon name="truck" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Fleet register</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>{veh.length} vehicles</span></div>
            <table className="tbl"><thead><tr><th>Vehicle</th><th>Plate</th><th>Type</th><th>Driver</th><th>Inspection</th><th>Docs</th><th>Compliance</th><th>Status</th></tr></thead>
              <tbody>{veh.map((v) => <tr key={v.id} className="clickable" style={{ background: selV.id === v.id ? 'var(--ai-bg)' : undefined }} onClick={() => setSelV(v)}><td className="mono cell-strong" style={{ fontSize: 11 }}>{v.id}</td><td className="mono faint" style={{ fontSize: 10.5 }}>{v.plate}</td><td style={{ fontSize: 12 }}>{v.type}</td><td><Avatar id={v.driver} size="sm" /></td><td><Badge kind={v.insp === 'Valid' ? 'ok' : 'warn'}>{v.insp}</Badge></td><td><Badge kind={v.docs === 'Valid' ? 'ok' : 'bad'}>{v.docs}</Badge></td><td style={{ width: 80 }}><div style={{ width: 56 }}><Bar pct={v.comp} color={scoreColor(v.comp)} /></div></td><td><Badge kind={v.status === 'Active' ? 'ok' : v.status === 'Out of Service' ? 'bad' : 'warn'} dot={v.status !== 'Active'}>{v.status}</Badge></td><td><RowActions onDelete={() => dbRemove('fleetVehicles', 'id', v.id)} /></td></tr>)}</tbody>
            </table>
          </div>
          <div className="card card-pad">
            <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Vehicle details</div><Badge kind={selV.status === 'Active' ? 'ok' : 'warn'}>{selV.status}</Badge></div>
            <div style={{ fontSize: 14, fontWeight: 700 }}>{selV.id} · {selV.plate}</div>
            {[['Type', selV.type], ['Make / model', selV.model], ['Region', selV.region], ['Inspection due', selV.inspDays + ' days'], ['Overall compliance', selV.comp + '%']].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5 }}><span className="faint">{k}</span><b>{v}</b></div>)}
            <div className="row" style={{ gap: 7, marginTop: 6 }}><span className="faint" style={{ fontSize: 11.5 }}>Driver</span><Avatar id={selV.driver} size="sm" /></div>
            <div className="eyebrow" style={{ margin: '12px 0 6px' }}>Inspection</div><DashSplit data={inspSummary} />
            <div className="eyebrow" style={{ margin: '12px 0 6px' }}>Documents</div><DashSplit data={docSummary} />
          </div>
        </div>
      )}
      {tab === 'drivers' && <React.Fragment>
        <div className="dk-kpis" style={{ gridTemplateColumns: 'repeat(5,1fr)' }}>{[['Approved drivers', drv.length, 'users', 'info'], ['Both qualified', drv.filter((d) => d.status === 'Both Qualified').length, 'check', 'ok'], ['Black-top only', drv.filter((d) => d.status === 'Black-top Only').length, 'truck', 'info'], ['Skid road only', drv.filter((d) => d.status === 'Skid Road Only').length, 'pin', 'warn'], ['Expired', drv.filter((d) => d.status === 'Expired').length, 'clock', 'bad']].map(([k, v, ic, tone], i) => { const t = DASH_TONE[tone]; return <div key={i} className="card" style={{ padding: '13px 14px', minWidth: 0 }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 22, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>; })}</div>
        <div className="card" style={{ marginTop: 16 }}><div className="card-head"><Icon name="users" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Approved drivers — defensive driving (black-top & skid road)</div></div>
          <table className="tbl"><thead><tr><th>Driver</th><th>Employee ID</th><th>Licence</th><th>Vehicle</th><th>Black-top valid</th><th>Skid road valid</th><th>Status</th></tr></thead>
            <tbody>{drv.map((d) => { const s = DB.staffById(d.staff); return <tr key={d.id} className="clickable" onClick={() => window.toast(s.name + ' driver record', 'info')}><td><div className="row" style={{ gap: 7 }}><Avatar id={d.staff} size="sm" /><span style={{ fontSize: 12.5, fontWeight: 600 }}>{s.name}</span></div></td><td className="mono faint" style={{ fontSize: 11 }}>{d.emp}</td><td className="mono faint" style={{ fontSize: 11 }}>{d.lic}</td><td style={{ fontSize: 12 }}>{d.veh}</td><td><span style={{ fontSize: 11.5, fontWeight: 600, color: d.blacktop <= DB.TODAY ? 'var(--bad)' : 'var(--text)' }}>{d.blacktop <= DB.TODAY ? 'Expired' : DB.rel(d.blacktop)}</span></td><td><span style={{ fontSize: 11.5, fontWeight: 600, color: d.skid <= DB.TODAY ? 'var(--bad)' : 'var(--text)' }}>{d.skid <= DB.TODAY ? 'Expired' : DB.rel(d.skid)}</span></td><td><Badge kind={drStK(d.status)} dot={d.status !== 'Both Qualified'}>{d.status}</Badge></td><td><RowActions onDelete={() => dbRemove('drivers', 'id', d.id)} /></td></tr>; })}</tbody>
          </table>
        </div>
      </React.Fragment>}
      {tab === 'fuel' && (
        <div className="card"><div className="card-head"><Icon name="receipt" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Fuel management</div><span className="spacer" /><Badge kind="ai">AI consumption watch</Badge></div>
          <table className="tbl"><thead><tr><th>Vehicle</th><th>Period</th><th>Litres</th><th>Cost (SAR)</th><th>km/L</th><th>Flag</th></tr></thead>
            <tbody>{DB.fuel.map((f, i) => <tr key={i}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{f.vehicle}</td><td className="faint">{f.period}</td><td>{f.litres}</td><td className="mono">{f.cost}</td><td className="mono">{f.kmL}</td><td><Badge kind={f.flag === 'Normal' ? 'ok' : 'warn'} dot={f.flag !== 'Normal'}>{f.flag}</Badge></td></tr>)}</tbody>
          </table>
          <div className="card-body" style={{ borderTop: '1px solid var(--border)' }}><AINote title="Consumption anomaly" clause="AIX">VH-08 fuel use is ~80% above its baseline this week — AI correlates it with idle time on the Central route and flags a possible leak or unauthorized use for inspection.</AINote></div>
        </div>
      )}
    </div>
  );
}
function ContractorsModule() {
  const [tab, setTab] = useState('register');
  const co = DB.contractors;
  const coKpis = [['Contractors', co.length, 'briefcase', 'info'], ['Approved', co.filter((c) => c.prequal === 'Approved').length, 'check', 'ok'], ['Conditional / pending', co.filter((c) => c.prequal !== 'Approved').length, 'alert', 'warn'], ['Insurance lapsed', co.filter((c) => c.insurance <= DB.TODAY).length, 'shield', 'bad'], ['HSE below 80', co.filter((c) => c.hse < 80).length, 'flag', 'bad'], ['Avg HSE score', Math.round(co.reduce((s, c) => s + c.hse, 0) / co.length), 'trend', 'ai']];
  const prequal = [{ l: 'Approved', v: co.filter((c) => c.prequal === 'Approved').length, c: '#22c55e' }, { l: 'Conditional', v: co.filter((c) => c.prequal === 'Conditional').length, c: '#f59e0b' }, { l: 'Suspended / pending', v: co.filter((c) => c.prequal !== 'Approved' && c.prequal !== 'Conditional').length, c: '#ef4444' }].filter((x) => x.v);
  const hseBars = co.slice(0, 6).map((c) => ({ l: c.name.split(' ')[0], v: c.hse, c: c.hse >= 90 ? '#22c55e' : c.hse >= 80 ? '#f59e0b' : '#ef4444' }));
  return (
    <div className="page page-wide rise">
      <PageHead title="Contractor Management" sub="Prequalification · vendor assessment · HSE compliance · insurance · performance">
        <Btn variant="primary" icon="plus" onClick={() => openContractorForm()}>Prequalify</Btn>
      </PageHead>
      <div style={{ marginBottom: 14 }}><AINote title="Contractor risk — Gulf Crane Hire" clause="AIX">Insurance has lapsed and HSE score (78) is below threshold, yet prequalification renewal is due in 20 days. Sentinel recommends suspending mobilization until both are resolved.</AINote></div>
      <Tabs tabs={[['register', 'Register & prequalification'], ['dashboard', 'Dashboard'], ['assessment', 'Vendor assessment']]} tab={tab} setTab={setTab} />
      {tab === 'dashboard' && <ModuleDash kpis={coKpis} panels={[
        { title: 'Prequalification status', node: <DashSplit data={prequal} />, w: '1fr' },
        { title: 'HSE score by contractor', node: <DashHBars data={hseBars} />, w: '1.4fr' },
      ]} />}
      {tab === 'register' && (
        <div className="card"><table className="tbl"><thead><tr><th>Ref</th><th>Contractor</th><th>Scope</th><th>Prequal</th><th>HSE</th><th>Insurance</th><th>Expiry</th></tr></thead>
          <tbody>{DB.contractors.map((c) => <tr key={c.id} className="clickable" onClick={() => window.toast(`${c.id} — ${c.name}`, 'info')}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{c.id}</td><td style={{ fontSize: 12.5 }}>{c.name}</td><td className="faint" style={{ fontSize: 12 }}>{c.scope}</td><td><Badge kind={c.prequal === 'Approved' ? 'ok' : 'warn'} dot>{c.prequal}</Badge></td><td><b style={{ color: scoreColor(c.hse) }}>{c.hse}</b></td><td><span style={{ color: c.insurance <= DB.TODAY ? 'var(--bad)' : 'var(--text)', fontWeight: 600 }}>{DB.rel(c.insurance)}</span></td><td className="faint">{DB.rel(c.exp)}</td><td><RowActions onEdit={() => openContractorForm(c)} onDelete={() => dbRemove('contractors', 'id', c.id)} /></td></tr>)}</tbody>
        </table></div>
      )}
      {tab === 'assessment' && (
        <div className="card"><div className="card-head"><Icon name="trend" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Vendor performance assessment</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Contractor</th><th>HSE</th><th>Quality</th><th>Delivery</th><th>Overall</th><th>Last review</th></tr></thead>
            <tbody>{DB.vendorAssessment.map((v) => <tr key={v.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{v.id}</td><td style={{ fontSize: 12.5 }}>{v.contractor}</td><td><b style={{ color: scoreColor(v.hse) }}>{v.hse}</b></td><td><b style={{ color: scoreColor(v.quality) }}>{v.quality}</b></td><td><b style={{ color: scoreColor(v.delivery) }}>{v.delivery}</b></td><td><Badge kind={v.overall >= 90 ? 'ok' : v.overall >= 80 ? 'warn' : 'bad'}>{v.overall}</Badge></td><td className="faint">{DB.rel(v.last)}</td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}
function EmergencySimulator() {
  const scenarios = [
    { id: 'h2s', name: 'H₂S release — Vessel V-204', risk: 'High', target: '< 8 min to muster', steps: ['Gas detection alarm at 10 ppm → escalates to 20 ppm', 'Initiate evacuation upwind to MP-1; don escape sets', 'Account for all personnel at muster (86 expected)', 'Rescue team dons SCBA; isolate the source', 'Stand down on confirmed clear atmosphere reading'] },
    { id: 'fire', name: 'Fire — hot-work area P-198', risk: 'High', target: '< 5 min response', steps: ['Raise alarm; fire watch attacks with extinguisher', 'Isolate fuel/energy; evacuate to MP-2', 'Headcount; notify ERT & client emergency desk', 'ERT contains and cordons re-ignition zone', 'Investigate & log as an incident'] },
    { id: 'cse', name: 'Confined-space rescue — V-204', risk: 'Critical', target: '< 6 min extraction', steps: ['Attendant raises alarm — do NOT enter unprotected', 'Rescue team: SCBA + tripod retrieval system', 'Casualty extraction to fresh air', 'First aid + medevac per the ERP', 'Debrief & drill-effectiveness review'] },
  ];
  const [sel, setSel] = useState('h2s');
  const [run, setRun] = useState(false);
  const [step, setStep] = useState(0);
  const sc = scenarios.find((s) => s.id === sel);
  useEffect(() => { if (run && step < sc.steps.length) { const t = setTimeout(() => setStep((s) => s + 1), 720); return () => clearTimeout(t); } }, [run, step, sel]);
  return (
    <div className="card" style={{ borderColor: 'var(--ai-line)' }}>
      <div className="card-head" style={{ background: 'linear-gradient(120deg, var(--ai-bg), #fff)' }}><span className="ai-badge-ico"><Icon name="sparkles" size={15} fill /></span><div className="h-sec" style={{ fontSize: 14 }}>Sentinel — emergency scenario simulator</div><span className="spacer" /><Badge kind={sc.risk === 'Critical' ? 'bad' : 'warn'}>{sc.risk}</Badge></div>
      <div className="card-body">
        <div className="row wrap" style={{ gap: 8, marginBottom: 14 }}>{scenarios.map((s) => <button key={s.id} className="tag" style={{ cursor: 'pointer', border: `1px solid ${sel === s.id ? 'var(--ai)' : 'var(--border)'}`, background: sel === s.id ? 'var(--ai-bg)' : '#fff', fontWeight: sel === s.id ? 700 : 500 }} onClick={() => { setSel(s.id); setRun(false); setStep(0); }}>{s.name}</button>)}</div>
        {!run ? <div className="row" style={{ justifyContent: 'space-between' }}><div className="faint" style={{ fontSize: 12.5 }}>Sentinel simulates the response sequence and evaluates timing against the ERP target ({sc.target}).</div><Btn variant="ai" size="sm" icon="sparkles" onClick={() => { setRun(true); setStep(0); }}>Run simulation</Btn></div>
          : <React.Fragment>
            {sc.steps.map((st, i) => (
              <div key={i} className="row" style={{ gap: 12, alignItems: 'flex-start', padding: '10px 0', borderBottom: i < sc.steps.length - 1 ? '1px solid var(--border)' : 'none', opacity: i < step ? 1 : .25, transition: 'opacity .35s' }}>
                <span style={{ width: 26, height: 26, borderRadius: '50%', flex: 'none', display: 'grid', placeItems: 'center', background: i < step ? 'var(--ai-bg)' : '#eef1f6', color: i < step ? 'var(--ai)' : 'var(--text-3)', fontSize: 11, fontWeight: 700 }}>{i + 1}</span>
                <div style={{ fontSize: 12.5, lineHeight: 1.5, paddingTop: 2 }}>{st}</div>
              </div>
            ))}
            {step >= sc.steps.length && <div style={{ marginTop: 12 }}><AINote title="Simulation evaluation" clause="AIX">Sentinel projects muster within target IF escape sets and the rescue team are pre-positioned. Gap found: the rescue-tripod inspection is overdue — resolve before the next live drill.</AINote></div>}
          </React.Fragment>}
      </div>
    </div>
  );
}
function EmergencyModule() {
  const [tab, setTab] = useState('drills');
  const E = DB.emergency;
  const dr = DB.drills;
  const eKpis = [['Drills (YTD)', dr.length, 'shield', 'info'], ['Satisfactory', dr.filter((d) => d.outcome === 'Satisfactory').length, 'check', 'ok'], ['Needs improvement', dr.filter((d) => d.outcome !== 'Satisfactory').length, 'alert', 'warn'], ['Muster points', 4, 'flag', 'info'], ['Equipment overdue', 1, 'clock', 'bad'], ['ERP readiness', '92%', 'check', 'ai']];
  const byOutcome = [{ l: 'Satisfactory', v: dr.filter((d) => d.outcome === 'Satisfactory').length, c: '#22c55e' }, { l: 'Improvement noted', v: dr.filter((d) => d.outcome !== 'Satisfactory').length, c: '#f59e0b' }].filter((x) => x.v);
  const byType = (() => { const m = {}; dr.forEach((d) => { m[d.type] = (m[d.type] || 0) + 1; }); const cols = ['#2563eb', '#ef4444', '#f59e0b', '#7a5bff', '#22c55e']; return Object.entries(m).map(([l, v], i) => ({ l, v, c: cols[i % cols.length] })); })();
  return (
    <div className="page page-wide rise">
      <PageHead title="Emergency Preparedness" sub="Drills · ERP & emergency contacts · muster tracking · emergency equipment"><DateFilter /></PageHead>
      <Tabs tabs={[['drills', 'Drills'], ['dashboard', 'Dashboard'], ['sim', 'Scenario simulator'], ['contacts', 'ERP & contacts'], ['muster', 'Muster'], ['equip', 'Equipment']]} tab={tab} setTab={setTab} />
      {tab === 'dashboard' && <ModuleDash kpis={eKpis} panels={[
        { title: 'Drill outcomes', node: <DashSplit data={byOutcome} />, w: '1fr' },
        { title: 'Drills by scenario type', node: <DashHBars data={byType} />, w: '1.4fr' },
      ]} />}
      {tab === 'sim' && <EmergencySimulator />}
      {tab === 'drills' && <div style={{ marginBottom: 14 }}><AINote title="Drill effectiveness analysis" clause="AIX">AI rates the confined-space rescue drill 'improvement noted' — response time exceeded target. A re-drill is recommended before the next CSE campaign on P-204.</AINote></div>}
      {tab === 'equip' && <div style={{ marginBottom: 14 }}><AINote title="Emergency equipment gap" clause="ISO 45001 §8.2">The rescue tripod & winch inspection is overdue while a confined-space entry permit is active on the same project — AI flags this as a critical readiness gap.</AINote></div>}
      {tab === 'muster' && <div style={{ marginBottom: 14 }}><AINote title="Muster readiness" clause="AIX">P-198 muster point hasn't drilled in 18 days — AI recommends a headcount drill to keep evacuation timing verified.</AINote></div>}
      {tab === 'drills' && (
        <div className="card"><table className="tbl"><thead><tr><th>Ref</th><th>Scenario</th><th>Project</th><th>Date</th><th>Participants</th><th>Outcome</th></tr></thead>
          <tbody>{DB.drills.map((d) => <tr key={d.id} className="clickable" onClick={() => window.toast(`${d.id} drill record`, 'info')}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{d.id}</td><td style={{ fontSize: 12.5 }}>{d.type}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{d.project}</td><td className="faint">{DB.fmt(d.date)}</td><td>{d.participants}</td><td><Badge kind={d.outcome === 'Satisfactory' ? 'ok' : 'warn'}>{d.outcome}</Badge></td></tr>)}</tbody>
        </table></div>
      )}
      {tab === 'contacts' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
          <div className="card"><div className="card-head"><Icon name="bell" size={16} style={{ color: 'var(--bad)' }} /><div className="h-sec">Emergency response contacts</div></div>
            <div className="card-body">{E.contacts.map((c, i) => <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '9px 0', borderBottom: i < E.contacts.length - 1 ? '1px solid var(--border)' : 'none' }}><div><div style={{ fontSize: 12.5, fontWeight: 650 }}>{c.role}</div><div className="faint" style={{ fontSize: 11.5 }}>{c.name}</div></div><span className="mono" style={{ fontSize: 12.5, fontWeight: 600 }}>{c.phone}</span></div>)}</div>
          </div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>ERP plans</div>
            {[['Site Emergency Response Plan', 'Approved · Rev 3'], ['H₂S Contingency Plan', 'Approved · Rev 2'], ['Oil-Spill Response Plan', 'Approved · Rev 1'], ['Medical Evacuation Plan', 'Approved · Rev 2']].map(([t, s], i) => <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '8px 0', borderBottom: i < 3 ? '1px solid var(--border)' : 'none' }}><span style={{ fontSize: 12.5 }}><Icon name="documents" size={13} style={{ color: 'var(--primary-600)', marginRight: 7 }} />{t}</span><Badge kind="ok">{s}</Badge></div>)}
          </div>
        </div>
      )}
      {tab === 'muster' && (
        <div className="card"><div className="card-head"><Icon name="users" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Muster points & headcount</div></div>
          <table className="tbl"><thead><tr><th>Project</th><th>Muster point</th><th>Headcount</th><th>Last drill</th><th>Status</th></tr></thead>
            <tbody>{E.muster.map((m, i) => <tr key={i}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{m.project}</td><td style={{ fontSize: 12.5 }}>{m.point}</td><td><b>{m.headcount}</b></td><td className="faint">{DB.rel(m.lastDrill)}</td><td><Badge kind={m.status === 'Verified' ? 'ok' : 'warn'} dot={m.status !== 'Verified'}>{m.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'equip' && (
        <div className="card"><div className="card-head"><Icon name="shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Emergency equipment inspection</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Item</th><th>Project</th><th>Next inspection</th><th>Status</th></tr></thead>
            <tbody>{E.equip.map((e) => <tr key={e.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{e.id}</td><td style={{ fontSize: 12.5 }}>{e.item}</td><td className="mono faint" style={{ fontSize: 11.5 }}>{e.project}</td><td><span style={{ fontWeight: 600, color: e.insp <= DB.TODAY ? 'var(--bad)' : 'var(--text)' }}>{DB.rel(e.insp)}</span></td><td><Badge kind={e.status === 'Serviceable' ? 'ok' : 'warn'} dot={e.status !== 'Serviceable'}>{e.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}

/* ===================== ROUTER + LOGIN ============================== */
/* ===================== FIELD OPERATIONS ============================ */
function FieldOpsModule({ onNav }) {
  const [tab, setTab] = useState('deploy');
  const dep = DB.fieldOps.deployments; const camp = DB.fieldOps.campaigns;
  const onSite = dep.filter((d) => d.status === 'On site').length;
  const crewMembers = dep.reduce((s, d) => s + (d.members || 0), 0);
  const avgReady = Math.round(camp.filter((c) => c.readiness).reduce((s, c) => s + c.readiness, 0) / camp.filter((c) => c.readiness).length);
  const foKpis = [['Active crews', dep.length, 'truck', 'info'], ['On site', onSite, 'check', 'ok'], ['Personnel deployed', crewMembers, 'users', 'ai'], ['Campaigns', camp.length, 'workflow', 'info'], ['Shutdowns', camp.filter((c) => c.type === 'Shutdown').length, 'flag', 'bad'], ['Avg readiness', avgReady + '%', 'shield', 'warn']];
  const byStatus = (() => { const m = {}; dep.forEach((d) => { m[d.status] = (m[d.status] || 0) + 1; }); const cols = ['#22c55e', '#2563eb', '#f59e0b', '#7a5bff']; return Object.entries(m).map(([l, v], i) => ({ l, v, c: cols[i % cols.length] })); })();
  const readyBars = camp.filter((c) => c.readiness).slice(0, 6).map((c) => ({ l: c.id, v: c.readiness, c: scoreColor(c.readiness) }));
  return (
    <div className="page page-wide rise">
      <PageHead title="Field Operations" sub="Mobile field crews · rapid deployment · shutdowns & turnarounds — Saudi Arabia · Iraq · Kuwait">
        <Btn icon="truck" variant="primary" onClick={() => openDispatchForm()}>Dispatch crew</Btn>
      </PageHead>
      <div style={{ marginBottom: 14 }}><AINote title="Deployment readiness" clause="AIX" action="Open mobilization plan" onAction={() => onNav('competency')}>Shutdown SD-09 mobilizes in days at 82% readiness — Sentinel flags 7 expiring certifications and 1 hydrotest-pump cert as the gating blockers across crews.</AINote></div>
      <Tabs tabs={[['deploy', 'Mobile deployments'], ['dashboard', 'Dashboard'], ['campaigns', 'Shutdowns & turnarounds']]} tab={tab} setTab={setTab} />
      {tab === 'dashboard' && <ModuleDash kpis={foKpis} panels={[
        { title: 'Crews by status', node: <DashSplit data={byStatus} />, w: '1fr' },
        { title: 'Campaign readiness', node: <DashHBars data={readyBars} />, w: '1.4fr' },
      ]} />}
      {tab === 'deploy' && (
        <div className="card"><div className="card-head"><Icon name="truck" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Mobile field crews</div><span className="spacer" /><Badge kind="ai">live status</Badge></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Crew</th><th>Location</th><th>Members</th><th>Equipment</th><th>Status</th></tr></thead>
            <tbody>{DB.fieldOps.deployments.map((d) => <tr key={d.id} className="clickable" onClick={() => window.toast(`${d.id} deployment pack`, 'info')}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{d.id}</td><td style={{ fontSize: 12.5 }}>{d.crew}</td><td className="faint" style={{ fontSize: 12 }}>{d.location}</td><td>{d.members}</td><td className="faint" style={{ fontSize: 12 }}>{d.equip}</td><td><Badge kind={d.status === 'On site' ? 'ok' : 'info'} dot>{d.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
      {tab === 'campaigns' && (
        <div className="card"><div className="card-head"><Icon name="workflow" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Shutdowns & turnarounds</div></div>
          <table className="tbl"><thead><tr><th>Ref</th><th>Campaign</th><th>Type</th><th>Client</th><th>Window</th><th>Crews</th><th>Readiness</th><th>Status</th></tr></thead>
            <tbody>{DB.fieldOps.campaigns.map((c) => <tr key={c.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{c.id}</td><td style={{ fontSize: 12.5 }}>{c.name}</td><td><Badge kind={c.type === 'Shutdown' ? 'bad' : 'warn'}>{c.type}</Badge></td><td className="faint">{c.client}</td><td className="faint" style={{ fontSize: 12 }}>{c.window}</td><td>{c.crews}</td><td style={{ width: 110 }}>{c.readiness ? <div className="row" style={{ gap: 6 }}><div style={{ width: 60 }}><Bar pct={c.readiness} color={scoreColor(c.readiness)} /></div><span className="mono faint" style={{ fontSize: 11 }}>{c.readiness}%</span></div> : <span className="faint">—</span>}</td><td><Badge kind={c.status === 'Execution' ? 'ok' : c.status === 'Tender' ? 'neutral' : 'warn'} dot>{c.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}

/* ===================== ADMINISTRATION · RBAC ======================== */
const RBAC_DEPTS = [
  { code: 'QHSE', name: 'QHSE / Compliance', members: 9, modules: 'Incidents · Risk · PTW · Audits · CAPA · Compliance · Emergency' },
  { code: 'OPS', name: 'Operations & Projects', members: 14, modules: 'Projects · Field Ops · PTW · Services · Incidents' },
  { code: 'QC', name: 'Quality / QA-QC', members: 7, modules: 'Quality · NCR · ITP · Audits · Documents' },
  { code: 'AST', name: 'Asset Integrity', members: 5, modules: 'Assets · Calibration · TPI · Breakdown' },
  { code: 'FLT', name: 'Fleet', members: 4, modules: 'Fleet · Fuel · GPS · Journey Mgmt' },
  { code: 'HR', name: 'HR / Competency', members: 6, modules: 'Competency · Training · Licences' },
  { code: 'DOC', name: 'Document Control', members: 3, modules: 'Documents · Controlled register · Compliance' },
  { code: 'PROC', name: 'Procurement / Vendors', members: 4, modules: 'Contractors · Vendor assessment' },
  { code: 'EMG', name: 'Emergency Response', members: 5, modules: 'Emergency · Drills · ERP' },
  { code: 'EXE', name: 'Executive', members: 3, modules: 'All departments · read-only · NL query' },
  { code: 'IT', name: 'IT / Administration', members: 2, modules: 'Administration · Roles · Audit log' },
];
const RBAC_LEVELS = [
  { lv: 'L0', name: 'Administrator', scope: 'System', can: 'Configure departments, levels, roles · manage users · read audit log', appr: false },
  { lv: 'L1', name: 'Field / Viewer', scope: 'Own records', can: 'View dashboards · submit field reports & observations', appr: false },
  { lv: 'L2', name: 'Officer / Supervisor', scope: 'Team', can: 'Create incidents, NCRs, observations · request permits', appr: false },
  { lv: 'L3', name: 'Coordinator', scope: 'Register', can: 'Manage a register (assets, competency, documents)', appr: false },
  { lv: 'L4', name: 'Manager / Authority', scope: 'Department', can: 'Approve & close · issue permits · sign off CAPA', appr: true },
  { lv: 'L5', name: 'Department Head', scope: 'Department + config', can: 'Full department control + local configuration', appr: true },
  { lv: 'L6', name: 'Executive', scope: 'Cross-department', can: 'Read everything across departments · natural-language query · no approvals', appr: false },
];
const RBAC_AUDIT = [
  { t: '08:42', who: 'Omar Nasser', act: 'Granted L4 · Permit Authority to Marwan Hadi (OPS)', ico: 'shield', tone: 'info' },
  { t: '08:31', who: 'Omar Nasser', act: 'Created department EMG · Emergency Response', ico: 'plus', tone: 'ok' },
  { t: 'Yesterday', who: 'Layla Karim', act: 'Closed NCR-2041 — scope: QC department only', ico: 'check', tone: 'ok' },
  { t: 'Yesterday', who: 'System', act: 'Blocked AST L3 from approving CAPA — level lacks approval right', ico: 'alert', tone: 'warn' },
  { t: '2 days ago', who: 'Faisal Al-Harbi', act: 'Cross-department read query: "open HiPo incidents this quarter"', ico: 'search', tone: 'info' },
  { t: '2 days ago', who: 'Omar Nasser', act: 'Revoked dormant account · rotated demo seed users', ico: 'logout', tone: 'bad' },
];
function AdminModule() {
  const [tab, setTab] = useState('depts');
  const tabs = [['depts', 'Departments'], ['levels', 'Levels & permissions'], ['users', 'Users'], ['audit', 'Audit log']];
  return (
    <div className="page page-wide rise">
      <PageHead title="Administration" sub="Department × Level access control — effective permission = Department ∩ Level ∩ Scope">
        <Badge kind="info">RBAC</Badge>
      </PageHead>
      <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(4,1fr)', marginBottom: 16 }}>
        <Kpi label="Departments" value={RBAC_DEPTS.length} icon="grid" tone="info" />
        <Kpi label="Access levels" value={RBAC_LEVELS.length} icon="shield" tone="info" />
        <Kpi label="Active users" value={RBAC_DEPTS.reduce((s, d) => s + d.members, 0)} icon="users" tone="ok" />
        <Kpi label="Demo personas" value={DB.demoUsers.length} icon="sparkles" tone="ai" />
      </div>
      <AINote tone="ai">Effective permissions are computed live: a user can only act where their <b>department</b> owns the module, their <b>level</b> grants the verb (view / create / approve), and the record falls inside their <b>scope</b>. Switch personas from the top-right menu to see navigation, dashboards and Sentinel context change instantly.</AINote>
      <Tabs tabs={tabs} tab={tab} setTab={setTab} />

      {tab === 'depts' && (
        <div className="card"><table className="tbl">
          <thead><tr><th>Code</th><th>Department</th><th>Members</th><th>Owned modules</th></tr></thead>
          <tbody>{RBAC_DEPTS.map((d) => (
            <tr key={d.code}><td><Badge kind="info">{d.code}</Badge></td><td style={{ fontWeight: 650 }}>{d.name}</td><td>{d.members}</td><td className="faint" style={{ fontSize: 12 }}>{d.modules}</td></tr>
          ))}</tbody>
        </table></div>
      )}

      {tab === 'levels' && (
        <div className="card"><table className="tbl">
          <thead><tr><th>Level</th><th>Role</th><th>Scope</th><th>Capabilities</th><th>Approve</th></tr></thead>
          <tbody>{RBAC_LEVELS.map((l) => (
            <tr key={l.lv}><td><Badge kind="neutral">{l.lv}</Badge></td><td style={{ fontWeight: 650 }}>{l.name}</td><td>{l.scope}</td><td className="faint" style={{ fontSize: 12 }}>{l.can}</td><td>{l.appr ? <Badge kind="ok">Yes</Badge> : <Badge kind="neutral">No</Badge>}</td></tr>
          ))}</tbody>
        </table></div>
      )}

      {tab === 'users' && (
        <div className="card"><table className="tbl">
          <thead><tr><th>User</th><th>Department</th><th>Level</th><th>Landing</th><th>Scope / capability</th></tr></thead>
          <tbody>{DB.demoUsers.map((u) => (
            <tr key={u.id}><td><div className="row" style={{ gap: 8 }}><span className="avatar" style={{ background: u.color, color: '#fff', fontSize: 10, width: 26, height: 26 }}>{u.initials}</span><span style={{ fontWeight: 650 }}>{u.name}</span>{u.ro && <Badge kind="warn">read-only</Badge>}</div></td><td>{u.deptCode}</td><td><Badge kind="neutral">{u.level}</Badge> {u.levelName}</td><td className="faint" style={{ fontSize: 12 }}>{u.landing}</td><td className="faint" style={{ fontSize: 12 }}>{u.cap}</td></tr>
          ))}</tbody>
        </table></div>
      )}

      {tab === 'audit' && (
        <div className="card card-pad">
          <SectionHead icon="shield" title="Immutable audit log" sub="Every grant, revocation and scope decision — append-only" />
          <div style={{ marginTop: 6 }}>{RBAC_AUDIT.map((a, i) => {
            const fg = { bad: 'var(--bad)', ok: 'var(--ok)', warn: 'var(--warn)', info: 'var(--primary-600)' }[a.tone];
            const bg = { bad: 'var(--bad-bg)', ok: 'var(--ok-bg)', warn: 'var(--warn-bg)', info: 'var(--info-bg)' }[a.tone];
            return (
              <div key={i} className="row" style={{ gap: 11, padding: '10px 4px', borderBottom: '1px solid var(--border)', alignItems: 'flex-start' }}>
                <span className="kpi-ico" style={{ background: bg, color: fg, width: 30, height: 30 }}><Icon name={a.ico} size={15} /></span>
                <div style={{ flex: 1 }}><div style={{ fontSize: 13, fontWeight: 600 }}>{a.act}</div><div className="faint" style={{ fontSize: 11.5, marginTop: 1 }}>{a.who}</div></div>
                <span className="faint" style={{ fontSize: 11.5 }}>{a.t}</span>
              </div>
            );
          })}</div>
        </div>
      )}
    </div>
  );
}
/* ===================== HSE STATISTICS (PrimaDRILL model) ============ */
const HSE_BASE = 1000000; // rates per 1,000,000 man-hours (drilling convention)
function hseStatCompute(v) {
  const n = (k) => Number(v[k]) || 0;
  const mh = n('manhours');
  const lwdc = n('lwdc'), lostDays = n('lostDays'), restricted = n('restricted'), mtc = n('mtc'), fat = n('fatalities'), fa = n('firstAid');
  const ltifr = mh ? +(lwdc * HSE_BASE / mh).toFixed(2) : 0;
  const ltisr = mh ? +(lostDays * HSE_BASE / mh).toFixed(2) : 0;
  const trcf = mh ? +((fat + lwdc + restricted + mtc) * HSE_BASE / mh).toFixed(2) : 0;
  const tips = [];
  if (!mh) tips.push({ tone: 'info', title: 'Enter man-hours first', body: 'Man-hours are the denominator for every frequency/severity rate — AI computes LTIFR, LTISR and TRCF live as you type.' });
  else {
    tips.push({ tone: trcf > 0 ? 'warn' : 'ok', title: `Live rates · per ${(HSE_BASE / 1e6)}M man-hours`, body: `LTIFR ${ltifr} · LTISR ${ltisr} · TRCF ${trcf}. AI recalculates on every keystroke and rolls them into the YTD trend.` });
    if (fat > 0) tips.push({ tone: 'bad', title: 'Fatality recorded', body: 'AI escalates immediately — statutory notification, board alert and a full investigation are required before the month can be closed.' });
    if (lwdc > 0) tips.push({ tone: 'warn', title: 'Lost-time injury in month', body: 'AI resets the LTI-free-days counter and links the case to its incident investigation & CAPA.' });
    const leading = n('inductions') + n('tbt') + n('inspections') + n('audits') + n('drills');
    const lagging = fa + mtc + restricted + lwdc + fat;
    if (leading && lagging >= 0) tips.push({ tone: lagging === 0 ? 'ok' : 'info', title: 'Leading vs lagging balance', body: `${leading} proactive activities logged against ${lagging} incident outcome(s). A high leading-to-lagging ratio is the signal AI tracks for safety-culture maturity.` });
  }
  return { tips, risk: Math.min(100, Math.round(trcf * 18)), riskLabel: 'TRCF (per 1M man-hours)' };
}
function openHseStat() {
  const lead = ['inductions', 'tbt', 'trainings', 'meetings', 'inspections', 'campaigns', 'rewards', 'audits', 'alerts', 'drills'];
  const lag = ['propDamage', 'firstAid', 'mtc', 'restricted', 'lwdc', 'lostDays', 'fatalities'];
  const lbl = Object.fromEntries(DB.hseStats.metrics.map((m) => [m.key, m.label]));
  window.openAIAssist({
    title: 'Add monthly HSE statistics', sub: 'PrimaDRILL HSE dashboard · Sentinel computes LTIFR / LTISR / TRCF live', icon: 'chart', width: 880, compute: hseStatCompute, submitLabel: 'Save month', done: 'Monthly HSE statistics saved · rates & YTD updated',
    fields: [
      { type: 'section', label: 'Reporting period' },
      { key: 'month', label: 'Month', type: 'select', options: DB.hseStats.months, half: true },
      { key: 'preparedBy', label: 'Prepared by', type: 'text', value: 'Amira Saleh · HSE Manager', half: true },
      { type: 'section', label: 'Exposure' },
      { key: 'manhours', label: 'Man-hours', type: 'text', placeholder: 'e.g. 152000', half: true },
      { key: 'manpower', label: 'Manpower (headcount)', type: 'text', placeholder: 'e.g. 540', half: true },
      { type: 'section', label: 'Leading indicators' },
      ...lead.map((k) => ({ key: k, label: lbl[k], type: 'text', half: true, placeholder: '0' })),
      { type: 'section', label: 'Lagging indicators' },
      ...lag.map((k) => ({ key: k, label: lbl[k], type: 'text', half: true, placeholder: '0' })),
    ],
  });
}
function HseStatsModule() {
  const s = DB.hseStats, R = s.rows, mh = R.manhours;
  const sum = (a) => a.reduce((x, y) => x + y, 0);
  const ytd = (m) => m.agg === 'avg' ? Math.round(sum(R[m.key]) / R[m.key].length) : sum(R[m.key]);
  const mhTotal = sum(mh);
  const rate = (arr) => +(sum(arr) * HSE_BASE / mhTotal).toFixed(2);
  const ltifr = rate(R.lwdc), ltisr = rate(R.lostDays), trcf = +(sum(R.fatalities.map((x, i) => x + R.lwdc[i] + R.restricted[i] + R.mtc[i])) * HSE_BASE / mhTotal).toFixed(2);
  const monthRate = (arr, i) => mh[i] ? +(arr[i] * HSE_BASE / mh[i]).toFixed(2) : 0;
  const fmtN = (x) => x >= 1000 ? x.toLocaleString() : x;
  const cell = { padding: '7px 9px', fontSize: 11.5, textAlign: 'right', borderBottom: '1px solid var(--border)', whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' };
  const rateRows = [['LTIFR', R.lwdc, ltifr], ['LTISR', R.lostDays, ltisr], ['TRCF', R.fatalities.map((x, i) => x + R.lwdc[i] + R.restricted[i] + R.mtc[i]), trcf]];
  let lastGroup = '';
  return (
    <div className="page page-wide rise">
      <PageHead title="HSE Statistics" sub={`Monthly safety performance · ${s.facility} · ${s.location} · ${s.year} — PrimaDRILL HSE dashboard model`}>
        <Btn variant="ghost" icon="download" size="sm" onClick={() => window.toast('HSE dashboard exported (XLSX)', 'info')}>Export</Btn>
        <Btn variant="primary" icon="plus" onClick={() => openHseStat()}>Add monthly statistics</Btn>
      </PageHead>
      <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(5,1fr)', marginBottom: 16 }}>
        <Kpi label="Total man-hours YTD" value={(mhTotal / 1e6).toFixed(2) + 'M'} icon="clock" tone="info" />
        <Kpi label="LTIFR" value={ltifr} icon="trend" tone="ok" sub=" per 1M hrs" />
        <Kpi label="LTISR" value={ltisr} icon="helmet" tone="warn" sub=" days/1M hrs" />
        <Kpi label="TRCF" value={trcf} icon="alert" tone="warn" sub=" per 1M hrs" />
        <Kpi label="Fatalities YTD" value={sum(R.fatalities)} icon="check-circle" tone="ok" />
      </div>
      <AINote tone="ai" title="Sentinel — HSE performance read" clause="ISO 45001 §9.1">{sum(R.lwdc)} lost-time injury YTD against {(mhTotal / 1e6).toFixed(2)}M man-hours → LTIFR {ltifr}. Leading-indicator activity ({sum(R.inductions)} inductions · {sum(R.tbt)} TBTs · {sum(R.inspections)} inspections) is strong and trending up, while recordable outcomes trend down — a maturing safety culture. Rates recompute automatically each time a month is entered.</AINote>
      <div className="card" style={{ marginTop: 16, overflowX: 'auto' }}>
        <div className="card-head"><Icon name="chart" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Monthly HSE statistics</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>Prepared by {s.preparedBy}</span></div>
        <table className="tbl" style={{ minWidth: 980 }}>
          <thead><tr><th style={{ textAlign: 'left', position: 'sticky', left: 0, background: 'var(--surface)' }}>Indicator</th>{s.months.map((m) => <th key={m} style={{ textAlign: 'right' }}>{m}</th>)}<th style={{ textAlign: 'right', color: 'var(--primary-700)' }}>YTD</th></tr></thead>
          <tbody>
            {s.metrics.map((m) => {
              const head = m.group !== lastGroup ? (lastGroup = m.group) : null;
              return (
                <React.Fragment key={m.key}>
                  {head && <tr><td colSpan={14} style={{ padding: '6px 9px', fontSize: 10, fontWeight: 700, letterSpacing: '.5px', textTransform: 'uppercase', color: 'var(--text-3)', background: 'var(--surface-2)' }}>{head} indicators</td></tr>}
                  <tr>
                    <td style={{ padding: '7px 9px', fontSize: 12, fontWeight: 600, position: 'sticky', left: 0, background: 'var(--surface)', borderBottom: '1px solid var(--border)' }}>{m.label}</td>
                    {R[m.key].map((x, i) => <td key={i} style={cell}>{fmtN(x)}</td>)}
                    <td style={{ ...cell, fontWeight: 800, color: 'var(--primary-700)', background: 'var(--primary-50)' }}>{fmtN(ytd(m))}</td>
                  </tr>
                </React.Fragment>
              );
            })}
            <tr><td colSpan={14} style={{ padding: '6px 9px', fontSize: 10, fontWeight: 700, letterSpacing: '.5px', textTransform: 'uppercase', color: 'var(--ai)', background: 'var(--ai-bg)' }}>Calculated rates · per 1M man-hours</td></tr>
            {rateRows.map(([lab, arr, yv]) => (
              <tr key={lab}>
                <td style={{ padding: '7px 9px', fontSize: 12, fontWeight: 700, position: 'sticky', left: 0, background: 'var(--surface)', borderBottom: '1px solid var(--border)' }}>{lab}</td>
                {arr.map((x, i) => <td key={i} style={{ ...cell, color: 'var(--text-2)' }}>{monthRate(arr, i)}</td>)}
                <td style={{ ...cell, fontWeight: 800, color: 'var(--ai)', background: 'var(--ai-bg)' }}>{yv}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
/* Non-Conformance Report — fields per PD.L4.QA.05 (NCR / CAR) */
function openNcrReport(rec) {
  const e = rec || {}; const d = e.detail || {};
  window.openAIAssist({
    title: rec ? 'Edit ' + e.id : 'Non-Conformance Report — NCR / CAR', sub: 'Form PD.L4.QA.05 · Sentinel checks repeats and drafts the CAR & effectiveness check', icon: 'check-shield', width: 940, compute: ncrCompute, submitLabel: rec ? 'Save changes' : 'Raise NCR / CAR', done: rec ? 'NCR updated' : 'NCR / CAR raised · AI root-cause & CAR draft ready',
    fields: [
      { type: 'section', label: 'NCR details' },
      { key: 'ncrNo', label: 'NCR no.', type: 'text', value: rec ? e.id : _seq(DB.ncrs, 'NCR-26-', 60), half: true },
      { key: 'date', label: 'Date', type: 'text', value: d.date || (e.date ? DB.fmt(dDate(e.date)) : ''), placeholder: '14 Jun 2026', half: true },
      { key: 'department', label: 'Department / area', type: 'text', value: d.department, half: true },
      { key: 'docRef', label: 'Document reference', type: 'text', value: d.docRef, placeholder: 'ITP / spec / drawing no.', half: true },
      { key: 'initiatedBy', label: 'NCR initiated by', type: 'text', value: d.initiatedBy, half: true },
      { key: 'receivedBy', label: 'NCR received by', type: 'text', value: d.receivedBy, half: true },
      { key: 'projectPo', label: 'Project / PO no.', type: 'select', options: DB.projects.map((p) => p.id + ' · ' + p.name), value: d.projectPo },
      { key: 'serviceDesc', label: 'Service / product description', type: 'text', value: d.serviceDesc, half: true },
      { key: 'customerSupplier', label: 'Customer / supplier name', type: 'text', value: d.customerSupplier, half: true },
      { key: 'quantity', label: 'Quantity', type: 'text', value: d.quantity, half: true },
      { key: 'category', label: 'Category', type: 'select', options: ['Documentation', 'Process deviation', 'Material', 'Supplier', 'Workmanship', 'Dimensional', 'Welding', 'Coating', 'Calibration', 'Client complaint'], value: e.cat, half: true },
      { key: 'severity', label: 'Severity', type: 'radio', options: ['Minor', 'Major'], value: e.severity || 'Major', half: true },
      { type: 'section', label: 'Finding', hint: 'What is the problem · which criteria it breaches · the evidence' },
      { key: 'finding', label: 'Finding — description of non-conformity', type: 'textarea', rows: 4, value: e.title || d.finding, placeholder: '1) Define the problem  2) Criteria breached (spec / customer / legal / standard)  3) Evidence…' },
      { type: 'section', label: 'Correction (containment)' },
      { key: 'correction', label: 'Correction — action taken to resolve', type: 'textarea' },
      { key: 'correctionApprover', label: 'Proposed correction approved by', type: 'text', half: true },
      { key: 'correctionResp', label: 'Correction responsibility', type: 'text', half: true },
      { key: 'correctionTarget', label: 'Correction target date', type: 'text', half: true },
      { key: 'correctionComplete', label: 'Correction completion date', type: 'text', half: true },
      { key: 'correctionVerifier', label: 'Correction verified by', type: 'text', half: true },
      { type: 'section', label: 'Root cause & corrective / preventive action (CAR)' },
      { key: 'rootCause', label: 'Root cause of non-conformity', type: 'textarea', value: d.rootCause, placeholder: 'Sentinel drafts this from the 5-Why on submit…' },
      { key: 'capa', label: 'Corrective / preventive action (CAR)', type: 'textarea', value: d.capa },
      { key: 'newRisk', label: 'New risk identified (if any)', type: 'text', half: true },
      { key: 'mocRequired', label: 'MOC required?', type: 'radio', options: ['No', 'Yes'], half: true },
      { key: 'capaApprover', label: 'Proposed CAPA approved by', type: 'text', half: true },
      { key: 'caResp', label: 'CA responsibility', type: 'text', half: true },
      { key: 'caTarget', label: 'CA target date', type: 'text', half: true },
      { key: 'caComplete', label: 'CA completion date', type: 'text', half: true },
      { key: 'caVerifier', label: 'CA verified by', type: 'text', half: true },
      { type: 'section', label: 'Verification of effectiveness' },
      { key: 'effectiveness', label: 'Verification of effectiveness of the CA / review of PA', type: 'textarea', value: d.effectiveness },
      { key: 'verifResp', label: 'Verification responsibility', type: 'text', value: d.verifResp, half: true },
      { key: 'verifDoneBy', label: 'Verification done by', type: 'text', value: d.verifDoneBy, half: true },
      { key: 'verifTarget', label: 'Verification target date', type: 'text', value: d.verifTarget, half: true },
      { key: 'verifComplete', label: 'Verification completion date', type: 'text', value: d.verifComplete, half: true },
      { key: 'status', label: 'Status of non-conformity', type: 'radio', options: ['Open', 'In progress', 'Closed'], value: e.status || 'Open', half: true },
    ],
    onSave: (v) => {
      const title = (v.finding || '').slice(0, 80) || v.serviceDesc || 'Nonconformity';
      const detail = { date: v.date, department: v.department, docRef: v.docRef, initiatedBy: v.initiatedBy, receivedBy: v.receivedBy, projectPo: v.projectPo, serviceDesc: v.serviceDesc, customerSupplier: v.customerSupplier, quantity: v.quantity, finding: v.finding, correction: v.correction, correctionApprover: v.correctionApprover, correctionResp: v.correctionResp, correctionTarget: v.correctionTarget, correctionComplete: v.correctionComplete, correctionVerifier: v.correctionVerifier, rootCause: v.rootCause, capa: v.capa, newRisk: v.newRisk, mocRequired: v.mocRequired, capaApprover: v.capaApprover, caResp: v.caResp, caTarget: v.caTarget, caComplete: v.caComplete, caVerifier: v.caVerifier, effectiveness: v.effectiveness, verifResp: v.verifResp, verifDoneBy: v.verifDoneBy, verifTarget: v.verifTarget, verifComplete: v.verifComplete };
      const stage = v.status === 'Closed' ? 'Closed' : v.status === 'In progress' ? 'CAPA' : 'Open';
      const proj = (v.projectPo || 'P-204').split(' · ')[0];
      const dt = v.date && !isNaN(new Date(v.date)) ? new Date(v.date) : DB.D(0);
      if (rec) dbUpdate('ncrs', 'id', e.id, { title, project: proj, cat: v.category, severity: v.severity, status: v.status, stage, detail: Object.assign({}, e.detail, detail) });
      else dbAdd('ncrs', { id: v.ncrNo || _seq(DB.ncrs, 'NCR-26-', 60), title, project: proj, cat: v.category || 'Workmanship', severity: v.severity || 'Major', owner: 'Q-001', stage, status: v.status || 'Open', date: dt, detail });
    },
  });
}
/* Management of Change — Request form per PD.L4.QA.03 */
function openMocRequest() {
  window.openAIAssist({
    title: 'Management of Change — Request', sub: 'Form PD.L4.QA.03 · Sentinel computes the 5×5 risk and routes the approval chain', icon: 'workflow', width: 920, compute: mocCompute, submitLabel: 'Submit MOC request', done: 'MOC request submitted · routed for MR → MD/VP approval',
    fields: [
      { type: 'section', label: 'Request' },
      { key: 'mocNo', label: 'MOC no.', type: 'text', value: 'MOC-26-014', half: true },
      { key: 'date', label: 'Date', type: 'text', placeholder: '14 Jun 2026', half: true },
      { key: 'requestedBy', label: 'Requested by', type: 'text', half: true },
      { key: 'department', label: 'Department', type: 'text', half: true },
      { key: 'changeType', label: 'Type of change', type: 'checks', options: ['Organization Structure Change', 'Key Personnel Change', 'Critical Equipment Change', 'Critical Supplier', 'QMS Changes', 'Product / Process Change', 'Change Facility'] },
      { key: 'description', label: 'Description of change', type: 'textarea' },
      { key: 'reason', label: 'Reason for change', type: 'textarea' },
      { type: 'section', label: 'Identified risk & priority (5×5)' },
      { key: 'riskIdentified', label: 'Risk identified (if any)', type: 'text' },
      { key: 'probability', label: 'Probability (P)', type: 'select', options: RISK_P, half: true },
      { key: 'severity', label: 'Severity (S)', type: 'select', options: RISK_S, half: true },
      { key: 'controls', label: 'Controls to mitigate', type: 'textarea' },
      { type: 'section', label: 'Expected impact' },
      { key: 'impactAreas', label: 'Impact on', type: 'checks', options: ['Product Quality', 'Product Delivery', 'Processes', 'Procedures', 'Responsibilities', 'Equipment', 'Competency'] },
      { type: 'section', label: 'MR review' },
      { key: 'mrDecision', label: 'MR decision', type: 'radio', options: ['Approved', 'Denied'], half: true },
      { key: 'approvedBy', label: 'Approved by (MR)', type: 'text', half: true },
      { key: 'mrActions', label: 'Required before change', type: 'checks', options: ['Edit operating procedure', 'Training required', 'Permit required', 'Notification required', 'Qualification required'] },
      { type: 'section', label: 'Management approval (MD / VP)' },
      { key: 'mgmtDecision', label: 'Decision', type: 'radio', options: ['Approved', 'Denied'], half: true },
      { key: 'mgmtComments', label: 'Comments', type: 'textarea' },
      { type: 'section', label: 'Execution (change executor)' },
      { key: 'estCost', label: 'Estimated cost', type: 'text', half: true },
      { key: 'expTime', label: 'Expected time', type: 'text', half: true },
      { key: 'expManpower', label: 'Expected manpower', type: 'text', half: true },
      { key: 'expDowntime', label: 'Expected downtime', type: 'text', half: true },
      { key: 'supervisedBy', label: 'Supervised by', type: 'text', half: true },
      { key: 'changesDone', label: 'Details of changes done', type: 'textarea' },
    ],
  });
}
const MOC_STEPS = ['Request', 'Screening', 'Risk Assessment', 'Review & Approval', 'Implementation', 'Verification', 'Closeout'];
function MocModule({ onOpen }) {
  const [tab, setTab] = useState('register');
  const m = DB.mocs;
  const open = m.filter((x) => x.status !== 'Closed').length;
  const high = m.filter((x) => x.rpn >= 10).length;
  const pending = m.filter((x) => /approval|review/i.test(x.stage)).length;
  const kpis = [['Total MOC', m.length, 'workflow', 'info'], ['Open', open, 'refresh', 'warn'], ['High / Extreme risk', high, 'alert', 'bad'], ['Pending approval', pending, 'clock', 'warn'], ['Closed', m.filter((x) => x.status === 'Closed').length, 'check', 'ok'], ['Avg cycle (days)', 17, 'history', 'ai']];
  const byType = (() => { const g = {}; m.forEach((x) => { g[x.type] = (g[x.type] || 0) + 1; }); const cols = ['#2563eb', '#7a5bff', '#f59e0b', '#22c55e', '#0e7490']; return Object.entries(g).map(([l, v], i) => ({ l, v, c: cols[i % cols.length] })); })();
  const byRisk = [{ l: 'High / Extreme', v: high, c: '#ef4444' }, { l: 'Medium', v: m.filter((x) => x.rpn >= 5 && x.rpn < 10).length, c: '#f59e0b' }, { l: 'Low', v: m.filter((x) => x.rpn < 5).length, c: '#22c55e' }].filter((x) => x.v);
  const ageing = [{ l: '0–7 days', v: 4, c: '#22c55e' }, { l: '8–30 days', v: 5, c: '#eab308' }, { l: '31–60 days', v: 2, c: '#f97316' }, { l: '> 60 days', v: 1, c: '#ef4444' }];
  const openMoc = (x) => onOpen && onOpen('moc', x);
  return (
    <div className="page page-wide rise">
      <PageHead title="Management of Change" sub="MOC requests · 5×5 risk · MR → MD/VP approval — PD-QSP MOC procedure"><DateFilter />
        <Btn variant="primary" icon="plus" onClick={() => openMocForm()}>Raise MOC request</Btn>
      </PageHead>
      <Tabs tabs={[['register', 'MOC register'], ['dashboard', 'Dashboard'], ['process', 'Process overview']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote tone="ai" title="Sentinel — change-risk watch" clause="ISO 9001 §6.3">MOC-26-009 (relocate chemical store) carries an Extremely-High RPN (15) and is still at MR review — AI recommends MD/VP escalation and a COSHH re-assessment before approval. Two open MOCs touch P-211 mobilisation; sequencing them avoids a delivery-schedule clash.</AINote></div>
      {tab === 'dashboard' && <ModuleDash kpis={kpis} panels={[
        { title: 'MOC by change type', node: <DashSplit data={byType} />, w: '1fr' },
        { title: 'MOC by risk level', node: <DashSplit data={byRisk} />, w: '1fr' },
        { title: 'Open MOC ageing', node: <DashHBars data={ageing} />, w: '1.2fr' },
      ]} />}
      {tab === 'process' && <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 12 }}>MOC process — request to closeout</div><Stepper steps={MOC_STEPS} current={3} /></div>}
      {tab === 'register' && (
        <div className="card">
          <div className="card-head"><Icon name="workflow" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">MOC register</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>{m.length} · click to open lifecycle</span></div>
          <table className="tbl">
            <thead><tr><th>MOC</th><th>Change</th><th>Type</th><th>Risk (RPN)</th><th>Stage</th><th>Owner</th><th>Status</th></tr></thead>
            <tbody>{m.map((x) => (
              <tr key={x.id} className="clickable" onClick={() => openMoc(x)}>
                <td className="mono cell-strong" style={{ fontSize: 11.5 }}>{x.id}</td>
                <td style={{ fontSize: 12.5, maxWidth: 240 }}>{x.title}</td>
                <td><span className="tag">{x.type}</span></td>
                <td><Badge kind={x.rpn >= 15 ? 'bad' : x.rpn >= 10 ? 'warn' : 'neutral'}>{x.rating} · {x.rpn}</Badge></td>
                <td className="faint" style={{ fontSize: 12 }}>{x.stage}</td>
                <td><Avatar id={x.owner} size="sm" /></td>
                <td><Badge kind={x.status === 'Closed' ? 'ok' : 'info'} dot={x.status !== 'Closed'}>{x.status}</Badge></td>
                <td><RowActions onView={() => openMoc(x)} onEdit={() => openMocForm(x)} onDelete={() => dbRemove('mocs', 'id', x.id)} /></td>
              </tr>
            ))}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}
function MocDetail({ rec, onBack }) {
  const x = rec;
  const impacts = [['Process Safety', 4, 3], ['Personnel Safety', 3, 2], ['Environment', 2, 2], ['Asset Integrity', 4, 3], ['Product Quality', 2, 3], ['Operational Efficiency', 3, 2]];
  const controls = [['Install pressure relief valve (PRV) per API 520', 'Q-007', '+10d', 'Planned'], ['Select agitator to API 610 / vendor spec', 'Q-006', '+14d', 'Planned'], ['Mechanical seal + noise insulation', 'Q-001', '+12d', 'Planned']];
  const approvers = [['Operations Manager', 'Q-006', 'Approved'], ['HSE Manager', 'Q-001', 'Approved'], ['Engineering Manager', 'Q-007', 'Pending'], ['Plant Manager', 'Q-002', 'Pending']];
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 10, marginBottom: 16 }}>
        <button className="icon-btn" onClick={onBack}><Icon name="chevL" size={17} /></button>
        <span className="kpi-ico" style={{ width: 36, height: 36, background: 'var(--info-bg)', color: 'var(--primary-600)' }}><Icon name="workflow" size={18} /></span>
        <div><div className="row" style={{ gap: 9 }}><span className="h-page" style={{ fontSize: 20 }}>{x.id}</span><Badge kind={x.rpn >= 15 ? 'bad' : x.rpn >= 10 ? 'warn' : 'neutral'}>{x.rating} · RPN {x.rpn}</Badge><Badge kind="info" dot>{x.status}</Badge></div><div className="h-sub">{x.title}</div></div>
        <span className="spacer" /><DocActions label="MOC request" id={x.id} />
      </div>
      <Stepper steps={['Entering', 'Risk Analysis', 'Approval']} current={2} sub={['Create & submit MOC', 'Assess impact & risk', 'Review & approve']} />
      <div className="dk-panels" style={{ gridTemplateColumns: '1fr 1.1fr 1fr', marginTop: 16 }}>
        <div className="card card-pad" style={{ minWidth: 0 }}>
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>1 · Entering</div><Badge kind="neutral">Submitted</Badge></div>
          {[['Title', x.title], ['Change type', x.type], ['Category', 'Mechanical'], ['Location', 'NGP - Area 12'], ['Requestor', DB.staffById(x.owner).name], ['Target date', '+10d']].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5, gap: 8 }}><span className="faint">{k}</span><b style={{ textAlign: 'right' }}>{v}</b></div>)}
          <div className="eyebrow" style={{ margin: '10px 0 4px' }}>Required documents</div>
          {['PHA completed', 'Operating procedure', 'P&ID / drawings', 'Equipment datasheet'].map((d) => <div key={d} className="row" style={{ gap: 7, padding: '3px 0', fontSize: 11.5 }}><Icon name="check" size={13} style={{ color: 'var(--ok)' }} />{d}</div>)}
        </div>
        <div className="card card-pad" style={{ minWidth: 0 }}>
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>2 · Risk Analysis</div><Badge kind="warn">{x.rating} ({x.rpn})</Badge></div>
          <table className="tbl" style={{ fontSize: 11 }}><thead><tr><th>Aspect</th><th>S</th><th>L</th><th>Score</th></tr></thead><tbody>{impacts.map((im, i) => { const sc = im[1] * im[2]; return <tr key={i}><td style={{ fontSize: 11 }}>{im[0]}</td><td>{im[1]}</td><td>{im[2]}</td><td><Badge kind={sc >= 12 ? 'bad' : sc >= 6 ? 'warn' : 'ok'}>{sc}</Badge></td></tr>; })}</tbody></table>
          <div className="eyebrow" style={{ margin: '10px 0 4px' }}>Mitigation / controls</div>
          {controls.map((c, i) => <div key={i} className="row" style={{ gap: 6, padding: '4px 0', borderBottom: '1px solid var(--border)', fontSize: 11 }}><span style={{ flex: 1 }}>{c[0]}</span><Avatar id={c[1]} size="sm" /><Badge kind="neutral">{c[3]}</Badge></div>)}
        </div>
        <div className="card card-pad" style={{ minWidth: 0 }}>
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>3 · Approval</div><Badge kind="warn" dot>Pending</Badge></div>
          {approvers.map((a, i) => <div key={i} className="row" style={{ gap: 8, padding: '8px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5 }}><Avatar id={a[1]} size="sm" /><div style={{ flex: 1 }}><div style={{ fontWeight: 650 }}>{a[0]}</div><div className="faint" style={{ fontSize: 10.5 }}>{DB.staffById(a[1]).name}</div></div><Badge kind={a[2] === 'Approved' ? 'ok' : 'warn'} dot={a[2] !== 'Approved'}>{a[2]}</Badge></div>)}
          <div className="row" style={{ gap: 8, marginTop: 10 }}><Btn variant="ghost" size="sm" icon="x" onClick={() => { dbUpdate('mocs', 'id', x.id, { status: 'Open', stage: 'Returned' }); window.toast('MOC returned', 'warn'); onBack(); }}>Reject</Btn><Btn variant="primary" size="sm" icon="check" onClick={() => { dbUpdate('mocs', 'id', x.id, { status: 'In Progress', stage: 'Implementation' }); window.toast('MOC approved · implementation opened', 'ok'); onBack(); }}>Approve</Btn></div>
        </div>
      </div>
    </div>
  );
}
/* ========= incident sub-sections (Investigation / Actions / Lessons / Alerts) ========= */
const sKind = (s) => ({ Open: 'info', 'In Progress': 'warn', 'Pending Verification': 'info', Closed: 'ok', Overdue: 'bad', Published: 'ok', Draft: 'neutral', 'Under Review': 'warn', Expired: 'bad' }[s] || 'neutral');
const pKind = (p) => ({ High: 'bad', Medium: 'warn', Low: 'ok' }[p] || 'neutral');
function IncidentBar({ inc, onNav, statusText }) {
  const d = incidentFull(inc);
  return (
    <div className="card card-pad" style={{ marginBottom: 14 }}>
      <div className="row" style={{ gap: 18, flexWrap: 'wrap', alignItems: 'center' }}>
        <span className="kpi-ico" style={{ width: 44, height: 44, borderRadius: 11, background: 'var(--bad)', color: '#fff', flex: 'none' }}><Icon name="helmet" size={23} /></span>
        <div className="row" style={{ gap: 8, alignItems: 'center', flexWrap: 'wrap' }}><span style={{ fontSize: 18, fontWeight: 800 }}>{inc.id}</span>{d.ltiBadge && <Badge kind="bad">{d.ltiBadge}</Badge>}<span className="faint" style={{ fontSize: 12 }}>{d.typeLabel}</span></div>
        {[['Date', DB.fmt(inc.date)], ['Location', d.location || 'Main Plant - Area 1'], ['Department', d.department || 'Operations'], ['Work Activity', d.workActivity || '—'], ['Status', statusText || 'Investigation & RCA'], ['Severity / Risk', `${d.risk.rating} (${d.risk.score})`], ['Injured Person', d.injured ? d.injured.name : '—']].map(([k, v]) => <div key={k}><span className="faint" style={{ fontSize: 10.5 }}>{k}</span><div style={{ fontSize: 12, fontWeight: 700, color: k === 'Severity / Risk' ? 'var(--bad)' : 'var(--text)' }}>{v}</div></div>)}
        <Btn variant="ghost" icon="ext" size="sm" style={{ marginLeft: 'auto' }} onClick={() => onNav('incidents')}>View incident details</Btn>
      </div>
    </div>
  );
}
function CauseTree({ tree }) {
  const box = (txt, bg, bd, lbl) => <div style={{ background: bg, border: `1px solid ${bd}`, borderLeft: `4px solid ${bd}`, borderRadius: 6, padding: '7px 10px', fontSize: 11, fontWeight: 600, minWidth: 118, maxWidth: 150, lineHeight: 1.25 }}>{lbl && <div style={{ fontSize: 8.5, fontWeight: 800, letterSpacing: '.5px', color: bd, marginBottom: 2 }}>{lbl}</div>}{txt}</div>;
  const conn = <span style={{ width: 16, height: 2, background: 'var(--border-2)', flex: 'none' }} />;
  return (
    <div className="row" style={{ gap: 0, alignItems: 'center', overflowX: 'auto', paddingBottom: 6 }}>
      {box(tree.top, 'var(--bad-bg)', 'var(--bad)', 'TOP EVENT')}{conn}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>{tree.branches.map((b, bi) => (
        <div key={bi} className="row" style={{ gap: 0, alignItems: 'center' }}>{box(b.cause, '#fff4e6', '#f97316')}{conn}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>{b.children.map((c, ci) => (
            <div key={ci} className="row" style={{ gap: 0, alignItems: 'center' }}>{box(c.cause, '#fef9c3', '#eab308')}{conn}
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>{c.roots.map((r, ri) => <div key={ri}>{box(r, '#dcfce7', '#22c55e')}</div>)}</div>
            </div>
          ))}</div>
        </div>
      ))}</div>
    </div>
  );
}
function InvestigationDetail({ rec, onBack, onNav }) {
  const inc = rec;
  const [tab, setTab] = useState('rca');
  const tabs = [['investigation', 'Investigation'], ['rca', 'Root Cause Analysis (Cause Tree)'], ['capa', 'CAPA (Actions)'], ['timeline', 'Timeline'], ['attach', 'Attachments'], ['lessons', 'Lessons Learned']];
  const acts = DB.capaActions.slice(0, 5);
  const actionStatus = [{ l: 'Open', v: 3, c: 'var(--bad)' }, { l: 'In Progress', v: 1, c: 'var(--warn)' }, { l: 'Pending Verification', v: 0, c: '#2563eb' }, { l: 'Closed', v: 1, c: 'var(--ok)' }];
  const roots = ['No tag line used', 'No exclusion zone enforced', 'Inadequate training', 'Supervision inadequate'];
  const tl = [['Investigation Started', '13 May · 08:50 AM', 'ok'], ['Evidence Collection', '13 May · 10:15 AM', 'ok'], ['Witness Interview', '13 May · 02:30 PM', 'ok'], ['RCA (Cause Tree)', '14 May · 09:00 AM', 'ok'], ['CAPA Initiated', '14 May · 11:20 AM', 'warn'], ['Verification Pending', '—', 'idle'], ['Investigation Closure', '—', 'idle']];
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 8, marginBottom: 10 }}><button className="row" onClick={onBack} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--primary-600)', fontWeight: 600, fontSize: 12.5, fontFamily: 'inherit', gap: 4 }}><Icon name="chevL" size={15} />Back to investigations</button></div>
      <PageHead title="Incident Investigation, RCA (Cause Tree) & CAPA" sub={`Incident Management · Investigation · ${inc.id}`}><DocActions label="investigation report" id={inc.id} /></PageHead>
      <div style={{ marginBottom: 14 }}><IncidentStepper cur={3} /></div>
      <IncidentBar inc={inc} onNav={onNav} statusText="Investigation & RCA" />
      <Tabs tabs={tabs} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — AI cause-tree & root-cause assist" clause="ISO 45001 §10.2">AI reconstructed the event and proposes the cause tree below — <b>4 root causes</b> at 88% confidence. Highest-leverage: <b>“No tag line used”</b> &amp; <b>“Supervision inadequate”</b>. 5 CAPAs pre-drafted. Two prior at-height events share this lifting-controls signature — treat as systemic.</AINote></div>
      <div style={{ display: 'grid', gridTemplateColumns: '0.9fr 2.1fr 1.1fr 1.1fr', gap: 14, alignItems: 'start', marginBottom: 14 }}>
        <div className="card card-pad">
          <div className="eyebrow" style={{ marginBottom: 10 }}>Investigation summary</div>
          {[['Investigation No.', 'INV-26-0123'], ['Lead Investigator', 'Sultan Al-Qahtani'], ['Investigation Team', '4 Members'], ['Start Date', '13 May 2024'], ['Target Completion', '27 May 2024'], ['Actual Completion', '—']].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', fontSize: 12 }}><span className="faint">{k}</span><b style={{ textAlign: 'right' }}>{v}</b></div>)}
          <div className="row" style={{ justifyContent: 'space-between', padding: '5px 0', fontSize: 12 }}><span className="faint">Status</span><Badge kind="warn">In Progress</Badge></div>
          <Btn variant="ghost" icon="signature" size="sm" style={{ marginTop: 8, width: '100%' }} onClick={() => window.toast('Edit investigation summary', 'info')}>Edit summary</Btn>
        </div>
        <div className="card card-pad" style={{ overflow: 'hidden' }}>
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Cause tree analysis</div><div className="row" style={{ gap: 10, flexWrap: 'wrap' }}>{[['Problem / Event', 'var(--bad)'], ['Direct Cause', '#f97316'], ['Indirect Cause', '#eab308'], ['Root Cause', '#22c55e']].map(([l, c]) => <span key={l} className="row" style={{ gap: 4, fontSize: 9.5, color: 'var(--text-2)' }}><span style={{ width: 9, height: 9, borderRadius: 2, background: c }} />{l}</span>)}</div></div>
          <CauseTree tree={DB.causeTree} />
          <Btn variant="ghost" icon="signature" size="sm" style={{ marginTop: 10 }} onClick={() => window.toast('Edit cause tree', 'info')}>Edit cause tree analysis</Btn>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Root cause(s) identified</div>{roots.map((r) => <div key={r} className="row" style={{ gap: 8, padding: '4px 0', fontSize: 12 }}><Icon name="check" size={14} style={{ color: 'var(--ok)', flex: 'none' }} />{r}</div>)}</div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>RCA details</div>{[['RCA Method', 'Cause Tree Analysis'], ['Analysis Date', '14 May 2024'], ['Facilitated By', 'Sultan Al-Qahtani'], ['Reviewed By', 'Yusuf Rahman'], ['Approved By', '—']].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5 }}><span className="faint">{k}</span><b style={{ textAlign: 'right' }}>{v}</b></div>)}</div>
        </div>
        <div className="card card-pad">
          <div className="eyebrow" style={{ marginBottom: 10 }}>Investigation timeline</div>
          {tl.map(([e, d, tone], i) => <div key={i} className="row" style={{ gap: 9, alignItems: 'flex-start', paddingBottom: 12 }}>
            <span style={{ width: 11, height: 11, borderRadius: '50%', flex: 'none', marginTop: 2, background: tone === 'ok' ? 'var(--ok)' : tone === 'warn' ? 'var(--warn)' : '#cbd5e1' }} />
            <div style={{ flex: 1, lineHeight: 1.2 }}><div style={{ fontSize: 11.5, fontWeight: 650 }}>{e}</div><div className="faint" style={{ fontSize: 10 }}>{d}</div></div>
          </div>)}
        </div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '2.1fr 1fr', gap: 14 }}>
        <div className="card card-pad">
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 10 }}><div className="eyebrow" style={{ margin: 0 }}>Corrective &amp; preventive actions (CAPA)</div><Btn variant="primary" icon="plus" size="sm" onClick={() => openActionForm()}>Add action</Btn></div>
          <table className="tbl"><thead><tr><th>Action</th><th>Description</th><th>Type</th><th>Root cause</th><th>Responsible</th><th>Due</th><th>Status</th><th>Priority</th></tr></thead>
            <tbody>{acts.map((a) => <tr key={a.id}><td className="mono cell-strong" style={{ fontSize: 11 }}>{a.id}</td><td style={{ fontSize: 12 }}>{a.desc}</td><td><span className="tag">{a.type}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{a.cause}</td><td><Avatar id={a.who} size="sm" /></td><td className="faint" style={{ fontSize: 11.5 }}>{a.due}</td><td><Badge kind={sKind(a.status)} dot={a.status !== 'Closed'}>{a.status}</Badge></td><td><Badge kind={pKind(a.priority)}>{a.priority}</Badge></td></tr>)}</tbody>
          </table>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Action status overview</div><div className="row" style={{ gap: 10, alignItems: 'center' }}><DashDonut data={actionStatus.filter((a) => a.v)} size={100} /><DashLegend data={actionStatus} /></div></div>
          <div className="card card-pad row" style={{ justifyContent: 'space-between' }}><div><div className="eyebrow" style={{ color: 'var(--bad)' }}>Overdue actions</div><div style={{ fontSize: 30, fontWeight: 800, color: 'var(--bad)' }}>1</div></div><Btn variant="ghost" size="sm" onClick={() => onNav('actiontracking')}>View overdue</Btn></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Lessons learned (draft)</div><ol style={{ margin: 0, paddingLeft: 18, fontSize: 11.5, lineHeight: 1.6, color: 'var(--text-2)' }}><li>Always use tag line for load control during lifting.</li><li>Establish and maintain exclusion zone.</li><li>Ensure all personnel are trained and competent.</li><li>Supervisor must verify pre-lift conditions.</li></ol></div>
        </div>
      </div>
      <div className="card card-pad" style={{ marginTop: 14 }}>
        <div className="eyebrow" style={{ marginBottom: 12 }}>Investigation approval &amp; closure</div>
        <div className="row" style={{ gap: 20, flexWrap: 'wrap', alignItems: 'flex-end' }}>
          <div><div className="faint" style={{ fontSize: 11 }}>Report Completed By</div><b style={{ fontSize: 12.5 }}>Sultan Al-Qahtani · 14 May 2024</b></div>
          <div><div className="faint" style={{ fontSize: 11 }}>Reviewed &amp; Approved By (QHSE Manager)</div><b style={{ fontSize: 12.5 }}>Yusuf Rahman · —</b></div>
          <input placeholder="Enter closure remarks…" style={{ flex: 1, minWidth: 200, padding: '9px 12px', borderRadius: 9, border: '1px solid var(--border)', fontFamily: 'inherit', fontSize: 12.5, background: 'var(--surface)' }} />
          <Btn variant="primary" icon="check" onClick={() => window.toast('Investigation approved & closed', 'ok')}>Approve &amp; close investigation</Btn>
        </div>
      </div>
    </div>
  );
}
function InvestigationSection({ onNav, onOpen, view }) {
  const [tab, setTab] = useState(view || 'list');
  const invs = DB.investigations;
  const cnt = (s) => invs.filter((i) => i.status === s).length;
  const kpis = [['Total Investigations', invs.length, 'search', 'info'], ['In Progress', cnt('In Progress'), 'refresh', 'warn'], ['Under Review', cnt('Review'), 'eye', 'ai'], ['Completed', cnt('Closed'), 'check', 'ok'], ['Overdue', 1, 'clock', 'bad'], ['Avg Days', 11, 'history', 'info']];
  const byStatus = [{ l: 'In Progress', v: cnt('In Progress'), c: 'var(--warn)' }, { l: 'Under Review', v: cnt('Review'), c: '#2563eb' }, { l: 'Closed', v: cnt('Closed'), c: 'var(--ok)' }];
  const rcaCats = [{ l: 'Lifting controls', v: 6, c: '#ef4444' }, { l: 'Competency / training', v: 5, c: '#f59e0b' }, { l: 'Supervision', v: 4, c: '#f97316' }, { l: 'Procedures', v: 3, c: '#22c55e' }, { l: 'Equipment', v: 2, c: '#2563eb' }];
  const open = (inv) => { const i = DB.incidents.find((x) => x.id === inv.inc); if (i) onOpen('investigation', i); };
  return (
    <div className="page page-wide rise">
      <PageHead title="Investigation" sub="Incident investigations · RCA (Cause Tree) · CAPA — across all incidents"><DateFilter /></PageHead>
      <Tabs tabs={[['list', 'Investigations'], ['dashboard', 'Dashboard']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — investigation intelligence" clause="ISO 45001 §10.2">Across {invs.length} open investigations, AI clusters root causes — <b>lifting-controls</b> recurs in 3 cases (systemic). It auto-drafts cause trees & CAPAs, flags INV-26-0123 as overdue‑risk, and recommends a cross-project lifting safety stand‑down.</AINote></div>
      {tab === 'dashboard' && (<React.Fragment>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6,1fr)', gap: 12, marginBottom: 14 }}>{kpis.map(([k, v, ic, tone]) => { const t = DASH_TONE[tone]; return (
          <div key={k} className="card" style={{ padding: '13px 14px' }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 36, height: 36, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={18} /></span><div><div style={{ fontSize: 23, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>
        ); })}</div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.4fr 1.2fr', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Investigations by status</div><div className="row" style={{ gap: 10, alignItems: 'center' }}><DashDonut data={byStatus} size={108} /><DashLegend data={byStatus} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Root-cause categories (aggregate)</div><DashHBars data={rcaCats} /></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Recent investigations</div>{invs.slice(0, 5).map((iv) => <div key={iv.no} className="row clickable" style={{ justifyContent: 'space-between', padding: '7px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5 }} onClick={() => open(iv)}><span className="mono" style={{ color: 'var(--primary-700)' }}>{iv.no}</span><span className="faint" style={{ flex: 1, margin: '0 8px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{iv.inc}</span><Badge kind={sKind(iv.status)}>{iv.status}</Badge></div>)}</div>
        </div>
      </React.Fragment>)}
      {tab === 'list' && (
        <div className="card">
          <div className="card-head"><Icon name="search" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Investigations register</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>{invs.length} investigations · click to open</span></div>
          <table className="tbl"><thead><tr><th>Investigation No.</th><th>Incident Ref.</th><th>Title</th><th>Lead</th><th>Team</th><th>Root causes</th><th>Target</th><th>Status</th></tr></thead>
            <tbody>{invs.map((iv) => <tr key={iv.no} className="clickable" onClick={() => open(iv)}><td className="mono cell-strong" style={{ fontSize: 11 }}>{iv.no}</td><td className="mono" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{iv.inc}</td><td style={{ fontSize: 12, maxWidth: 240 }}>{iv.title}</td><td><Avatar id={iv.lead} size="sm" /></td><td className="faint">{iv.team}</td><td><b>{iv.roots}</b></td><td className="faint" style={{ fontSize: 11.5 }}>{iv.target}</td><td><Badge kind={sKind(iv.status)} dot={iv.status !== 'Closed'}>{iv.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}
function ActionTrackingSection({ onNav, onOpen, view }) {
  const [tab, setTab] = useState(view || 'list');
  const acts = DB.capaActions;
  const kpis = [['Total Actions', 18, 'receipt', 'info'], ['Open', 7, 'flag', 'bad'], ['In Progress', 6, 'refresh', 'warn'], ['Pending Verification', 3, 'eye', 'info'], ['Closed', 2, 'check', 'ok'], ['Overdue', 2, 'clock', 'bad'], ['Avg Days Overdue', 8.6, 'history', 'info']];
  const byStatus = [{ l: 'Open', v: 7, c: 'var(--bad)' }, { l: 'In Progress', v: 6, c: 'var(--warn)' }, { l: 'Pending Verification', v: 3, c: '#2563eb' }, { l: 'Closed', v: 2, c: 'var(--ok)' }];
  const byPriority = [{ l: 'High', v: 6, c: 'var(--bad)' }, { l: 'Medium', v: 8, c: 'var(--warn)' }, { l: 'Low', v: 4, c: 'var(--ok)' }];
  const aging = [{ l: '0–7 days', v: 5, c: 'var(--ok)' }, { l: '8–30 days', v: 6, c: '#eab308' }, { l: '31–60 days', v: 3, c: '#f97316' }, { l: '> 60 days', v: 1, c: 'var(--bad)' }];
  const openInc = (a) => { const i = DB.incidents.find((x) => x.id === a.inc); if (i) onOpen('incident', i); };
  return (
    <div className="page page-wide rise">
      <PageHead title="Action Tracking" sub="Corrective & preventive actions across all incidents"><DateFilter /><Btn icon="download" size="sm" onClick={() => window.toast('Actions exported (XLSX)', 'info')}>Export</Btn></PageHead>
      <Tabs tabs={[['list', 'Actions register'], ['dashboard', 'Dashboard']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — action-risk forecast" clause="AIX">AI predicts <b>CAPA-001</b> (tag-line procedure) will slip again without escalation — owner overloaded with 4 open high-priority actions. 2 overdue, 5 due in 7 days. Recommended: reassign CAPA-007 and fast-track CAPA-004 (90% done) to verification.</AINote></div>
      {tab === 'dashboard' && (<React.Fragment>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 10, marginBottom: 14 }}>{kpis.map(([k, v, ic, tone]) => { const t = DASH_TONE[tone]; return (
          <div key={k} className="card" style={{ padding: '12px 12px' }}><span style={{ width: 34, height: 34, borderRadius: 10, background: t[0], color: t[1], display: 'grid', placeItems: 'center' }}><Icon name={ic} size={17} /></span><div style={{ fontSize: 24, fontWeight: 800, marginTop: 7 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5 }}>{k}</div></div>
        ); })}</div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 14, marginBottom: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Actions by status</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={byStatus} size={100} /><DashLegend data={byStatus} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Actions by priority</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={byPriority} size={100} /><DashLegend data={byPriority} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ color: 'var(--bad)', marginBottom: 8 }}>Overdue actions · 2</div>{[['CAPA-001', 'Use tag line for all lifting operations.', '2 days'], ['CAPA-010', 'Update risk assessment procedure.', '1 day']].map(([id, d, days]) => <div key={id} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5 }}><span className="mono" style={{ color: 'var(--primary-700)' }}>{id}</span><span className="faint" style={{ flex: 1, margin: '0 8px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{d}</span><b style={{ color: 'var(--bad)' }}>{days}</b></div>)}</div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Actions due soon · 5</div>{[['CAPA-002', 'Establish and enforce exclusion zone.', '5 May'], ['CAPA-003', 'Provide rigger & lifting safety training.', '5 May'], ['CAPA-004', 'Strengthen field supervision.', '5 May']].map(([id, d, days]) => <div key={id} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', borderBottom: '1px solid var(--border)', fontSize: 11.5 }}><span className="mono" style={{ color: 'var(--primary-700)' }}>{id}</span><span className="faint" style={{ flex: 1, margin: '0 8px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{d}</span><b className="faint">{days}</b></div>)}</div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1.4fr', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Actions aging (open &amp; in progress)</div><DashHBars data={aging} /></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Action performance</div><div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 12 }}>{[['On-time completion', '88.9%', '↑ 12%', 'var(--ok)'], ['Avg closure time', '21 days', '↓ 5 days', 'var(--ok)'], ['Reopened actions', '1', '5.6%', 'var(--warn)'], ['Effectiveness', '94.4%', '↑ 8%', 'var(--ok)']].map(([k, v, d, col]) => <div key={k}><div className="eyebrow" style={{ fontSize: 8.5 }}>{k}</div><div style={{ fontSize: 22, fontWeight: 800, marginTop: 3 }}>{v}</div><div style={{ fontSize: 10.5, color: col, fontWeight: 600 }}>{d}</div></div>)}</div></div>
        </div>
      </React.Fragment>)}
      {tab === 'list' && (
        <div className="card card-pad">
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Actions register · all incidents</div><span className="faint" style={{ fontSize: 11 }}>Showing 1–8 of 18 · click row to open incident</span></div>
          <table className="tbl"><thead><tr><th>Action</th><th>Incident</th><th>Description</th><th>Type</th><th>Root cause</th><th>Owner</th><th>Priority</th><th>Due</th><th>Status</th><th>Days</th><th>Progress</th></tr></thead>
            <tbody>{acts.map((a) => <tr key={a.id} className="clickable" onClick={() => openInc(a)}><td className="mono cell-strong" style={{ fontSize: 11 }}>{a.id}</td><td className="mono" style={{ fontSize: 11, color: 'var(--primary-700)' }}>{a.inc}</td><td style={{ fontSize: 12, maxWidth: 200 }}>{a.desc}</td><td><span className="tag">{a.type}</span></td><td className="faint" style={{ fontSize: 11 }}>{a.cause}</td><td><Avatar id={a.who} size="sm" /></td><td><Badge kind={pKind(a.priority)}>{a.priority}</Badge></td><td className="faint" style={{ fontSize: 11.5 }}>{a.due}</td><td><Badge kind={sKind(a.status)} dot={a.status !== 'Closed'}>{a.status}</Badge></td><td style={{ fontSize: 11, color: a.overdue ? 'var(--bad)' : 'var(--text-2)', fontWeight: 600 }}>{a.overdue ? `${a.overdue}d over` : a.left ? `${a.left}d left` : '—'}</td><td style={{ width: 88 }}><div className="row" style={{ gap: 6 }}><div style={{ flex: 1 }}><Bar pct={a.progress} color={a.progress === 100 ? 'var(--ok)' : 'var(--primary-600)'} /></div><span className="mono faint" style={{ fontSize: 10 }}>{a.progress}%</span></div></td><td><RowActions onView={() => openInc(a)} onEdit={() => openActionForm(a)} onDelete={() => dbRemove('capaActions', 'id', a.id)} /></td></tr>)}</tbody>
          </table>
        </div>
      )}
    </div>
  );
}
function LessonsSection({ onNav, onOpen, view }) {
  const [stab, setStab] = useState(view || 'list');
  const [sel, setSel] = useState(DB.lessonsList[0]);
  const kpis = [['Total Lessons', 24, 'documents', 'info'], ['Published', 18, 'check', 'ok'], ['Draft', 4, 'signature', 'warn'], ['Under Review', 2, 'eye', 'ai'], ['Applied', 142, 'refresh', 'info'], ['Effectiveness', '92%', 'trend', 'ok']];
  const applic = [['Main Plant - Area 1', 5], ['Main Plant - Area 2', 4], ['Offshore Platform A', 3], ['Workshop', 2], ['Project Alpha', 4]];
  const channels = [['Email', 64, 'chat'], ['Safety Alert', 28, 'bell'], ['Toolbox Talk', 32, 'users'], ['Notice Board', 18, 'grid']];
  const byCat = [{ l: 'Lifting Operations', v: 8, c: '#ef4444' }, { l: 'Work Planning', v: 6, c: '#f59e0b' }, { l: 'Communication', v: 4, c: '#f97316' }, { l: 'Equipment', v: 3, c: '#22c55e' }, { l: 'PPE', v: 3, c: '#2563eb' }];
  const openInc = (l) => { const i = DB.incidents.find((x) => x.id === l.ref); if (i) onOpen('incident', i); };
  return (
    <div className="page page-wide rise">
      <PageHead title="Lessons Learned" sub="Capture, share and apply lessons to prevent recurrence — across all incidents"><DateFilter /></PageHead>
      <Tabs tabs={[['list', 'Lessons register'], ['dashboard', 'Dashboard']]} tab={stab} setTab={setStab} />
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6,1fr)', gap: 12, marginBottom: 14 }}>{kpis.map(([k, v, ic, tone]) => { const t = DASH_TONE[tone]; return (
        <div key={k} className="card" style={{ padding: '13px 14px' }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 38, height: 38, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={19} /></span><div><div style={{ fontSize: 24, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>
      ); })}</div>
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — lessons engine" clause="ISO 45001 §10.2">AI auto-drafts lessons from every closed investigation and propagates them across sites (142 applications). It flags 2 at-height crews that haven't acknowledged LL-2024-024 and recommends a Toolbox Talk before the next P-204 lift.</AINote></div>
      {stab === 'dashboard' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1.1fr 1.4fr', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Lessons by category</div><DashHBars data={byCat} /><div className="eyebrow" style={{ margin: '16px 0 8px' }}>Applied at</div>{applic.map(([l, v]) => <div key={l} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5 }}><span>{l}</span><b>{v}</b></div>)}</div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Distribution &amp; effectiveness</div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 10, marginBottom: 14 }}>{channels.map(([l, v, ic]) => <div key={l} style={{ textAlign: 'center' }}><Icon name={ic} size={18} style={{ color: 'var(--primary-600)' }} /><div style={{ fontSize: 18, fontWeight: 800, marginTop: 2 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8 }}>{l}</div></div>)}</div>
            <div className="row" style={{ gap: 14, alignItems: 'center' }}><div><div style={{ fontSize: 26, fontWeight: 800, color: 'var(--ok)' }}>92%</div><div className="faint" style={{ fontSize: 10.5 }}>Positive feedback</div></div><div style={{ flex: 1 }}><Bar pct={92} color="var(--ok)" /></div></div>
            <div className="row" style={{ gap: 16, marginTop: 10 }}>{[['Positive', 55, 'var(--ok)'], ['Neutral', 4, 'var(--warn)'], ['Negative', 1, 'var(--bad)']].map(([l, v, c]) => <span key={l} style={{ fontSize: 11.5 }}><b style={{ color: c }}>{v}</b> {l}</span>)}</div>
          </div>
        </div>
      )}
      {stab === 'list' && (
        <div className="split">
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 8 }}>Lessons register · click to view, incident ref to open incident</div>
            <table className="tbl"><thead><tr><th>Lesson ID</th><th>Title</th><th>Incident ref.</th><th>Category</th><th>Location</th><th>Published</th><th>Status</th><th>Applied</th></tr></thead>
              <tbody>{DB.lessonsList.map((l) => <tr key={l.id} className="clickable" style={{ background: sel.id === l.id ? 'var(--ai-bg)' : undefined }} onClick={() => setSel(l)}><td className="mono cell-strong" style={{ fontSize: 11 }}>{l.id}</td><td style={{ fontSize: 12, maxWidth: 220 }}>{l.title}</td><td className="mono" style={{ fontSize: 11, color: 'var(--primary-700)' }} onClick={(e) => { e.stopPropagation(); openInc(l); }}>{l.ref}</td><td><span className="tag">{l.cat}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{l.loc}</td><td className="faint" style={{ fontSize: 11.5 }}>{l.date}</td><td><Badge kind={sKind(l.status)}>{l.status}</Badge></td><td><b>{l.applied || '—'}</b></td><td><RowActions onEdit={() => window.toast('Edit lesson', 'info')} onDelete={() => dbRemove('lessonsList', 'id', l.id)} /></td></tr>)}</tbody>
            </table>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <div className="card card-pad"><div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Lesson details</div><Badge kind={sKind(sel.status)}>{sel.status}</Badge></div>{[['Lesson ID', sel.id], ['Title', sel.title], ['Incident Reference', sel.ref], ['Category', sel.cat], ['Location', sel.loc], ['Published Date', sel.date], ['Applied', `${sel.applied} times`]].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5, gap: 10 }}><span className="faint">{k}</span><b style={{ textAlign: 'right' }}>{v}</b></div>)}<Btn variant="ghost" icon="ext" size="sm" style={{ marginTop: 8, width: '100%' }} onClick={() => openInc(sel)}>Open incident {sel.ref}</Btn></div>
            <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Lesson content</div><div style={{ fontSize: 11.5, lineHeight: 1.5 }}><b style={{ color: 'var(--bad)' }}>Root cause</b><div className="faint" style={{ marginBottom: 6 }}>No tag line used and operator was in line of fire.</div><b style={{ color: 'var(--ok)' }}>Lesson</b><div className="faint">Always use tag lines to control load swing and keep personnel out of the line of fire.</div></div></div>
          </div>
        </div>
      )}
    </div>
  );
}
/* Pictorial safety-alert poster — hazard scene + do/don't pictograms */
function AlertPoster({ sel }) {
  return (
    <div style={{ borderRadius: 12, overflow: 'hidden', border: '1px solid var(--border)', background: '#fff' }}>
      {/* red header band */}
      <div style={{ background: 'linear-gradient(120deg,#b91c1c,#ef4444)', color: '#fff', padding: '12px 14px', display: 'flex', alignItems: 'center', gap: 10 }}>
        <span style={{ width: 38, height: 38, borderRadius: 9, background: 'rgba(255,255,255,.18)', display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name="alert" size={22} /></span>
        <div><div style={{ fontSize: 10, fontWeight: 800, letterSpacing: 1, opacity: .9 }}>SAFETY ALERT · {sel.type}</div><div style={{ fontSize: 14, fontWeight: 800, lineHeight: 1.15 }}>{sel.title}</div></div>
      </div>
      {/* hazard scene */}
      <div style={{ background: 'linear-gradient(180deg,#eef4fe,#fff)', padding: '10px 12px' }}>
        <svg viewBox="0 0 320 150" style={{ width: '100%', height: 'auto', display: 'block' }}>
          {/* ground */}
          <rect x="0" y="128" width="320" height="22" fill="#e7ebf1" />
          {/* crane mast + jib */}
          <rect x="36" y="22" width="9" height="106" fill="#f59e0b" stroke="#b45309" /><rect x="36" y="22" width="150" height="9" fill="#f59e0b" stroke="#b45309" />
          {/* hoist line + hook */}
          <line x1="150" y1="31" x2="150" y2="60" stroke="#64748b" strokeWidth="2" />
          {/* swinging pipe (motion arc) */}
          <path d="M150 62 q34 6 56 26" fill="none" stroke="#cbd5e1" strokeWidth="2" strokeDasharray="4 4" />
          <g transform="rotate(24 150 64)"><rect x="120" y="60" width="86" height="13" rx="6" fill="#94a3b8" stroke="#475569" /></g>
          {/* exclusion-zone person in line of fire */}
          <g transform="translate(228 96)"><circle cx="0" cy="-14" r="8" fill="#1f2937" /><rect x="-6" y="-6" width="12" height="24" rx="5" fill="#2563eb" /><rect x="-9" y="18" width="6" height="14" fill="#1f2937" /><rect x="3" y="18" width="6" height="14" fill="#1f2937" /></g>
          {/* impact burst */}
          <g transform="translate(212 78)"><path d="M0 0 l6 -7 2 9 8 -4 -4 8 9 2 -9 3 4 8 -8 -4 -2 9 -6 -7 -6 7 -2 -9 -8 4 4 -8 -9 -2 9 -3 -4 -8 8 4 2 -9z" fill="#ef4444" opacity=".9" /></g>
          {/* warning triangle */}
          <g transform="translate(120 104)"><path d="M0 -16 L14 8 L-14 8 Z" fill="#fde047" stroke="#b45309" strokeWidth="2" strokeLinejoin="round" /><rect x="-1.6" y="-8" width="3.2" height="9" fill="#1f2937" /><circle cx="0" cy="4" r="1.8" fill="#1f2937" /></g>
        </svg>
      </div>
      {/* what / cause */}
      <div style={{ padding: '10px 14px', borderTop: '1px solid var(--border)' }}>
        <div style={{ fontSize: 11.5, lineHeight: 1.55 }}><b style={{ color: 'var(--bad)' }}>What happened:</b> <span className="faint">A suspended pipe load swung into the line of fire and struck the rigger — no tag line and no exclusion zone in place.</span></div>
      </div>
      {/* do / don't pictograms */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 0, borderTop: '1px solid var(--border)' }}>
        <div style={{ padding: '10px 14px', borderRight: '1px solid var(--border)', background: 'var(--ok-bg)' }}>
          <div className="row" style={{ gap: 6, color: '#0f7a4f', fontWeight: 800, fontSize: 11, marginBottom: 6 }}><Icon name="check" size={14} />DO</div>
          {['Use tag lines on every load', 'Set & enforce an exclusion zone', 'Keep clear of the line of fire', 'Critical-lift supervision present'].map((d) => <div key={d} className="row" style={{ gap: 6, padding: '3px 0', fontSize: 11 }}><Icon name="check" size={12} style={{ color: 'var(--ok)', flex: 'none' }} />{d}</div>)}
        </div>
        <div style={{ padding: '10px 14px', background: 'var(--bad-bg)' }}>
          <div className="row" style={{ gap: 6, color: '#c0362d', fontWeight: 800, fontSize: 11, marginBottom: 6 }}><Icon name="x" size={14} />DON'T</div>
          {['Guide loads by hand', 'Stand under / beside a suspended load', 'Lift without a rigging plan', 'Skip the pre-lift toolbox talk'].map((d) => <div key={d} className="row" style={{ gap: 6, padding: '3px 0', fontSize: 11 }}><Icon name="x" size={12} style={{ color: 'var(--bad)', flex: 'none' }} />{d}</div>)}
        </div>
      </div>
      {/* footer */}
      <div className="row" style={{ gap: 10, padding: '9px 14px', borderTop: '1px solid var(--border)', fontSize: 10.5, color: 'var(--text-3)', flexWrap: 'wrap' }}>
        <span className="row" style={{ gap: 5 }}><Icon name="users" size={12} />1,248 recipients</span>
        <span className="row" style={{ gap: 5 }}><Icon name="check" size={12} style={{ color: 'var(--ok)' }} />87% acknowledged</span>
        <span className="spacer" /><span>EN · العربية</span>
      </div>
    </div>
  );
}
function SafetyAlertsSection({ onNav, onOpen, view }) {
  const [stab, setStab] = useState(view || 'list');
  const [sel, setSel] = useState(DB.safetyAlerts[0]);
  const kpis = [['Total Safety Alerts', 32, 'documents', 'info'], ['Published', 24, 'check', 'ok'], ['Draft', 4, 'signature', 'warn'], ['Under Review', 2, 'eye', 'ai'], ['Total Distribution', '1,248', 'chat', 'info'], ['Acknowledgment', '87%', 'check', 'ok']];
  const channels = [{ l: 'Email', v: 562, c: '#2563eb' }, { l: 'SMS', v: 312, c: '#22c55e' }, { l: 'Intranet', v: 250, c: '#f59e0b' }, { l: 'Notice Board', v: 124, c: '#a855f7' }];
  const topics = [['Lifting Operations', 10, 31], ['Work at Height', 7, 22], ['Vehicle Safety', 5, 16], ['Machinery & Tools', 4, 12], ['Electrical Safety', 3, 9]];
  const openInc = (a) => { const i = DB.incidents.find((x) => x.id === a.ref); if (i) onOpen('incident', i); };
  return (
    <div className="page page-wide rise">
      <PageHead title="Safety Alert" sub="Create, publish and communicate safety alerts — across all incidents"><DateFilter /><Btn variant="primary" icon="plus" onClick={() => openAlertForm()}>Create safety alert</Btn></PageHead>
      <Tabs tabs={[['list', 'Alerts register'], ['dashboard', 'Dashboard']]} tab={stab} setTab={setStab} />
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(6,1fr)', gap: 12, marginBottom: 14 }}>{kpis.map(([k, v, ic, tone]) => { const t = DASH_TONE[tone]; return (
        <div key={k} className="card" style={{ padding: '13px 14px' }}><div className="row" style={{ gap: 10, alignItems: 'center' }}><span style={{ width: 38, height: 38, borderRadius: 11, background: t[0], color: t[1], display: 'grid', placeItems: 'center', flex: 'none' }}><Icon name={ic} size={19} /></span><div><div style={{ fontSize: 23, fontWeight: 800, lineHeight: 1 }}>{v}</div><div className="eyebrow" style={{ fontSize: 8.5, marginTop: 2 }}>{k}</div></div></div></div>
      ); })}</div>
      <div style={{ marginBottom: 14 }}><AINote title="Sentinel — alert drafting & reach" clause="AIX">AI drafts safety alerts from incidents (EN + AR) and routes them across Email, SMS, Intranet and Notice Board — 1,248 recipients, 87% acknowledged. It auto-escalates the 14 overdue acknowledgements and recommends a re-alert for 2 night-shift crews.</AINote></div>
      {stab === 'dashboard' && (
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Distribution by channel</div><div className="row" style={{ gap: 8, alignItems: 'center' }}><DashDonut data={channels} size={108} /><DashLegend data={channels} /></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Acknowledgment overview</div><div className="row" style={{ gap: 12, alignItems: 'center' }}><Ring value={87} size={96} stroke={10} color="var(--ok)"><div style={{ fontSize: 18, fontWeight: 800 }}>87%</div></Ring><div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 6 }}>{[['Acknowledged', '1,086', 'var(--ok)'], ['Pending', '162', 'var(--warn)'], ['Overdue', '14', 'var(--bad)']].map(([l, v, c]) => <div key={l} className="row" style={{ gap: 6, fontSize: 11 }}><span style={{ width: 8, height: 8, borderRadius: 2, background: c }} /><span style={{ flex: 1, color: 'var(--text-2)' }}>{l}</span><b>{v}</b></div>)}</div></div></div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 6 }}>Most common topics</div>{topics.map(([l, v, p], i) => <div key={l} className="row" style={{ justifyContent: 'space-between', padding: '6px 0', fontSize: 11.5 }}><span>{i + 1}. {l}</span><b>{v} <span className="faint" style={{ fontWeight: 400 }}>({p}%)</span></b></div>)}</div>
        </div>
      )}
      {stab === 'list' && (
        <div className="split">
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 8 }}>Safety alert register · click to view, incident ref to open incident</div>
            <table className="tbl"><thead><tr><th>Alert ID</th><th>Title</th><th>Type</th><th>Incident ref.</th><th>Status</th><th>Published</th></tr></thead>
              <tbody>{DB.safetyAlerts.map((a) => <tr key={a.id} className="clickable" style={{ background: sel.id === a.id ? 'var(--ai-bg)' : undefined }} onClick={() => setSel(a)}><td className="mono cell-strong" style={{ fontSize: 11 }}>{a.id}</td><td style={{ fontSize: 12 }}>{a.title}</td><td><Badge kind={a.type === 'ENV' ? 'ok' : 'info'}>{a.type}</Badge></td><td className="mono" style={{ fontSize: 11, color: 'var(--primary-700)' }} onClick={(e) => { e.stopPropagation(); openInc(a); }}>{a.ref}</td><td><Badge kind={sKind(a.status)}>{a.status}</Badge></td><td className="faint" style={{ fontSize: 11.5 }}>{a.date}</td><td><RowActions onEdit={() => openAlertForm(a)} onDelete={() => dbRemove('safetyAlerts', 'id', a.id)} /></td></tr>)}</tbody>
            </table>
          </div>
          <div className="card card-pad">
            <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Safety alert details</div><Badge kind={sKind(sel.status)}>{sel.status}</Badge></div>
            <div style={{ fontSize: 15, fontWeight: 750, marginBottom: 8 }}>{sel.title}</div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '6px 12px' }}>{[['Alert ID', sel.id], ['Incident Ref.', sel.ref], ['Type', sel.type], ['Location', 'Main Plant - Area 1'], ['Published', sel.date], ['Author', 'Sultan Al-Qahtani'], ['Language', 'English, Arabic'], ['Channels', 'Email · SMS · Intranet']].map(([k, v]) => <div key={k}><div className="faint" style={{ fontSize: 10.5 }}>{k}</div><b style={{ fontSize: 11.5 }}>{v}</b></div>)}</div>
            <div style={{ marginTop: 12 }}><AlertPoster sel={sel} /></div>
            <Btn variant="ghost" icon="ext" size="sm" style={{ marginTop: 10 }} onClick={() => openInc(sel)}>Open incident {sel.ref}</Btn>
          </div>
        </div>
      )}
    </div>
  );
}
/* ===================== SAFETY OBSERVATION ========================= */
function obsKind(s) { return s === 'Closed' ? 'ok' : s === 'Open' ? 'bad' : s === 'Pending Verification' ? 'info' : 'warn'; }
function SafetyObsModule({ onNav }) {
  const [tab, setTab] = useState('register');
  const obs = DB.safetyObs;
  const [sel, setSel] = useState(obs[0]);
  const cnt = (s) => obs.filter((o) => o.status === s).length;
  const overdue = obs.filter((o) => o.due < DB.TODAY && o.status !== 'Closed').length;
  const kpis = [['Total observations', obs.length, 'flag', 'info'], ['Open', cnt('Open'), 'alert', 'bad'], ['In progress', cnt('In Progress'), 'refresh', 'warn'], ['Pending verification', cnt('Pending Verification'), 'eye', 'info'], ['Closed', cnt('Closed'), 'check', 'ok'], ['Overdue', overdue, 'clock', 'bad']];
  const byCat = (() => { const m = {}; obs.forEach((o) => { m[o.cat] = (m[o.cat] || 0) + 1; }); const cols = ['#ef4444', '#f59e0b', '#22c55e', '#2563eb', '#7a5bff', '#0e7490']; return Object.entries(m).map(([l, v], i) => ({ l, v, c: cols[i % cols.length] })); })();
  const byRisk = ['High', 'Medium', 'Low'].map((r, i) => ({ l: r, v: obs.filter((o) => o.risk === r).length, c: ['#ef4444', '#f59e0b', '#22c55e'][i] }));
  const byStatus = ['Open', 'In Progress', 'Pending Verification', 'Closed'].map((s, i) => ({ l: s, v: cnt(s), c: ['#ef4444', '#f59e0b', '#2563eb', '#22c55e'][i] }));
  const ck = DB.obsChecklist; const ckTotal = ck.sections.reduce((a, s) => a + s.items.length, 0);
  const ckYes = ck.sections.reduce((a, s) => a + s.items.filter((i) => i[2] === true).length, 0);
  const ckNo = ck.sections.reduce((a, s) => a + s.items.filter((i) => i[2] === false).length, 0);
  const ckNa = ckTotal - ckYes - ckNo;
  return (
    <div className="page page-wide rise">
      <PageHead title="Safety Observation Reporting" sub="Capture, classify and close unsafe acts, conditions & good practices — ISO 45001"><DateFilter /><Btn variant="primary" icon="plus" onClick={() => openObsForm()}>New observation</Btn></PageHead>
      <Tabs tabs={[['register', 'Observation register'], ['dashboard', 'Dashboard'], ['checklist', 'Checklist library']]} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title="Leading-indicator trend" clause="AIX">Unsafe-condition observations are trending up on P-219 chemical works. Sentinel clusters reports into leading indicators and recommends a targeted toolbox talk before the next shift.</AINote></div>
      {tab === 'dashboard' && <ModuleDash kpis={kpis} panels={[
        { title: 'By category', node: <DashSplit data={byCat} />, w: '1fr' },
        { title: 'By risk level', node: <DashSplit data={byRisk} />, w: '1fr' },
        { title: 'By status', node: <DashSplit data={byStatus} />, w: '1fr' },
      ]} />}
      {tab === 'register' && (
        <div className="split">
          <div className="card"><div className="card-head"><Icon name="flag" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Observation register</div><span className="spacer" /><span className="faint" style={{ fontSize: 11 }}>{obs.length} observations</span></div>
            <table className="tbl"><thead><tr><th>Obs. No.</th><th>Title</th><th>Category</th><th>Location</th><th>Risk</th><th>Status</th><th>Reported by</th><th>Due</th><th></th></tr></thead>
              <tbody>{obs.map((o) => <tr key={o.id} className="clickable" style={{ background: sel.id === o.id ? 'var(--ai-bg)' : undefined }} onClick={() => setSel(o)}><td className="mono cell-strong" style={{ fontSize: 11 }}>{o.id}</td><td style={{ fontSize: 12, maxWidth: 200 }}>{o.title}</td><td><span className="tag">{o.cat}</span></td><td className="faint" style={{ fontSize: 11.5 }}>{o.loc}</td><td><Badge kind={o.risk === 'High' ? 'bad' : o.risk === 'Medium' ? 'warn' : 'ok'}>{o.risk}</Badge></td><td><Badge kind={obsKind(o.status)} dot={o.status !== 'Closed'}>{o.status}</Badge></td><td><Avatar id={o.by} size="sm" /></td><td><span style={{ fontSize: 11.5, color: o.due < DB.TODAY && o.status !== 'Closed' ? 'var(--bad)' : 'var(--text-3)', fontWeight: 600 }}>{DB.rel(o.due)}</span></td><td><RowActions onEdit={() => openObsForm(o)} onDelete={() => dbRemove('safetyObs', 'id', o.id)} /></td></tr>)}</tbody>
            </table>
          </div>
          <div className="card card-pad">
            <div className="row" style={{ justifyContent: 'space-between', marginBottom: 10 }}><div className="eyebrow" style={{ margin: 0 }}>Observation details</div><Badge kind={obsKind(sel.status)}>{sel.status}</Badge></div>
            <div style={{ fontSize: 13.5, fontWeight: 700, marginBottom: 8 }}>{sel.title}</div>
            {[['Obs. No.', sel.id], ['Category', sel.cat], ['Type', sel.type], ['Location', sel.loc], ['Risk level', sel.risk], ['Reported on', DB.fmt(sel.date)], ['Due', DB.fmt(sel.due)]].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '4px 0', fontSize: 11.5 }}><span className="faint">{k}</span><b>{v}</b></div>)}
            <div className="row" style={{ gap: 7, marginTop: 8 }}><span className="faint" style={{ fontSize: 11.5 }}>Reported by</span><Avatar id={sel.by} size="sm" /></div>
            <div style={{ marginTop: 10, border: '1px dashed var(--border-2)', borderRadius: 10, height: 92, display: 'grid', placeItems: 'center', color: 'var(--text-3)', fontSize: 11.5, background: 'var(--surface-2)' }}><div style={{ textAlign: 'center' }}><Icon name="camera" size={20} /><div style={{ marginTop: 3 }}>Site photo / evidence</div></div></div>
            <Btn variant="ghost" icon="ext" size="sm" style={{ marginTop: 10, width: '100%' }} onClick={() => window.toast('Observation opened', 'info')}>Open full observation</Btn>
          </div>
        </div>
      )}
      {tab === 'checklist' && (
        <div className="split">
          <div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">{ck.name}</div><span className="spacer" /><Badge kind="ok">{ck.status}</Badge></div>
            <div className="card-body" style={{ paddingTop: 12, paddingBottom: 4 }}>
              {ck.sections.map((s, si) => (
                <div key={si} style={{ marginBottom: 12 }}>
                  <div className="eyebrow" style={{ marginBottom: 6 }}>{si + 1}. {s.sec}</div>
                  {s.items.map((it, ii) => <div key={ii} className="row" style={{ justifyContent: 'space-between', padding: '7px 0', borderBottom: '1px solid var(--border)', fontSize: 12.5 }}><span>{si + 1}.{ii + 1} {it[0]}</span><div className="row" style={{ gap: 8 }}><span className="tag">{it[1]}</span><Badge kind={it[2] === true ? 'ok' : it[2] === false ? 'bad' : 'neutral'}>{it[2] === true ? 'Yes' : it[2] === false ? 'No' : 'N/A'}</Badge></div></div>)}
                </div>
              ))}
            </div>
          </div>
          <div className="card card-pad">
            <div className="eyebrow" style={{ marginBottom: 8 }}>Checklist statistics</div>
            {[['Total items', ckTotal], ['Yes', ckYes], ['No', ckNo], ['N/A', ckNa], ['Used in observations', ck.used]].map(([k, v]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '5px 0', fontSize: 12 }}><span className="faint">{k}</span><b>{v}</b></div>)}
            <div className="eyebrow" style={{ margin: '12px 0 6px' }}>Compliance {Math.round(ckYes / (ckYes + ckNo) * 100)}%</div>
            <Bar pct={Math.round(ckYes / (ckYes + ckNo) * 100)} color="var(--ok)" />
            <div style={{ marginTop: 14 }}><AINote title="Checklist insight" clause="AIX">Emergency-exit access is the recurring No across recent uses — Sentinel flags it as the top corrective theme for this checklist.</AINote></div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ===================== HSE INSPECTION SUITE ======================= */
function inspKind(s) { return s === 'Completed' ? 'ok' : s === 'In Progress' ? 'warn' : 'bad'; }
function HseInspectionModule({ onNav }) {
  const [tab, setTab] = useState(DB.inspTypes[0].key);
  const meta = DB.inspTypes.find((t) => t.key === tab);
  const rows = DB.hseInspections[tab];
  const [sel, setSel] = useState(rows[0]);
  useEffect(() => { setSel(DB.hseInspections[tab][0]); }, [tab]);
  const totFind = rows.reduce((a, r) => a + r.findings, 0);
  const crit = rows.reduce((a, r) => a + r.crit, 0), major = rows.reduce((a, r) => a + r.major, 0), minor = rows.reduce((a, r) => a + r.minor, 0);
  const kpis = [['Total inspections', meta.total, 'clipboard', 'info'], ['Completed', meta.completed, 'check', 'ok'], ['In progress', meta.inprog, 'refresh', 'warn'], ['Planned', meta.planned, 'calendar', 'ai'], ['Overdue', meta.overdue, 'clock', 'bad'], ['Compliance', meta.comp + '%', 'trend', meta.comp >= 80 ? 'ok' : 'warn']];
  const sev = [{ l: 'Critical', v: crit || 1, c: '#ef4444' }, { l: 'Major', v: major || 4, c: '#f59e0b' }, { l: 'Minor', v: minor || 8, c: '#22c55e' }];
  const trend = { labels: ['Dec', 'Jan', 'Feb', 'Mar', 'Apr', 'May'], series: [{ c: '#2563eb', d: [72, 74, 76, 78, 80, meta.comp] }] };
  return (
    <div className="page page-wide rise">
      <PageHead title="HSE Inspection" sub="Facility · project · permit · weekly & monthly themed inspections — checklist-driven with findings & CAPA"><DateFilter /><Btn icon="calendar" size="sm" onClick={() => window.toast('Inspection calendar', 'info')}>Calendar</Btn><Btn variant="primary" icon="plus" onClick={() => openInspectionForm()}>New inspection</Btn></PageHead>
      <Tabs tabs={DB.inspTypes.map((t) => [t.key, t.label])} tab={tab} setTab={setTab} />
      <div style={{ marginBottom: 14 }}><AINote title={`Sentinel — ${meta.label} intelligence`} clause="AIX">{meta.cadence} cadence · AI tracks compliance at <b>{meta.comp}%</b> and clusters findings — housekeeping & PPE are the recurring categories. It auto-routes open findings to CAPA and predicts the next-period compliance trajectory.</AINote></div>
      <ModuleDash kpis={kpis} panels={[
        { title: 'Findings by severity', node: <DashSplit data={sev} />, w: '1fr' },
        { title: 'Compliance trend (6 mo)', node: <DashLine trend={trend} />, w: '1.3fr' },
        { title: 'Open findings', node: <div style={{ fontSize: 12 }}>{[['Critical', crit, 'var(--bad)'], ['Major', major, 'var(--warn)'], ['Minor', minor, 'var(--ok)'], ['Total', totFind, 'var(--text)']].map(([k, v, c]) => <div key={k} className="row" style={{ justifyContent: 'space-between', padding: '8px 0', borderBottom: '1px solid var(--border)' }}><span className="faint">{k}</span><b style={{ color: c }}>{v}</b></div>)}</div>, w: '1fr' },
      ]} />
      <div className="split" style={{ marginTop: 16 }}>
        <div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">{meta.label} inspections</div></div>
          <table className="tbl"><thead><tr><th>Inspection ID</th><th>Area</th><th>Dept</th><th>Date</th><th>Inspector</th><th>Compliance</th><th>Findings</th><th>Status</th></tr></thead>
            <tbody>{rows.map((r) => <tr key={r.id} className="clickable" style={{ background: sel.id === r.id ? 'var(--ai-bg)' : undefined }} onClick={() => setSel(r)}><td className="mono cell-strong" style={{ fontSize: 10.5 }}>{r.id}</td><td className="faint" style={{ fontSize: 11.5 }}>{r.area}</td><td className="faint" style={{ fontSize: 11.5 }}>{r.dept}</td><td className="faint" style={{ fontSize: 11.5 }}>{DB.fmt(r.date)}</td><td><Avatar id={r.inspector} size="sm" /></td><td style={{ width: 96 }}><div className="row" style={{ gap: 6 }}><div style={{ width: 50 }}><Bar pct={r.comp} color={scoreColor(r.comp)} /></div><span className="mono faint" style={{ fontSize: 10.5 }}>{r.comp}%</span></div></td><td><span style={{ fontSize: 11.5 }}><b style={{ color: 'var(--bad)' }}>{r.crit}</b>·<b style={{ color: 'var(--warn)' }}>{r.major}</b>·<b style={{ color: 'var(--ok)' }}>{r.minor}</b></span></td><td><Badge kind={inspKind(r.status)} dot={r.status !== 'Completed'}>{r.status}</Badge></td></tr>)}</tbody>
          </table>
        </div>
        <div className="card card-pad">
          <div className="row" style={{ justifyContent: 'space-between', marginBottom: 8 }}><div className="eyebrow" style={{ margin: 0 }}>Checklist summary</div><Badge kind={inspKind(sel.status)}>{sel.status}</Badge></div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--primary-700)', marginBottom: 8 }}>{sel.id}</div>
          {DB.inspChecklistSections.map((s, i) => { const pct = Math.round(s[2] / s[1] * 100); return <div key={i} className="row" style={{ gap: 8, padding: '5px 0', fontSize: 11 }}><span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{s[0]}</span><div style={{ width: 44 }}><Bar pct={pct} color={scoreColor(pct)} /></div><span className="mono faint" style={{ fontSize: 10 }}>{pct}%</span></div>; })}
          <Btn variant="ghost" icon="ext" size="sm" style={{ marginTop: 10, width: '100%' }} onClick={() => window.toast('Inspection report opened', 'info')}>View / download report</Btn>
        </div>
      </div>
    </div>
  );
}

function ModuleHost({ active, onNav, onOpen }) {
  const map = {
    dashboard: <Dashboard onNav={onNav} onOpen={onOpen} />, depts: <DeptDashboards onNav={onNav} onOpen={onOpen} />, ai: <AIModule onNav={onNav} onOpen={onOpen} />,
    safetyobs: <SafetyObsModule onNav={onNav} />, hseinspect: <HseInspectionModule onNav={onNav} />,
    incidents: <IncidentsModule onNav={onNav} onOpen={onOpen} />, allincidents: <IncidentsModule onNav={onNav} onOpen={onOpen} />, quality: <QualityModule onNav={onNav} onOpen={onOpen} />,
    compliance: <ComplianceModule onNav={onNav} />,
    ptw: <PtwDashboard onNav={onNav} onOpen={onOpen} />, ptwreg: <PtwRegister onNav={onNav} onOpen={onOpen} />, myptw: <MyPtw onNav={onNav} onOpen={onOpen} />, ptwcal: <PtwCalendar onNav={onNav} onOpen={onOpen} />, ptwprocess: <PtwProcess onNav={onNav} />, lotolifecycle: <LotoLifecycle onNav={onNav} />, lotoreg: <LotoView onNav={onNav} onOpen={onOpen} />,
    competency: <CompetencyModule onNav={onNav} />, assets: <AssetsModule onNav={onNav} />,
    services: <ServicesModule onNav={onNav} />, audits: <AuditsModule />,
    risk: <RiskDash />, riskregister: <RiskDash tab="register" />, riskassess: <RiskDash tab="assess" />, riskmatrix: <RiskDash tab="matrix" />, riskhazid: <RiskDash tab="jsa" />, riskanalysis: <RiskDash tab="dashboard" />, riskeval: <RiskDash tab="matrix" />, risktreat: <RiskDash tab="treatment" />, riskbowtie: <RiskDash tab="barrier" />, riskmonitor: <RiskDash tab="heat" />,
    capa: <CapaModule />, documents: <DocsModule />, projects: <ProjectsModule onOpen={onOpen} />,
    fleet: <FleetModule />, contractors: <ContractorsModule />, emergency: <EmergencyModule />,
    field: <FieldOpsModule onNav={onNav} />, admin: <AdminModule />, hsestats: <HseStatsModule />, moc: <MocModule onOpen={onOpen} />,
    investigation: <InvestigationSection onNav={onNav} onOpen={onOpen} />, actiontracking: <ActionTrackingSection onNav={onNav} onOpen={onOpen} />, lessonslearned: <LessonsSection onNav={onNav} onOpen={onOpen} />, safetyalerts: <SafetyAlertsSection onNav={onNav} onOpen={onOpen} />,
  };
  return map[active] || <div className="page rise"><ModulePlaceholder icon="grid" title="Module" desc="Part of the AI-COS QHSE scope." points={[]} /></div>;
}
const PROJ_STAGES = ['Tender', 'Award', 'Mobilization', 'Execution', 'Demobilization', 'Closeout'];
function ProjectDetail({ rec, onBack, onNav }) {
  const p = rec;
  const pd = DB.projDocs[p.id];
  const curIdx = PROJ_STAGES.indexOf(p.stage === 'Mobilization' ? 'Mobilization' : p.stage);
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 10, marginBottom: 16 }}>
        <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: 'var(--primary-600)' }}><Icon name="workflow" size={18} /></span>
        <div><div className="row" style={{ gap: 9 }}><span className="h-page" style={{ fontSize: 20 }}>{p.id}</span><Badge kind="info">{p.stage}</Badge><Badge kind={p.risk === 'High' ? 'bad' : p.risk === 'Medium' ? 'warn' : 'ok'}>{p.risk} risk</Badge></div><div className="h-sub">{p.name} · {p.client} · {p.region}</div></div>
        <span className="spacer" /><DocActions label="project pack" id={p.id} />
      </div>
      {/* lifecycle */}
      <div className="card card-pad" style={{ marginBottom: 16 }}>
        <div className="row" style={{ justifyContent: 'space-between' }}>{PROJ_STAGES.map((s, i) => (
          <div key={s} className="row" style={{ gap: 8, flex: 1 }}>
            <span style={{ width: 26, height: 26, borderRadius: '50%', flex: 'none', display: 'grid', placeItems: 'center', background: i < curIdx ? 'var(--ok)' : i === curIdx ? 'var(--primary-600)' : '#eef1f6', color: i <= curIdx ? '#fff' : 'var(--text-3)', fontSize: 11, fontWeight: 700 }}>{i < curIdx ? <Icon name="check" size={13} /> : i + 1}</span>
            <span style={{ fontSize: 12, fontWeight: i === curIdx ? 700 : 500, color: i <= curIdx ? 'var(--text)' : 'var(--text-3)' }}>{s}</span>
            {i < PROJ_STAGES.length - 1 && <div style={{ flex: 1, height: 2, background: i < curIdx ? 'var(--ok)' : 'var(--border-2)' }} />}
          </div>
        ))}</div>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 16, alignItems: 'start' }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {pd && <React.Fragment>
            <div className="card"><div className="card-head"><Icon name="check-shield" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">HSE & quality deliverables</div></div>
              <div className="card-body" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14 }}>
                <div style={{ border: '1px solid var(--border)', borderRadius: 10, padding: 12 }}><div className="eyebrow" style={{ fontSize: 9 }}>Project HSE Plan</div><div style={{ fontSize: 13, fontWeight: 650, marginTop: 4 }}>{pd.hsePlan}</div></div>
                <div style={{ border: '1px solid var(--border)', borderRadius: 10, padding: 12 }}><div className="eyebrow" style={{ fontSize: 9 }}>Inspection & Test Plan (ITP)</div><div style={{ fontSize: 13, fontWeight: 650, marginTop: 4 }}>{pd.itp}</div></div>
              </div>
              <div className="card-body" style={{ paddingTop: 0 }}>
                <div className="eyebrow" style={{ fontSize: 9.5, marginBottom: 8 }}>Method statements</div>
                <div className="row wrap" style={{ gap: 7 }}>{pd.methods.map((m) => <span key={m} className="tag"><Icon name="documents" size={11} />{m}</span>)}</div>
              </div>
              <table className="tbl"><thead><tr><th>Client deliverable</th><th>Status</th></tr></thead><tbody>{pd.deliverables.map((d, i) => <tr key={i}><td style={{ fontSize: 12.5 }}>{d[0]}</td><td><Badge kind={/time|current|approved|submitted/i.test(d[1]) ? 'ok' : 'warn'}>{d[1]}</Badge></td></tr>)}</tbody></table>
            </div>
            <div className="card"><div className="card-head"><Icon name="trend" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Project KPIs</div></div>
              <div className="card-body">{pd.kpis.map(([k, v], i) => <div key={i} className="row" style={{ gap: 12, padding: '7px 0' }}><span style={{ width: 150, fontSize: 12.5 }}>{k}</span><div style={{ flex: 1 }}><Bar pct={v} color={scoreColor(v)} /></div><b className="mono" style={{ fontSize: 12, width: 34, textAlign: 'right' }}>{v}%</b></div>)}</div>
            </div>
          </React.Fragment>}
          {!pd && <div className="card card-pad faint" style={{ fontSize: 13 }}>This project is at {p.stage} stage — HSE plan, ITP and deliverables are prepared at award/mobilization.</div>}
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Summary</div>
            {[['Client', p.client], ['Region', p.region], ['Stage', p.stage], ['Value', p.value + ' SAR'], ['HSE score', p.hse || '—'], ['Progress', p.progress + '%']].map(([k, v], i) => <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '6px 0', fontSize: 12.5 }}><span className="faint">{k}</span><b>{v}</b></div>)}
          </div>
          <AINote title="Mobilization readiness" clause="AIX">{p.stage === 'Mobilization' ? 'AI flags 7 certifications and Hydrotest Pump HP-03 cert as blockers for full mobilization — resolve before crew deployment.' : 'No mobilization blockers detected. Maintain HSE-plan and ITP cadence.'}</AINote>
        </div>
      </div>
    </div>
  );
}
/* Print / Export actions — demo affordance (shows a toast; no backend generation) */
function DocActions({ label, id }) {
  const what = (id ? id + ' ' : '') + (label || 'document');
  return (
    <React.Fragment>
      <Btn size="sm" variant="ghost" icon="documents" onClick={() => window.toast('Opening print preview — ' + what, 'info')}>Print</Btn>
      <Btn size="sm" icon="download" onClick={() => window.toast(what + ' exported (PDF)', 'info')}>Export</Btn>
    </React.Fragment>
  );
}
function PTWDetail({ rec, onBack }) {
  const p = rec;
  const controls = PERMIT_CONTROLS[p.type] || ['Task risk assessment', 'PPE matrix'];
  const risk = PERMIT_RISK[p.type] || 40;
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 10, marginBottom: 16 }}>
        <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: 'var(--primary-600)' }}><Icon name="flag" size={18} /></span>
        <div><div className="row" style={{ gap: 9 }}><span className="h-page" style={{ fontSize: 20 }}>{p.id}</span><Badge kind={p.status === 'Active' ? 'ok' : p.status === 'Awaiting approval' ? 'warn' : 'neutral'} dot>{p.status}</Badge>{p.simops && <Badge kind="bad">SIMOPS</Badge>}</div><div className="h-sub">{p.type} · {p.sub} · {p.project}</div></div>
        <span className="spacer" /><DocActions label="permit" id={p.id} />
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 16, alignItems: 'start' }}>
        <div className="card" style={{ borderColor: 'var(--ai-line)' }}>
          <div className="card-head" style={{ background: 'linear-gradient(120deg, var(--ai-bg), #fff)' }}><span className="ai-badge-ico"><Icon name="sparkles" size={15} fill /></span><div className="h-sec" style={{ fontSize: 14 }}>AI permit review</div><span className="spacer" /><Badge kind={risk >= 70 ? 'bad' : 'warn'}>Risk {risk}/100</Badge></div>
          <div className="card-body">
            {p.simops && <div style={{ border: '1px solid var(--bad-line)', background: 'var(--bad-bg)', borderRadius: 10, padding: '10px 12px', marginBottom: 12 }}><div className="row" style={{ gap: 8 }}><Icon name="alert" size={14} style={{ color: 'var(--bad)' }} /><div style={{ fontSize: 12.5 }}><b style={{ color: 'var(--bad)' }}>SIMOPS conflict.</b> Another active permit overlaps this area/window — sequence or separate before approval.</div></div></div>}
            <div className="eyebrow" style={{ fontSize: 9.5, marginBottom: 8 }}>Required controls — AI verification</div>
            {controls.map((c, i) => (
              <div key={i} className="row" style={{ gap: 10, padding: '7px 0', borderBottom: i < controls.length - 1 ? '1px solid var(--border)' : 'none' }}>
                <Icon name={i === controls.length - 1 && p.status === 'Awaiting approval' ? 'alert' : 'check-circle'} size={16} style={{ color: i === controls.length - 1 && p.status === 'Awaiting approval' ? 'var(--warn)' : 'var(--ok)', flex: 'none' }} />
                <span style={{ fontSize: 12.5, flex: 1 }}>{c}</span>
                <Badge kind={i === controls.length - 1 && p.status === 'Awaiting approval' ? 'warn' : 'ok'}>{i === controls.length - 1 && p.status === 'Awaiting approval' ? 'Confirm' : 'In place'}</Badge>
              </div>
            ))}
            <div className="card-body" style={{ paddingLeft: 0, paddingRight: 0, paddingBottom: 0 }}><AINote title="AI recommendation" clause="PTW">{p.simops ? 'Hold approval until the SIMOPS conflict is sequenced. All other controls verified.' : 'Controls verified — safe to approve once the highlighted item is confirmed by the issuing authority.'}</AINote></div>
          </div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 10 }}>Details</div>
            {[['Type', p.type], ['Scope', p.sub], ['Project', p.project], ['Validity', p.validity], ['Risk', p.risk], ['SIMOPS', p.simops ? 'Yes' : 'No']].map(([k, v], i) => <div key={i} className="row" style={{ justifyContent: 'space-between', padding: '6px 0', fontSize: 12.5 }}><span className="faint">{k}</span><b>{v}</b></div>)}
          </div>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 8 }}>Actions</div><div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            <Btn variant="primary" icon="check" disabled={p.simops} onClick={() => window.toast(p.simops ? 'Blocked — resolve SIMOPS first' : 'Permit approved · audit-logged', p.simops ? 'warn' : 'ok')}>{p.simops ? 'Approval blocked (SIMOPS)' : 'Approve permit'}</Btn>
            <Btn variant="ghost" icon="x" onClick={() => window.toast('Returned to issuer for clarification', 'warn')}>Return for clarification</Btn>
          </div></div>
        </div>
      </div>
    </div>
  );
}
function DetailHost({ detail, onBack, onNav }) {
  if (detail.type === 'incident') return <IncidentDetail rec={detail.data} onBack={onBack} onNav={onNav} />;
  if (detail.type === 'investigation') return <InvestigationDetail rec={detail.data} onBack={onBack} onNav={onNav} />;
  if (detail.type === 'ncr') return <NCRDetail rec={detail.data} onBack={onBack} onNav={onNav} />;
  if (detail.type === 'moc') return <MocDetail rec={detail.data} onBack={onBack} />;
  if (detail.type === 'project') return <ProjectDetail rec={detail.data} onBack={onBack} onNav={onNav} />;
  if (detail.type === 'ptw') return <PTWDetail rec={detail.data} onBack={onBack} />;
  // generic project / ptw detail
  const d = detail.data;
  return (
    <div className="page page-wide rise">
      <div className="row" style={{ gap: 10, marginBottom: 16 }}><button className="icon-btn" onClick={onBack}><Icon name="chevL" size={17} /></button><span className="h-page" style={{ fontSize: 20 }}>{d.id}</span><Badge kind="info" dot>{d.stage || d.status}</Badge></div>
      <div className="card card-pad" style={{ maxWidth: 720 }}>
        <div style={{ fontSize: 15, fontWeight: 700, marginBottom: 12 }}>{d.name || d.type}</div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '10px 24px' }}>
          {Object.entries(d).filter(([k]) => !['id'].includes(k)).map(([k, v]) => (
            <div key={k} className="row" style={{ justifyContent: 'space-between', borderBottom: '1px dotted var(--border)', padding: '5px 0', fontSize: 12.5 }}><span className="faint" style={{ textTransform: 'capitalize' }}>{k}</span><b>{String(v)}</b></div>
          ))}
        </div>
      </div>
    </div>
  );
}

function QLogin({ onEnter }) {
  const [role, setRole] = useState('director');
  const auditor = role === 'auditor';
  return (
    <div style={{ height: '100vh', display: 'grid', gridTemplateColumns: '1.05fr 1fr', overflow: 'hidden' }}>
      <div style={{ position: 'relative', background: 'linear-gradient(155deg, #0c2138 0%, #102a45 45%, #163a5e 100%)', color: '#fff', padding: '52px 56px', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
        <div style={{ position: 'absolute', inset: 0, backgroundImage: 'radial-gradient(circle at 1px 1px, rgba(255,255,255,.05) 1px, transparent 0)', backgroundSize: '26px 26px', opacity: .7 }} />
        <div style={{ position: 'relative', zIndex: 1 }}><img src="app/aicos-logo-dark.png" alt="AI-COS — QHSE Excellence" style={{ height: 52, width: 'auto', display: 'block' }} /></div>
        <div style={{ position: 'relative', zIndex: 1, marginTop: 'auto' }}>
          <div className="badge" style={{ background: 'rgba(47,111,237,.18)', color: '#9ec2ff', border: '1px solid rgba(47,111,237,.35)' }}><Icon name="shield" size={12} /> ISO 9001 · ISO 14001 · ISO 45001</div>
          <h1 style={{ fontSize: 36, fontWeight: 800, letterSpacing: '-1.1px', lineHeight: 1.1, margin: '18px 0 14px', maxWidth: 470 }}>Your outsourced digital QHSE department.</h1>
          <p style={{ fontSize: 15, color: '#aebfd6', maxWidth: 450, lineHeight: 1.55 }}>One AI-powered platform for compliance, HSE, quality, asset integrity and project execution — keeping field operations continuously compliant and audit-ready.</p>
          <div className="row" style={{ gap: 26, marginTop: 30 }}>{[['AI', 'Incident → RCA → CAPA'], ['3', 'ISO systems'], ['24/7', 'Audit-ready']].map(([a, b], i) => <div key={i} style={{ borderLeft: i ? '1px solid rgba(255,255,255,.12)' : 'none', paddingLeft: i ? 20 : 0 }}><div style={{ fontSize: 20, fontWeight: 800 }}>{a}</div><div style={{ fontSize: 12, color: '#8fa6c4' }}>{b}</div></div>)}</div>
        </div>
        <div style={{ position: 'relative', zIndex: 1, marginTop: 34, fontSize: 12, color: '#6f87a6' }}>ClearLoft · QHSE & Operational Excellence ERP</div>
      </div>
      <div style={{ display: 'grid', placeItems: 'center', padding: 40, background: 'var(--bg)' }}>
        <div style={{ width: 380, maxWidth: '100%' }}>
          <img src="app/aicos-logo.png" alt="AI-COS — QHSE Excellence" style={{ height: 46, width: 'auto', marginBottom: 22, display: 'block' }} />
          <div className="eyebrow">Sign in</div>
          <h2 style={{ fontSize: 25, fontWeight: 800, letterSpacing: '-.6px', margin: '6px 0 4px' }}>Welcome back</h2>
          <div className="row" style={{ justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
            <p className="muted" style={{ fontSize: 13.5, margin: 0 }}>Enter the QHSE demo.</p>
            <a href="/" style={{ fontSize: 12, fontWeight: 600, color: 'var(--primary-600)', textDecoration: 'none' }}>← All editions</a>
          </div>
          <div className="row" style={{ gap: 10, alignItems: 'flex-start', background: 'var(--warn-bg)', border: '1px solid var(--warn-line)', borderRadius: 11, padding: '11px 13px', marginBottom: 22 }}>
            <span style={{ color: 'var(--warn)', flex: 'none', marginTop: 1 }}><Icon name="alert" size={16} /></span>
            <div style={{ fontSize: 12, color: 'var(--text-2)', lineHeight: 1.5 }}><b style={{ color: 'var(--ink)' }}>Demonstration only.</b> Sample data for preview — nothing here is operational.</div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 18 }}>
            {[['director', 'grid', 'var(--primary-600)', 'QHSE Director', 'Full platform — all modules, Sentinel & approvals', 'Yusuf Rahman'], ['auditor', 'check-shield', 'var(--ai)', 'Client Auditor', 'Read-only, scoped, time-boxed evidence view', 'Aramco · external auditor']].map(([r, ic, col, ti, su, wh]) => (
              <button key={r} onClick={() => setRole(r)} style={{ display: 'flex', alignItems: 'center', gap: 13, textAlign: 'left', cursor: 'pointer', width: '100%', background: role === r ? 'var(--surface)' : 'var(--surface-2)', fontFamily: 'inherit', border: `1.5px solid ${role === r ? col : 'var(--border)'}`, borderRadius: 13, padding: '12px 14px', boxShadow: role === r ? 'var(--sh)' : 'none' }}>
                <span style={{ width: 38, height: 38, borderRadius: 11, flex: 'none', display: 'grid', placeItems: 'center', background: role === r ? col : '#eef1f6', color: role === r ? '#fff' : 'var(--text-2)' }}><Icon name={ic} size={19} /></span>
                <div style={{ flex: 1, minWidth: 0 }}><div style={{ fontWeight: 750, fontSize: 14 }}>{ti}</div><div className="faint" style={{ fontSize: 11.5, marginTop: 1 }}>{su}</div><div style={{ fontSize: 11, color: col, fontWeight: 600, marginTop: 2 }}>{wh}</div></div>
              </button>
            ))}
          </div>
          <Btn variant="primary" size="lg" style={{ width: '100%' }} iconR="arrowR" onClick={() => onEnter(role)}>{auditor ? 'Open auditor evidence view' : 'Enter AI-COS QHSE'}</Btn>
          <div className="row" style={{ justifyContent: 'center', gap: 7, marginTop: 16, fontSize: 12, color: 'var(--text-3)' }}><Icon name="lock" size={13} /> SSO &amp; MFA enforced · audit-logged session</div>
        </div>
      </div>
    </div>
  );
}

function AuditorView({ onLogout }) {
  const [secs, setSecs] = useState(7186);
  useEffect(() => { const t = setInterval(() => setSecs((s) => Math.max(0, s - 1)), 1000); return () => clearInterval(t); }, []);
  const clock = [Math.floor(secs / 3600), Math.floor(secs % 3600 / 60), secs % 60].map((n) => String(n).padStart(2, '0')).join(':');
  const openNCR = DB.ncrs.filter((n) => n.status !== 'Closed').length;
  const openInc = DB.incidents.filter((i) => i.status !== 'Closed').length;
  return (
    <div style={{ minHeight: '100vh', background: 'var(--bg)', position: 'relative', overflow: 'hidden' }}>
      <div style={{ position: 'fixed', inset: '-20%', zIndex: 0, pointerEvents: 'none', opacity: .04, transform: 'rotate(-24deg)', display: 'flex', flexWrap: 'wrap', alignContent: 'flex-start', gap: '34px 26px' }}>
        {Array.from({ length: 160 }).map((_, i) => <span key={i} style={{ fontSize: 15, fontWeight: 800, whiteSpace: 'nowrap', color: 'var(--ink)' }}>CS ARABIA · AUDITOR VIEW · CONFIDENTIAL</span>)}
      </div>
      <header style={{ height: 60, position: 'relative', zIndex: 2, background: 'var(--surface)', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', padding: '0 24px', gap: 16 }}>
        <div className="row" style={{ gap: 10 }}><BrandMark size={32} /><div style={{ fontWeight: 800, fontSize: 15 }}>AI-COS <span style={{ color: 'var(--text-3)', fontWeight: 600 }}>Evidence</span></div></div>
        <span className="badge" style={{ background: 'var(--ai-bg)', color: 'var(--ai)', border: '1px solid var(--ai-line)' }}><Icon name="check-shield" size={12} /> Client Auditor · read-only</span>
        <span className="faint" style={{ fontSize: 12 }}>Scope: National Oil Co. · P-204 · last 90 days</span>
        <span className="spacer" />
        <span className="row" style={{ gap: 6, fontSize: 12.5, color: 'var(--warn)', fontWeight: 600 }}><Icon name="clock" size={13} />Session expires in {clock}</span>
        <Btn size="sm" variant="ghost" icon="logout" onClick={onLogout}>Exit</Btn>
      </header>
      <div style={{ maxWidth: 1080, margin: '0 auto', padding: 24, position: 'relative', zIndex: 1 }}>
        <div className="row" style={{ gap: 10, alignItems: 'flex-start', background: 'var(--info-bg)', border: '1px solid var(--primary-100)', borderRadius: 11, padding: '11px 14px', marginBottom: 18 }}>
          <Icon name="lock" size={16} style={{ color: 'var(--primary-600)', flex: 'none', marginTop: 1 }} />
          <div style={{ fontSize: 12.5, color: 'var(--text-2)', lineHeight: 1.5 }}><b style={{ color: 'var(--ink)' }}>Read-only evidence view.</b> Scoped to your project and date range. Exports are watermarked; every action you take here is logged for the audited entity. No records can be edited.</div>
        </div>
        <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(4,1fr)', marginBottom: 16 }}>
          <Kpi label="Compliance score" value={DB.mgmt.complianceScore} icon="check-shield" tone="ok" />
          <Kpi label="Open NCRs (scope)" value={openNCR} icon="check-shield" tone="warn" />
          <Kpi label="Open incidents (scope)" value={openInc} icon="helmet" tone="warn" />
          <Kpi label="Equipment readiness" value={DB.mgmt.equipmentReadiness} unit="%" icon="cpu" tone="ok" />
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginBottom: 16 }}>
          <div className="card card-pad"><div className="eyebrow" style={{ marginBottom: 12 }}>ISO management systems</div><div className="row" style={{ gap: 18, justifyContent: 'space-around' }}>{DB.standards.map((s) => <div key={s.code} style={{ textAlign: 'center' }}><Ring value={s.score} size={70} color={scoreColor(s.score)}><b style={{ fontSize: 15 }}>{s.score}</b></Ring><div style={{ fontSize: 11, fontWeight: 600, marginTop: 6 }}>{s.code.split(':')[0]}</div></div>)}</div></div>
          <div className="card"><div className="card-head"><Icon name="clipboard" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Audit history</div></div>
            <table className="tbl"><thead><tr><th>Ref</th><th>Scope</th><th>Findings</th><th>Status</th></tr></thead><tbody>{DB.audits.map((a) => <tr key={a.id}><td className="mono cell-strong" style={{ fontSize: 11.5 }}>{a.id}</td><td style={{ fontSize: 12 }}>{a.scope}</td><td>{a.findings}</td><td><Badge kind={a.status === 'Closed' ? 'ok' : a.status === 'Planned' ? 'info' : 'warn'} dot={a.status !== 'Closed'}>{a.status}</Badge></td></tr>)}</tbody></table>
          </div>
        </div>
        <div className="card"><div className="card-head"><Icon name="documents" size={16} style={{ color: 'var(--primary-600)' }} /><div className="h-sec">Evidence pack</div><span className="spacer" /><Btn size="sm" icon="download" onClick={() => window.toast('Watermarked evidence pack exported · access logged', 'info')}>Download (watermarked)</Btn></div>
          <table className="tbl"><thead><tr><th>Document</th><th>Type</th><th>Status</th></tr></thead><tbody>{DB.docs.slice(0, 4).map((d) => <tr key={d.code}><td><div style={{ fontSize: 12.5, fontWeight: 650 }}>{d.title}</div><div className="mono faint" style={{ fontSize: 10.5 }}>{d.code} · {d.ver}</div></td><td className="faint" style={{ fontSize: 12 }}>{d.type}</td><td><StatusBadge status={d.status} /></td></tr>)}</tbody></table>
        </div>
        <div className="faint" style={{ fontSize: 11.5, textAlign: 'center', marginTop: 18 }}><Icon name="lock" size={11} /> All access in this view is read-only, watermarked and logged for the audited entity (NFR-SEC.4).</div>
      </div>
    </div>
  );
}

/* Live data mutations — mutate window.DB, force a re-render so every register/
   KPI/dashboard updates instantly, and persist the dataset back to Neon. */
function dbSave(key) { try { fetch('/api/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key, data: window.DB[key] }) }).catch(() => {}); } catch (e) {} }
function dbAdd(key, rec) { if (!window.DB[key]) window.DB[key] = []; window.DB[key].unshift(rec); if (window.__bump) window.__bump(); dbSave(key); return rec; }
function dbUpdate(key, idField, idVal, patch) { const arr = window.DB[key] || []; const r = arr.find((x) => x[idField] === idVal); if (r) Object.assign(r, patch); if (window.__bump) window.__bump(); dbSave(key); return r; }
function dbRemove(key, idField, idVal) { window.DB[key] = (window.DB[key] || []).filter((x) => x[idField] !== idVal); if (window.__bump) window.__bump(); dbSave(key); }
function dDate(v) { return v ? new Date(v) : new Date(); }
/* Row actions kebab — View / Edit / Delete */
function RowActions({ onView, onEdit, onDelete }) {
  const [open, setOpen] = useState(false);
  return (
    <span style={{ position: 'relative' }} onClick={(e) => e.stopPropagation()}>
      <button className="icon-btn" style={{ width: 28, height: 28 }} onClick={() => setOpen((o) => !o)}><Icon name="dots" size={15} /></button>
      {open && <React.Fragment>
        <div style={{ position: 'fixed', inset: 0, zIndex: 60 }} onClick={() => setOpen(false)} />
        <div className="popover" style={{ right: 0, top: 'calc(100% + 4px)', minWidth: 130, zIndex: 61 }}>
          {onView && <div className="pop-item" onClick={() => { setOpen(false); onView(); }}><Icon name="eye" size={13} />View</div>}
          {onEdit && <div className="pop-item" onClick={() => { setOpen(false); onEdit(); }}><Icon name="signature" size={13} />Edit</div>}
          {onDelete && <div className="pop-item" style={{ color: 'var(--bad)' }} onClick={() => { setOpen(false); if (window.confirm('Delete this record? This cannot be undone.')) onDelete(); }}><Icon name="x" size={13} />Delete</div>}
        </div>
      </React.Fragment>}
    </span>
  );
}
function _seq(arr, prefix, start) { return prefix + String((start || 1) + (arr ? arr.length : 0)).padStart(3, '0'); }

function _di(d) { if (!d) return ''; const x = new Date(d); return isNaN(x) ? '' : x.toISOString().slice(0, 10); }
/* ===== Sentinel live form-analysis engines — reactive while the user fills the form ===== */
/* Classification reference tables shared by the incident form, its cascading derive() and live analysis */
var INC_TYPES = ['Near miss', 'First-aid case', 'Medical-treatment case', 'Restricted-work case', 'Lost-time injury (LTI)', 'Fatality', 'Property damage', 'Environmental', 'Security', 'Dangerous occurrence'];
var INC_MECHANISMS = ['Struck by object', 'Caught in / between', 'Fall from height', 'Slip / trip / fall (same level)', 'Contact with electricity', 'Contact with chemical', 'Manual handling / overexertion', 'Exposure (noise / heat / gas)', 'Vehicle collision', 'Fire / explosion'];
var INC_MECH_CAT = { 'Struck by object': 'Lifting & rigging', 'Caught in / between': 'Lifting & rigging', 'Fall from height': 'Work at height', 'Slip / trip / fall (same level)': 'Slips, trips & falls', 'Contact with electricity': 'Electrical', 'Contact with chemical': 'Chemical / spill', 'Manual handling / overexertion': 'Manual handling', 'Exposure (noise / heat / gas)': 'Occupational health', 'Vehicle collision': 'Vehicle / transport', 'Fire / explosion': 'Fire & explosion' };
var INC_MECH_CONTROL = { 'Struck by object': 'Exclusion zone + tool tethering + hard-barrier segregation', 'Caught in / between': 'Machine guarding + LOTO isolation + line-of-fire training', 'Fall from height': 'Fall-arrest harness + edge protection + work-at-height permit', 'Slip / trip / fall (same level)': 'Housekeeping standard + walkway demarcation + spill response', 'Contact with electricity': 'LOTO + verified zero-energy + insulated PPE', 'Contact with chemical': 'COSHH assessment + ventilation + chemical PPE + eyewash', 'Manual handling / overexertion': 'Manual-handling assessment + mechanical aids + team lift', 'Exposure (noise / heat / gas)': 'Exposure monitoring + RPE/hearing protection + rotation', 'Vehicle collision': 'Traffic-management plan + banksman + segregation', 'Fire / explosion': 'Hot-work permit + gas test + fire watch' };
var INC_POT_RANK = { Minor: 1, Serious: 2, Major: 3, Fatal: 4 };
function sentinelIncident(v) {
  const cat = v.cat, sev = v.severity, ttl = (v.title || '').toLowerCase();
  const lines = []; let tone = 'info';
  const started = v.title || v.cat || v.severity || v.type || v.mechanism;
  const hipo = sev === 'High' || INC_POT_RANK[v.potential] >= 3 || /Fatality|Lost-time|Dangerous/.test(v.type || '');
  const headline = started
    ? (hipo ? 'High-potential (HiPo) event' : 'Reportable event') + (v.type ? ' · ' + v.type : '') + (cat ? ' · ' + cat : '')
    : 'Select the type, mechanism and severity — Sentinel will classify, score and route this report.';
  // severity routing
  if (sev === 'High') { tone = 'bad'; lines.push({ tone: 'bad', icon: 'alert', text: 'High severity → auto-escalates to the HSE Director & senior management; a formal ICAM investigation is opened on submit.' }); }
  else if (sev === 'Medium') { tone = 'warn'; lines.push({ tone: 'warn', icon: 'alert', text: 'Medium severity → supervisor-led investigation due within 48 hours.' }); }
  else if (sev === 'Low') { lines.push({ tone: 'ok', icon: 'check', text: 'Low severity → line-manager review and corrective action.' }); }
  // regulator / RIDDOR-style notifiability driven by type & potential
  if (/Fatality|Lost-time|Dangerous occurrence/.test(v.type || '') || v.potential === 'Fatal') { tone = 'bad'; lines.push({ tone: 'bad', icon: 'shield', text: 'Notifiable to the regulator (PDO/OSHA-class) — statutory report due within 24 h; preserve the scene and evidence.' }); }
  // mechanism-driven line-of-fire insight
  if (v.mechanism) lines.push({ tone: hipo ? 'warn' : 'info', icon: 'workflow', text: 'Mechanism “' + v.mechanism + '” → line-of-fire / energy-source analysis; mapped to ' + (INC_MECH_CAT[v.mechanism] || cat || 'general') + ' control set.' });
  // injury detail insight
  if (v.bodyPart && v.bodyPart !== 'None (no injury)') lines.push({ tone: 'warn', icon: 'helmet', text: 'Injury to ' + v.bodyPart.toLowerCase() + (v.injuryNature && v.injuryNature !== 'None' ? ' (' + v.injuryNature.toLowerCase() + ')' : '') + ' → body-part PPE adequacy and first-aid response will be reviewed.' });
  // repeat detection
  const repeats = cat ? DB.incidents.filter((x) => x.cat === cat || (INC_MECH_CAT[v.mechanism] && x.cat === INC_MECH_CAT[v.mechanism])).length : 0;
  if (repeats >= 2) lines.push({ tone: 'warn', icon: 'history', text: 'Repeat signature — ' + repeats + " prior '" + (cat || INC_MECH_CAT[v.mechanism]) + "' events on record. Recommend a trend review and a systemic CAPA." });
  if (v.project) lines.push({ tone: 'info', icon: 'pin', text: 'Routes to the ' + v.project + ' HSE lead; open permits and the risk register are cross-checked for related controls.' });
  // suggestions (apply into fields)
  const suggest = [];
  if (v.mechanism && INC_MECH_CONTROL[v.mechanism] && !v.control) suggest.push({ text: 'Add control: ' + INC_MECH_CONTROL[v.mechanism], set: { key: 'control', val: INC_MECH_CONTROL[v.mechanism] } });
  if (/(fatal|amput|hospital|\blti\b|fracture|unconscious|serious)/.test(ttl) && sev !== 'High') suggest.push({ text: 'Raise severity to High', set: { key: 'severity', val: 'High' } });
  if ((v.title || v.mechanism) && !v.desc) suggest.push({ text: 'Draft investigation summary', set: { key: 'desc', val: 'On ' + (v.date || '[date]') + ' at ' + (v.project || 'site') + (v.location ? ' (' + v.location + ')' : '') + ', ' + (v.title ? v.title.charAt(0).toLowerCase() + v.title.slice(1) : (v.mechanism || 'an event').toLowerCase()) + (v.mechanism ? ' — mechanism: ' + v.mechanism.toLowerCase() : '') + '. Area made safe and isolated immediately. Investigation initiated per IMS PD-IMS-L4-F-14; root cause and corrective actions to follow.' } });
  return { headline, tone, clause: 'ISO 45001 §10.2', lines, suggest };
}
/* Cascading auto-fill: selecting an option updates dependent values (changedKey limits over-writing the user) */
function deriveIncident(v, k) {
  const p = {};
  if (k === 'type') {
    if (/Fatality/.test(v.type)) { p.severity = 'High'; p.potential = 'Fatal'; p.recordable = 'Yes'; p.reportable = 'Yes'; p.clientNotified = 'Yes'; }
    else if (/Lost-time|Restricted/.test(v.type)) { p.severity = 'High'; if (INC_POT_RANK[v.potential] < 3) p.potential = 'Major'; p.recordable = 'Yes'; p.reportable = 'Yes'; p.clientNotified = 'Yes'; }
    else if (/Medical-treatment/.test(v.type)) { if (v.severity === 'Low') p.severity = 'Medium'; p.recordable = 'Yes'; p.clientNotified = 'Pending'; }
    else if (/Dangerous occurrence/.test(v.type)) { p.reportable = 'Yes'; p.clientNotified = 'Yes'; }
    else if (/Near miss|First-aid/.test(v.type)) { if (!v.severity) p.severity = 'Low'; p.recordable = 'No'; }
    if (/Environmental/.test(v.type)) p.cat = 'Chemical / spill';
  }
  if (k === 'mechanism' && v.mechanism) {
    if (INC_MECH_CAT[v.mechanism]) p.cat = INC_MECH_CAT[v.mechanism];
    if (/Fall from height|Fire|electricity/.test(v.mechanism) && INC_POT_RANK[v.potential] < 3) p.potential = 'Major';
  }
  if (k === 'injuryNature') {
    if (/Amputation|Fatality/.test(v.injuryNature)) { p.severity = 'High'; p.potential = 'Fatal'; p.recordable = 'Yes'; p.reportable = 'Yes'; if (/Fatality/.test(v.injuryNature)) p.type = 'Fatality'; }
    else if (/Fracture|Burn/.test(v.injuryNature)) { if (v.severity !== 'High') p.severity = 'High'; p.recordable = 'Yes'; }
    if (v.injuryNature !== 'None' && v.bodyPart === 'None (no injury)') p.bodyPart = 'Multiple';
    if (v.injuryNature !== 'None' && v.personType === 'No person harmed') p.personType = 'Own employee';
  }
  if (k === 'potential') {
    if (v.potential === 'Fatal' && v.severity !== 'High') p.severity = 'High';
    if (INC_POT_RANK[v.potential] >= 3) p.reportable = 'Yes';
  }
  return p;
}
function sentinelRisk(v) {
  const L = +v.likelihood || 0, C = +v.severity || 0, R = L * C, area = (v.area || '').toLowerCase();
  const lines = []; let tone = 'info', band = '';
  if (R) {
    band = R >= 15 ? 'Extreme' : R >= 10 ? 'High' : R >= 5 ? 'Medium' : 'Low';
    tone = R >= 15 ? 'bad' : R >= 10 ? 'warn' : R >= 5 ? 'warn' : 'ok';
    lines.push({ tone, icon: 'gauge', text: 'Inherent risk score ' + R + '/25 → ' + band + '. ' + (R >= 10 ? 'Additional controls required before work proceeds.' : 'Manage by existing controls and monitoring.') });
    lines.push({ tone: 'info', icon: 'workflow', text: R >= 10 ? 'Above-medium risk → Sentinel recommends a Cause Tree / Fishbone analysis and management sign-off.' : 'Low/medium risk → a 5-Why review is sufficient for residual assessment.' });
  }
  const suggest = [];
  const ctrl = [[/(hot work|weld|flame|fire)/, 'Hot-work permit + fire watch + gas test'], [/(lift|crane|rig|hoist)/, 'Lift plan + certified rigger + exclusion zone'], [/(confined|vessel|purge|nitrogen)/, 'Gas test + standby attendant + rescue plan'], [/(height|scaffold|fall|roof)/, 'Fall-arrest harness + edge protection + access permit'], [/(electric|isolat|loto)/, 'LOTO isolation + verified zero-energy + insulated PPE'], [/(chemical|coshh|clean|acid)/, 'COSHH assessment + ventilation + correct PPE']];
  const cm = ctrl.find((c) => c[0].test(area));
  if (cm && !v.control) suggest.push({ text: 'Add control: ' + cm[1], set: { key: 'control', val: cm[1] } });
  return { headline: v.area ? 'Assessing: ' + v.area : 'Describe the hazard — Sentinel will score risk and propose controls.', tone, clause: 'ISO 31000', lines, suggest };
}
function sentinelNcr(v) {
  const cat = v.cat, sev = v.severity, lines = []; let tone = 'info';
  const repeats = cat ? DB.ncrs.filter((x) => x.cat === cat).length : 0;
  if (sev === 'Critical') { tone = 'bad'; lines.push({ tone: 'bad', icon: 'alert', text: 'Critical nonconformity → containment + stop-work review; escalates to the Quality Manager.' }); }
  else if (sev === 'Major') { tone = 'warn'; lines.push({ tone: 'warn', icon: 'alert', text: 'Major NCR → full root-cause analysis and CAPA required before closure.' }); }
  else if (sev === 'Minor') { lines.push({ tone: 'ok', icon: 'check', text: 'Minor NCR → correction and disposition; CAPA optional.' }); }
  if (repeats >= 2) lines.push({ tone: 'warn', icon: 'history', text: 'Repeat signature — ' + repeats + " prior '" + cat + "' NCRs. Sentinel flags a possible systemic cause." });
  lines.push({ tone: 'info', icon: 'workflow', text: 'On submit, Sentinel drafts the 5-Why and routes to ' + (v.project || 'the project') + ' quality lead for disposition.' });
  return { headline: v.title ? 'Analysing: ' + v.title : 'Describe the nonconformity — Sentinel checks for repeats & drafts the RCA.', tone, clause: 'ISO 9001 §10.2', lines, suggest: [] };
}
function sentinelMoc(v) {
  const rate = v.rating, lines = []; let tone = 'info';
  const rpn = { Low: 4, Medium: 8, High: 12, Extreme: 16 }[rate];
  if (rpn) lines.push({ tone: rpn >= 12 ? 'bad' : rpn >= 8 ? 'warn' : 'ok', icon: 'gauge', text: 'Change risk index ' + rpn + '/16 (' + rate + '). ' + (rpn >= 12 ? 'Requires HAZOP / risk workshop and senior approval.' : 'Standard MOC review and approval chain.') });
  if (rpn >= 12) tone = 'bad'; else if (rpn >= 8) tone = 'warn';
  lines.push({ tone: 'info', icon: 'workflow', text: 'Sentinel routes ' + (v.type ? 'this ' + v.type.toLowerCase() + ' change' : 'the change') + ' through screening → risk assessment → approval, and links affected procedures & PSSR.' });
  return { headline: v.title ? 'Screening: ' + v.title : 'Describe the change — Sentinel screens risk and routes approvals.', tone, clause: 'ISO 9001 §6.3', lines, suggest: [] };
}
function sentinelJourney(v) {
  const km = +v.km || 0, lines = []; let tone = 'ok';
  if (km) { tone = km >= 300 ? 'bad' : km >= 150 ? 'warn' : 'ok'; lines.push({ tone, icon: 'truck', text: km + ' km ' + (km >= 300 ? '→ long-haul: mandatory rest stops every 2 h and a co-driver above 500 km.' : km >= 150 ? '→ schedule a rest stop and confirm fatigue management.' : '→ within single-driver limits.') }); }
  lines.push({ tone: 'info', icon: 'gauge', text: 'Sentinel scores route & fatigue risk, verifies driver qualification and checks weather before approval.' });
  if (v.vehicle) lines.push({ tone: 'info', icon: 'check', text: 'Vehicle ' + v.vehicle + ' inspection & insurance validity confirmed against the fleet register.' });
  return { headline: v.name ? 'Planning: ' + v.name : 'Enter the route — Sentinel assesses journey risk before approval.', tone, clause: 'Journey management', lines, suggest: [] };
}

function openIncidentForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit incident ' + e.id : 'Report incident / near-miss', sub: 'PD-IMS-L4-F-14 · Sentinel auto-classifies & drafts the investigation', icon: 'helmet', submitLabel: rec ? 'Save changes' : 'Submit report', done: rec ? 'Incident updated' : 'Incident logged · AI investigation & CAPA draft ready',
    live: sentinelIncident, derive: deriveIncident, aside: true,
    fields: [
      { type: 'section', label: 'Classification', hint: 'Sentinel (right) re-scores and re-routes the moment you change any of these.' },
      { key: 'type', label: 'Event type', type: 'select', options: INC_TYPES, value: e.type || 'Near miss', half: true },
      { key: 'cat', label: 'Hazard category', type: 'select', options: ['Lifting & rigging', 'Work at height', 'Confined space', 'Hot work', 'Electrical', 'Manual handling', 'Vehicle / transport', 'Slips, trips & falls', 'Chemical / spill', 'Fire & explosion', 'Occupational health', 'Pressure', 'Other'], value: e.cat || 'Lifting & rigging', half: true },
      { key: 'mechanism', label: 'Mechanism / energy source', type: 'select', options: INC_MECHANISMS, value: (e.detail && e.detail.mechanism) || '', half: true },
      { key: 'activityType', label: 'Activity status', type: 'select', options: ['Routine operation', 'Non-routine task', 'Maintenance', 'Commissioning', 'Shutdown / turnaround', 'Emergency response'], value: (e.detail && e.detail.activityType) || 'Routine operation', half: true },
      { key: 'severity', label: 'Actual severity', type: 'radio', options: ['Low', 'Medium', 'High'], value: e.severity || 'Medium', half: true },
      { key: 'potential', label: 'Potential (worst-case)', type: 'select', options: ['Minor', 'Serious', 'Major', 'Fatal'], value: (e.detail && e.detail.potential) || 'Serious', half: true },
      { key: 'recordable', label: 'Recordable?', type: 'select', options: ['No', 'Yes'], value: (e.detail && e.detail.recordable) || 'No', half: true },
      { key: 'reportable', label: 'Regulatory reportable?', type: 'select', options: ['No', 'Yes'], value: (e.detail && e.detail.reportable) || 'No', half: true },
      { key: 'clientNotified', label: 'Client notified?', type: 'select', options: ['No', 'Yes', 'Pending'], value: (e.detail && e.detail.clientNotified) || 'No', half: true },
      { type: 'section', label: 'Injured / affected person' },
      { key: 'personType', label: 'Affected party', type: 'select', options: ['No person harmed', 'Own employee', 'Contractor', 'Visitor', 'Public', 'Environment only', 'Asset only'], value: (e.detail && e.detail.personType) || 'No person harmed', half: true },
      { key: 'injuredPerson', label: 'Name (if applicable)', type: 'text', value: (e.detail && e.detail.injuredPerson) || '', half: true },
      { key: 'employeeId', label: 'Employee / badge ID', type: 'text', value: (e.detail && e.detail.employeeId) || '', half: true },
      { key: 'company', label: 'Company', type: 'text', value: (e.detail && e.detail.company) || '', half: true },
      { key: 'designation', label: 'Designation', type: 'text', value: (e.detail && e.detail.designation) || '', half: true },
      { key: 'bodyPart', label: 'Body part affected', type: 'select', options: ['None (no injury)', 'Head / face', 'Eye', 'Neck', 'Back', 'Shoulder / arm', 'Hand / fingers', 'Torso', 'Leg / knee', 'Foot / ankle', 'Multiple', 'Internal'], value: (e.detail && e.detail.bodyPart) || 'None (no injury)', half: true },
      { key: 'injuryNature', label: 'Nature of injury', type: 'select', options: ['None', 'Laceration / cut', 'Bruise / contusion', 'Fracture', 'Sprain / strain', 'Burn', 'Amputation', 'Crush', 'Foreign body', 'Respiratory', 'Fatality'], value: (e.detail && e.detail.injuryNature) || 'None', half: true },
      { key: 'treatment', label: 'Treatment given', type: 'select', options: ['None', 'First aid on site', 'Clinic / paramedic', 'Hospital — outpatient', 'Hospital — admitted', 'Referred / specialist'], value: (e.detail && e.detail.treatment) || 'None', half: true },
      { key: 'lostDays', label: 'Lost-time days', type: 'number', value: (e.detail && e.detail.lostDays != null) ? String(e.detail.lostDays) : '0', half: true },
      { type: 'section', label: 'Event details' },
      { key: 'title', label: 'What happened (title)', type: 'text', full: true, value: e.title, placeholder: 'Brief factual description of the event' },
      { key: 'date', label: 'Date of event', type: 'date', value: _di(e.date), half: true },
      { key: 'time', label: 'Time', type: 'text', value: (e.detail && e.detail.time) || '08:45', half: true },
      { key: 'project', label: 'Project / site', type: 'select', options: ['P-204', 'P-211', 'P-198', 'P-187'], value: e.project || 'P-204', half: true },
      { key: 'location', label: 'Specific location / area', type: 'text', value: (e.detail && e.detail.location) || '', half: true },
      { key: 'workActivity', label: 'Work activity', type: 'text', value: (e.detail && e.detail.workActivity) || '', half: true },
      { key: 'equipment', label: 'Equipment involved', type: 'text', value: (e.detail && e.detail.equipment) || '', half: true },
      { key: 'weather', label: 'Weather / conditions', type: 'select', options: ['Clear', 'Hot / high temp', 'Rain', 'Wind', 'Low light / night', 'Dust / poor visibility'], value: (e.detail && e.detail.weather) || 'Clear', half: true },
      { key: 'control', label: 'Control that failed / required', type: 'text', full: true, value: (e.detail && e.detail.control) || '' },
      { type: 'section', label: 'Reporting & response' },
      { key: 'reportedBy', label: 'Reported by', type: 'text', value: (e.detail && e.detail.reportedBy) || 'Ahmed Khan', half: true },
      { key: 'reportedRole', label: 'Role', type: 'text', value: (e.detail && e.detail.reportedRole) || 'Operator', half: true },
      { key: 'witnesses', label: 'Witnesses', type: 'text', full: true, value: (e.detail && e.detail.witnesses) || '' },
      { key: 'desc', label: 'Description', type: 'textarea', value: e.desc || (e.detail && e.detail.description), full: true },
      { key: 'immediate', label: 'Immediate action taken', type: 'textarea', value: e.detail && e.detail.immediate ? e.detail.immediate.join('; ') : '', full: true },
    ],
    onSave: (v) => {
      const detail = { mechanism: v.mechanism, activityType: v.activityType, potential: v.potential, recordable: v.recordable, reportable: v.reportable, clientNotified: v.clientNotified, personType: v.personType, injuredPerson: v.injuredPerson, employeeId: v.employeeId, company: v.company, designation: v.designation, bodyPart: v.bodyPart, injuryNature: v.injuryNature, treatment: v.treatment, lostDays: +v.lostDays || 0, reportedBy: v.reportedBy, reportedRole: v.reportedRole, witnesses: v.witnesses, location: v.location, workActivity: v.workActivity, equipment: v.equipment, weather: v.weather, control: v.control, time: v.time, description: v.desc, immediate: v.immediate ? v.immediate.split(/;\s*/).filter(Boolean) : undefined };
      return rec ? dbUpdate('incidents', 'id', e.id, { type: v.type, hipo: v.severity === 'High' || INC_POT_RANK[v.potential] >= 3, title: v.title, project: v.project, date: dDate(v.date), severity: v.severity, cat: v.cat, detail: Object.assign({}, e.detail, detail) }) : dbAdd('incidents', { id: _seq(DB.incidents, 'INC-26-', 31), type: v.type || 'Incident', hipo: v.severity === 'High' || INC_POT_RANK[v.potential] >= 3, title: v.title || 'New reported event', project: v.project || 'P-204', date: dDate(v.date), severity: v.severity || 'Medium', status: 'Reported', capa: null, cat: v.cat || 'Lifting & rigging', detail });
    } });
}
function openRiskForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit risk' : 'Add new risk', sub: 'ISO 31000 · Sentinel suggests controls & residual rating', icon: 'alert', submitLabel: rec ? 'Save changes' : 'Add risk', done: rec ? 'Risk updated' : 'Risk added to register',
    live: sentinelRisk,
    fields: [
      { key: 'area', label: 'Risk / hazard (area · task)', type: 'text', full: true, value: e.area, placeholder: 'e.g. Hot work near hydrocarbon' },
      { key: 'project', label: 'Location / project', type: 'select', options: ['P-204', 'P-211', 'P-198', 'Corporate'], value: e.project || 'P-204', half: true },
      { key: 'control', label: 'Existing control', type: 'text', value: e.control, half: true },
      { key: 'likelihood', label: 'Likelihood (1–5)', type: 'select', options: ['1', '2', '3', '4', '5'], value: String(e.likelihood || 3), half: true },
      { key: 'severity', label: 'Consequence (1–5)', type: 'select', options: ['1', '2', '3', '4', '5'], value: String(e.severity || 3), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('risks', 'id', e.id, { area: v.area, project: v.project, likelihood: +v.likelihood, severity: +v.severity, control: v.control }) : dbAdd('risks', { id: _seq(DB.risks, 'RR-26-', 1), area: v.area || 'New risk', project: v.project || 'P-204', likelihood: +v.likelihood || 3, severity: +v.severity || 3, control: v.control || 'TBD', status: 'Open' }) });
}
function openNcrForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + e.id : 'Raise NCR / CAR', sub: 'ISO 9001 · AI repeat-detection & RCA assist', icon: 'check-shield', submitLabel: rec ? 'Save changes' : 'Raise NCR', done: rec ? 'NCR updated' : 'NCR raised · AI checked for repeat signature',
    live: sentinelNcr,
    fields: [
      { key: 'title', label: 'Title / nonconformity', type: 'text', full: true, value: e.title },
      { key: 'project', label: 'Project', type: 'select', options: ['P-204', 'P-211', 'P-198'], value: e.project || 'P-204', half: true },
      { key: 'cat', label: 'Category', type: 'select', options: ['Workmanship', 'Documentation', 'Material', 'Process', 'Supplier'], value: e.cat || 'Workmanship', half: true },
      { key: 'severity', label: 'Severity', type: 'radio', options: ['Minor', 'Major', 'Critical'], value: e.severity || 'Major', half: true },
      { key: 'date', label: 'Date raised', type: 'date', value: _di(e.date), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('ncrs', 'id', e.id, { title: v.title, project: v.project, cat: v.cat, severity: v.severity, date: dDate(v.date) }) : dbAdd('ncrs', { id: _seq(DB.ncrs, 'NCR-26-', 60), title: v.title || 'New nonconformity', project: v.project || 'P-204', cat: v.cat || 'Workmanship', severity: v.severity || 'Major', owner: 'Q-001', stage: 'Open', status: 'Open', date: dDate(v.date) }) });
}
function openObsForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit observation' : 'New safety observation', sub: 'Unsafe act / condition / good practice', icon: 'flag', submitLabel: rec ? 'Save changes' : 'Log observation', done: rec ? 'Observation updated' : 'Observation logged · trends updated',
    ai: { title: 'Sentinel assist', body: 'AI clusters the observation into leading indicators and routes corrective actions.' },
    fields: [
      { key: 'title', label: 'Observation', type: 'text', full: true, value: e.title },
      { key: 'cat', label: 'Category', type: 'select', options: ['Unsafe Condition', 'Unsafe Act', 'Environmental', 'Housekeeping', 'Health Hazard', 'Positive'], value: e.cat || 'Unsafe Condition', half: true },
      { key: 'loc', label: 'Location', type: 'select', options: ['NGP - Area 12', 'P-204', 'P-211', 'Workshop', 'Storage Yard'], value: e.loc || 'NGP - Area 12', half: true },
      { key: 'risk', label: 'Risk level', type: 'radio', options: ['Low', 'Medium', 'High'], value: e.risk || 'Medium', half: true },
      { key: 'date', label: 'Date', type: 'date', value: _di(e.date), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('safetyObs', 'id', e.id, { title: v.title, cat: v.cat, loc: v.loc, risk: v.risk, date: dDate(v.date) }) : dbAdd('safetyObs', { id: _seq(DB.safetyObs, 'OBS-26-', 256), title: v.title || 'New observation', cat: v.cat || 'Unsafe Condition', type: 'General', loc: v.loc || 'NGP - Area 12', risk: v.risk || 'Medium', status: 'Open', by: 'Q-002', date: dDate(v.date), due: new Date(Date.now() + 7 * 864e5) }) });
}
function openDocForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit document ' + e.code : 'New controlled document', sub: 'IMS document control · ISO 9001 §7.5', icon: 'documents', submitLabel: rec ? 'Save changes' : 'Create document', done: rec ? 'Document updated' : 'Document created (draft)',
    fields: [
      { key: 'title', label: 'Document title', type: 'text', full: true, value: e.title },
      { key: 'code', label: 'Document code', type: 'text', half: true, value: e.code, placeholder: 'PRC-OPS-016' },
      { key: 'type', label: 'Type', type: 'select', options: ['Procedure', 'Work instruction', 'Form', 'Policy'], value: e.type || 'Procedure', half: true },
      { key: 'review', label: 'Next review', type: 'date', value: _di(e.review), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('docs', 'code', e.code, { title: v.title, type: v.type, review: dDate(v.review) }) : dbAdd('docs', { code: v.code || _seq(DB.docs, 'DOC-', 1), title: v.title || 'New document', type: v.type || 'Procedure', ver: 'v1.0', ack: 0, status: 'Draft', review: dDate(v.review) }) });
}
function openAuditForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit audit ' + e.id : 'Schedule audit', sub: 'Internal / external · ISO 19011', icon: 'clipboard', submitLabel: rec ? 'Save changes' : 'Schedule audit', done: rec ? 'Audit updated' : 'Audit scheduled',
    fields: [
      { key: 'scope', label: 'Scope / title', type: 'text', full: true, value: e.scope },
      { key: 'type', label: 'Type', type: 'select', options: ['Internal', 'External'], value: e.type || 'Internal', half: true },
      { key: 'date', label: 'Planned date', type: 'date', value: _di(e.date), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('audits', 'id', e.id, { scope: v.scope, type: v.type, date: dDate(v.date) }) : dbAdd('audits', { id: _seq(DB.audits, 'AUD-26-', 1), scope: v.scope || 'New audit', type: v.type || 'Internal', date: dDate(v.date), findings: 0, major: 0, status: 'Planned' }) });
}
function openMocForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + e.id : 'Raise MOC request', sub: 'PD-QSP MOC · AI screens risk & routes approvals', icon: 'workflow', submitLabel: rec ? 'Save changes' : 'Submit MOC', done: rec ? 'MOC updated' : 'MOC raised · routed for risk assessment',
    live: sentinelMoc,
    fields: [
      { key: 'title', label: 'Change title', type: 'text', full: true, value: e.title },
      { key: 'type', label: 'Change type', type: 'select', options: ['Equipment', 'Process', 'Technology', 'Facility', 'Organization'], value: e.type || 'Equipment', half: true },
      { key: 'rating', label: 'Risk rating', type: 'select', options: ['Low', 'Medium', 'High', 'Extreme'], value: e.rating || 'Medium', half: true },
      { key: 'date', label: 'Target date', type: 'date', half: true },
      { key: 'reason', label: 'Reason for change', type: 'textarea', full: true },
    ],
    onSave: (v) => { const rpn = { Low: 4, Medium: 8, High: 12, Extreme: 16 }[v.rating] || 8; rec ? dbUpdate('mocs', 'id', e.id, { title: v.title, type: v.type, rating: v.rating, rpn }) : dbAdd('mocs', { id: _seq(DB.mocs, 'MOC-26-', 14), title: v.title || 'New change request', type: v.type || 'Equipment', rpn, rating: v.rating || 'Medium', stage: 'Screening', owner: 'Q-006', status: 'Open' }); } });
}
function openPtwForm(rec) {
  const e = rec || {};
  const permitNo = rec ? e.id : _seq(DB.ptw, 'PTW-26-', 100);
  window.openAIAssist({ title: rec ? 'Edit ' + e.id : 'Create permit to work', sub: 'Form PTW-L4-F-01 · Sentinel pre-loads hazards & controls and flags SIMOPS clashes', icon: 'flag', width: 940, compute: ptwCompute, submitLabel: rec ? 'Save changes' : 'Submit for approval', done: rec ? 'Permit updated' : 'PTW created · routed for approval',
    fields: [
      { type: 'section', label: 'Permit details' },
      { key: 'permitNo', label: 'Permit no.', type: 'readonly', value: permitNo },
      { key: 'ptype', label: 'Permit type', type: 'select', options: ['Hot Work', 'Cold Work', 'Electrical', 'Excavation', 'Confined Space', 'Lifting', 'Working at Height'], value: e.ptype || e.type || 'Hot Work', half: true },
      { key: 'desc', label: 'Job / work description', type: 'textarea', full: true, value: e.desc || e.sub, placeholder: 'Describe the work to be performed…' },
      { key: 'equip', label: 'Equipment / system', type: 'text', half: true, value: e.equip, placeholder: 'e.g. P-201 discharge line' },
      { key: 'loc', label: 'Location', type: 'select', options: ['NGP - Area 12', 'North Ghawar Plant - Area 12', 'P-204', 'P-211', 'P-198', 'Tank Farm', 'Workshop'], value: e.loc || 'NGP - Area 12', half: true },
      { key: 'area', label: 'Specific area / sub-location', type: 'text', half: true, value: e.area },
      { key: 'risk', label: 'Risk level', type: 'select', options: ['Low', 'Medium', 'High'], value: e.risk || 'High', half: true },
      { type: 'section', label: 'Schedule & resources' },
      { key: 'start', label: 'Planned start', type: 'datetime', half: true },
      { key: 'finish', label: 'Planned finish', type: 'datetime', half: true },
      { key: 'persons', label: 'No. of persons', type: 'number', value: String(e.persons || 4), half: true },
      { key: 'contractor', label: 'Contractor / crew', type: 'text', half: true, value: e.contractor, placeholder: 'In-house / contractor name' },
      { type: 'section', label: 'Requestor' },
      { key: 'requestedBy', label: 'Requested by', type: 'text', value: e.requestedBy || (e.by ? DB.staffById(e.by).name : 'Ahmed Khan'), half: true },
      { key: 'department', label: 'Department', type: 'select', options: ['Operations', 'Maintenance', 'HSE', 'Engineering', 'Projects'], value: e.department || 'Operations', half: true },
      { key: 'reqDate', label: 'Request date', type: 'date', half: true },
      { key: 'reqSign', label: 'Requestor signature', type: 'sign', signer: e.requestedBy || 'Ahmed Khan', half: true },
      { type: 'section', label: 'Hazards & controls', hint: 'AI pre-selects the typical set for the permit type — adjust as needed.' },
      { key: 'hazards', label: 'Hazards identified', type: 'checks', options: ['Fire / explosion', 'Electric shock', 'Toxic / fumes', 'Work at height', 'Pinch / crush', 'Confined space', 'Dropped object', 'Hot surfaces'], value: e.hazards || ['Fire / explosion', 'Hot surfaces'] },
      { key: 'controls', label: 'Controls in place', type: 'checks', options: ['Gas test', 'Fire watch', 'Isolation / LOTO', 'Barricading', 'Rescue standby', 'PPE', 'Tool tethering', 'Toolbox talk done'], value: e.controls || ['Gas test', 'Fire watch', 'PPE'] },
      { type: 'section', label: 'Approval workflow', hint: 'Routed in sequence on submit — each approver e-signs in turn.' },
      { key: 'approvers', label: 'Approvers', type: 'approvers', options: [['Area Supervisor', 'Ravi Kumar'], ['HSE Engineer', 'Fatima Noor'], ['Operations Manager', 'Sultan Al-Qahtani'], ['Permit Issuer', 'Khalid Al-Qahtani']] },
      { type: 'section', label: 'Attachments' },
      { key: 'attachments', label: 'Attached documents', type: 'text', full: true, placeholder: 'JSA.pdf, Isolation diagram.pdf, drawings…' },
    ],
    onSave: (v) => {
      const fmtDT = (s) => { if (!s) return ''; const d = new Date(s); if (isNaN(d)) return ''; const t = (s.split('T')[1] || '').slice(0, 5); return DB.fmt(d) + (t ? ' ' + t : ''); };
      const start = fmtDT(v.start) || (rec ? e.start : '—'); const finish = fmtDT(v.finish) || (rec ? e.finish : '—');
      const patch = { type: v.ptype, sub: v.desc || 'New permit', equip: v.equip, loc: v.loc || 'NGP - Area 12', area: v.area, risk: v.risk || 'High', start, finish, persons: +v.persons || 1, contractor: v.contractor, requestedBy: v.requestedBy, department: v.department, reqDate: v.reqDate, hazards: v.hazards, controls: v.controls, attachments: v.attachments };
      rec ? dbUpdate('ptw', 'id', e.id, patch) : dbAdd('ptw', Object.assign({ id: permitNo, by: 'Q-006', reqOn: DB.fmt(new Date()), project: 'P-204', validity: start + ' – ' + finish, status: 'Awaiting approval', simops: false }, patch));
    } });
}
function openLotoForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + e.id : 'New energy isolation (LOTO)', sub: 'Lock-out / tag-out under a parent permit', icon: 'lock', submitLabel: rec ? 'Save changes' : 'Create isolation', done: rec ? 'Isolation updated' : 'Isolation created',
    fields: [
      { key: 'equip', label: 'Equipment / system', type: 'text', full: true, value: e.equip },
      { key: 'ptw', label: 'Parent PTW', type: 'select', options: DB.ptw.slice(0, 10).map((p) => p.id), value: e.ptw, half: true },
      { key: 'type', label: 'Isolation type', type: 'select', options: ['Electrical', 'Mechanical', 'Pneumatic', 'Hydraulic', 'Thermal'], value: e.type || 'Electrical', half: true },
      { key: 'method', label: 'Isolation method', type: 'select', options: ['Lock & Tag', 'Blind / spade', 'Disconnect', 'Valve lock'], value: e.method || 'Lock & Tag', half: true },
      { key: 'loc', label: 'Location', type: 'text', half: true, value: e.loc },
      { key: 'points', label: 'Isolation points', type: 'number', value: String(e.points || 2), half: true },
      { key: 'by', label: 'Isolated by', type: 'select', options: DB.staff.map((s) => s.name), half: true },
      { key: 'verifiedBy', label: 'Verified by', type: 'select', options: DB.staff.map((s) => s.name), half: true },
      { key: 'date', label: 'Isolated on', type: 'date', value: _di(e.isolatedOn), half: true },
    ],
    onSave: (v) => { const sid = (n) => { const s = DB.staff.find((x) => x.name === n); return s ? s.id : 'Q-006'; }; const iso = DB.fmt(dDate(v.date)); return rec ? dbUpdate('loto', 'id', e.id, { equip: v.equip, ptw: v.ptw, type: v.type, method: v.method, loc: v.loc, points: +v.points, by: sid(v.by), verifiedBy: v.verifiedBy ? sid(v.verifiedBy) : '—', isolatedOn: iso }) : dbAdd('loto', { id: _seq(DB.loto, 'LOTO-26-', 156), ptw: v.ptw || (DB.ptw[0] ? DB.ptw[0].id : 'PTW-26-100'), loc: v.loc || 'NGP - Area 12', equip: v.equip || 'New isolation', type: v.type || 'Electrical', method: v.method || 'Lock & Tag', points: +v.points || 2, status: 'Active', isolatedOn: iso, restoredOn: '—', by: sid(v.by), verifiedBy: v.verifiedBy ? sid(v.verifiedBy) : '—' }); } });
}
function openProjectForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + e.id : 'New project', sub: 'Tender → mobilization → execution → closeout', icon: 'workflow', submitLabel: rec ? 'Save changes' : 'Create project', done: rec ? 'Project updated' : 'Project created',
    fields: [
      { key: 'name', label: 'Project name', type: 'text', full: true, value: e.name },
      { key: 'client', label: 'Client', type: 'text', half: true, value: e.client },
      { key: 'region', label: 'Region', type: 'select', options: ['Eastern', 'Central', 'Western', 'Offshore'], value: e.region || 'Eastern', half: true },
      { key: 'stage', label: 'Stage', type: 'select', options: ['Tender', 'Mobilization', 'Execution', 'Closeout'], value: e.stage || 'Tender', half: true },
      { key: 'risk', label: 'Risk', type: 'select', options: ['Low', 'Medium', 'High'], value: e.risk || 'Medium', half: true },
    ],
    onSave: (v) => rec ? dbUpdate('projects', 'id', e.id, { name: v.name, client: v.client, region: v.region, stage: v.stage, risk: v.risk }) : dbAdd('projects', { id: _seq(DB.projects, 'P-', 220), name: v.name || 'New project', client: v.client || 'Client', region: v.region || 'Eastern', stage: v.stage || 'Tender', hse: 0, progress: 5, value: 'SAR —', risk: v.risk || 'Medium' }) });
}
function openContractorForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + (e.name || 'contractor') : 'Prequalify contractor', sub: 'HSE · insurance · performance', icon: 'briefcase', submitLabel: rec ? 'Save changes' : 'Add contractor', done: rec ? 'Contractor updated' : 'Contractor added (prequalification pending)',
    fields: [
      { key: 'name', label: 'Contractor name', type: 'text', full: true, value: e.name },
      { key: 'scope', label: 'Scope', type: 'text', half: true, value: e.scope },
      { key: 'hse', label: 'HSE score', type: 'number', value: String(e.hse || 85), half: true },
      { key: 'prequal', label: 'Prequalification', type: 'select', options: ['Approved', 'Conditional', 'Pending'], value: e.prequal || 'Pending', half: true },
      { key: 'exp', label: 'Prequal expiry', type: 'date', value: _di(e.exp), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('contractors', 'id', e.id, { name: v.name, scope: v.scope, hse: +v.hse, prequal: v.prequal, exp: dDate(v.exp) }) : dbAdd('contractors', { id: _seq(DB.contractors, 'CON-', 1), name: v.name || 'New contractor', scope: v.scope || '—', prequal: v.prequal || 'Pending', hse: +v.hse || 85, insurance: new Date(Date.now() + 200 * 864e5), exp: dDate(v.exp) }) });
}
function openObservationLog(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + e.id : 'Log observation', sub: 'Quality / HSE field observation', icon: 'flag', submitLabel: rec ? 'Save changes' : 'Log observation', done: rec ? 'Observation updated' : 'Observation logged · trends updated',
    fields: [
      { key: 'obs', label: 'Observation', type: 'text', full: true, value: e.obs },
      { key: 'type', label: 'Type', type: 'select', options: ['Positive', 'Unsafe condition', 'Unsafe act'], value: e.type || 'Unsafe condition', half: true },
      { key: 'project', label: 'Project', type: 'select', options: ['P-204', 'P-211', 'P-198', 'P-219'], value: e.project || 'P-204', half: true },
      { key: 'date', label: 'Date', type: 'date', value: _di(e.date), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('observations', 'id', e.id, { obs: v.obs, type: v.type, project: v.project, date: dDate(v.date) }) : dbAdd('observations', { id: _seq(DB.observations, 'OBS-26-', 88), obs: v.obs || 'New observation', type: v.type || 'Unsafe condition', by: 'Q-002', project: v.project || 'P-204', date: dDate(v.date), status: 'Logged' }) });
}
function openAlertForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + e.id : 'Create safety alert', sub: 'AI drafts from an incident · EN + AR', icon: 'bell', submitLabel: rec ? 'Save changes' : 'Publish alert', done: rec ? 'Safety alert updated' : 'Safety alert created (draft)',
    ai: { title: 'Sentinel assist', body: 'AI drafts the alert content from the linked incident and routes it across channels.' },
    fields: [
      { key: 'title', label: 'Alert title', type: 'text', full: true, value: e.title },
      { key: 'type', label: 'Type', type: 'select', options: ['HSE', 'ENV'], value: e.type || 'HSE', half: true },
      { key: 'ref', label: 'Incident ref.', type: 'select', options: DB.incidents.slice(0, 8).map((i) => i.id), value: e.ref, half: true },
      { key: 'date', label: 'Publish date', type: 'date', half: true },
    ],
    onSave: (v) => rec ? dbUpdate('safetyAlerts', 'id', e.id, { title: v.title, type: v.type, ref: v.ref }) : dbAdd('safetyAlerts', { id: _seq(DB.safetyAlerts, 'SA-2024-', 24), title: v.title || 'New safety alert', type: v.type || 'HSE', ref: v.ref || DB.incidents[0].id, status: 'Draft', date: DB.fmt(dDate(v.date)) }) });
}
function openActionForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit action' : 'Add corrective / preventive action', sub: 'CAPA action tied to a finding / incident', icon: 'flag', submitLabel: rec ? 'Save changes' : 'Add action', done: rec ? 'Action updated' : 'Action added & assigned',
    fields: [
      { key: 'desc', label: 'Action description', type: 'text', full: true, value: e.desc },
      { key: 'type', label: 'Type', type: 'radio', options: ['Corrective', 'Preventive'], value: e.type || 'Corrective', half: true },
      { key: 'priority', label: 'Priority', type: 'radio', options: ['Low', 'Medium', 'High'], value: e.priority || 'Medium', half: true },
      { key: 'inc', label: 'Source / incident ref.', type: 'select', options: DB.incidents.slice(0, 8).map((i) => i.id), value: e.inc, half: true },
      { key: 'who', label: 'Responsible person', type: 'select', options: DB.staff.map((s) => s.name), half: true },
      { key: 'cause', label: 'Root cause addressed', type: 'text', full: true, value: e.cause },
      { key: 'due', label: 'Due date', type: 'date', value: _di(e.due), half: true },
    ],
    onSave: (v) => { const who = (DB.staff.find((s) => s.name === v.who) || DB.staff[0]).id; const due = DB.fmt(dDate(v.due)); return rec ? dbUpdate('capaActions', 'id', e.id, { desc: v.desc, type: v.type, priority: v.priority, inc: v.inc, who, cause: v.cause, due }) : dbAdd('capaActions', { id: _seq(DB.capaActions, 'CAPA-', 1), inc: v.inc || DB.incidents[0].id, desc: v.desc || 'New action', type: v.type || 'Corrective', cause: v.cause || '—', who, due, status: 'Open', priority: v.priority || 'Medium', progress: 0, overdue: 0, last: 'just now' }); } });
}
function openAssetForm(rec) {
  const e = rec || {};
  openForm({ title: rec ? 'Edit ' + e.id : 'Register asset', sub: 'Equipment · certification · calibration', icon: 'cpu', submitLabel: rec ? 'Save changes' : 'Register asset', done: rec ? 'Asset updated' : 'Asset registered',
    fields: [
      { key: 'name', label: 'Asset name', type: 'text', full: true, value: e.name },
      { key: 'type', label: 'Type', type: 'select', options: ['Mobile unit', 'Lifting gear', 'Test equipment', 'Tool'], value: e.type || 'Mobile unit', half: true },
      { key: 'project', label: 'Project', type: 'select', options: ['P-204', 'P-211', 'P-198', 'Workshop'], value: e.project || 'P-204', half: true },
      { key: 'cert', label: 'Certification expiry', type: 'date', value: _di(e.cert), half: true },
    ],
    onSave: (v) => rec ? dbUpdate('assets', 'id', e.id, { name: v.name, type: v.type, project: v.project, cert: dDate(v.cert) }) : dbAdd('assets', { id: _seq(DB.assets, 'AS-', 1), name: v.name || 'New asset', type: v.type || 'Mobile unit', project: v.project || 'P-204', cert: dDate(v.cert), status: 'Certified', readiness: 100 }) });
}
function openTrainingForm() {
  openForm({ title: 'Add training record', sub: 'Competency & training', icon: 'users', submitLabel: 'Add record', done: 'Training record added',
    fields: [
      { key: 'staff', label: 'Employee', type: 'select', options: DB.staff.map((s) => s.name), half: true },
      { key: 'role', label: 'Role', type: 'text', half: true },
      { key: 'course', label: 'Course', type: 'text', full: true },
      { key: 'gap', label: 'Has gap?', type: 'radio', options: ['No', 'Yes'], value: 'No', half: true },
    ],
    onSave: (v) => { const s = DB.staff.find((x) => x.name === v.staff) || DB.staff[0]; dbAdd('competency', { staff: s.id, role: v.role || s.role, certs: {}, gap: v.gap === 'Yes' }); } });
}
function openServiceForm() {
  openForm({ title: 'New service record', sub: 'Industrial services traceability', icon: 'box', submitLabel: 'Add record', done: 'Service record added',
    fields: [
      { key: 'type', label: 'Service', type: 'select', options: ['Nitrogen', 'Pipeline', 'Water', 'Chemical'], value: 'Nitrogen', half: true },
      { key: 'project', label: 'Project', type: 'select', options: ['P-204', 'P-211', 'P-198'], value: 'P-204', half: true },
      { key: 'activity', label: 'Activity', type: 'text', full: true },
      { key: 'date', label: 'Date', type: 'date', half: true },
    ],
    onSave: (v) => { const t = (v.type || 'Nitrogen').toLowerCase(); const arr = DB.services[t] || DB.services.nitrogen; arr.unshift({ id: 'SVC-' + (arr.length + 1), activity: v.activity || 'Service', project: v.project || 'P-204', result: 'Pass', date: dDate(v.date) }); if (window.__bump) window.__bump(); } });
}
function openInspectionForm() {
  openForm({ title: 'Schedule inspection', sub: 'HSE inspection · checklist-driven', icon: 'clipboard', submitLabel: 'Schedule', done: 'Inspection scheduled',
    fields: [
      { key: 'type', label: 'Inspection type', type: 'select', options: DB.inspTypes.map((t) => t.label), half: true },
      { key: 'area', label: 'Area / location', type: 'text', half: true },
      { key: 'dept', label: 'Department', type: 'select', options: ['Operations', 'Maintenance', 'HSE', 'Engineering'], value: 'Operations', half: true },
      { key: 'date', label: 'Date', type: 'date', half: true },
    ],
    onSave: (v) => { const meta = DB.inspTypes.find((t) => t.label === v.type) || DB.inspTypes[0]; const arr = DB.hseInspections[meta.key]; arr.unshift({ id: meta.prefix + '-2024-0' + (500 + arr.length + 1), area: v.area || 'NGP - Area 12', dept: v.dept || 'Operations', date: dDate(v.date), inspector: 'Q-001', status: 'Not Completed', comp: 0, findings: 0, crit: 0, major: 0, minor: 0 }); if (window.__bump) window.__bump(); } });
}
function openMgmtReview() {
  openForm({ title: 'Schedule management review', sub: 'ISO 9001 §9.3', icon: 'calendar', submitLabel: 'Schedule', done: 'Management review scheduled',
    fields: [
      { key: 'title', label: 'Review title', type: 'text', full: true },
      { key: 'date', label: 'Date', type: 'date', half: true },
      { key: 'status', label: 'Status', type: 'select', options: ['Planned', 'In progress', 'Closed'], value: 'Planned', half: true },
    ],
    onSave: (v) => dbAdd('mgmtReviews', { id: _seq(DB.mgmtReviews, 'MR-', 1), title: v.title || 'Management review', date: dDate(v.date), status: v.status || 'Planned' }) });
}
function openDispatchForm() {
  openForm({ title: 'Dispatch field crew', sub: 'Mobile deployment', icon: 'truck', submitLabel: 'Dispatch', done: 'Deployment dispatched to crew tablet',
    fields: [
      { key: 'crew', label: 'Crew', type: 'text', full: true },
      { key: 'location', label: 'Location', type: 'text', half: true },
      { key: 'members', label: 'Members', type: 'number', value: '6', half: true },
    ],
    onSave: (v) => { (DB.fieldOps.deployments || (DB.fieldOps.deployments = [])).unshift({ id: 'DEP-' + (DB.fieldOps.deployments.length + 1), crew: v.crew || 'New crew', location: v.location || 'Field', members: +v.members || 6, equip: '—', status: 'Mobilizing' }); if (window.__bump) window.__bump(); } });
}
function jmpCompute(v) {
  const km = +v.km || 0; const tips = []; let risk = km >= 300 ? 78 : km >= 150 ? 52 : 28;
  if (km >= 300) tips.push({ tone: 'bad', title: 'Long-haul journey', body: km + ' km — mandatory rest stops every 2 h and a co-driver above 500 km; night-driving restrictions apply.' });
  else if (km >= 150) tips.push({ tone: 'warn', title: 'Schedule a rest stop', body: km + ' km — plan a rest stop and confirm fatigue management before departure.' });
  else tips.push({ tone: 'ok', title: 'Within single-driver limits', body: km + ' km — standard journey; confirm the vehicle inspection is valid.' });
  if (v.vehicle) tips.push({ tone: 'info', title: 'Vehicle & driver checks', body: 'Sentinel verifies ' + v.vehicle + ' inspection / insurance validity and driver qualification before approval.' });
  if (v.type === 'Material Delivery') tips.push({ tone: 'warn', title: 'Load securing', body: 'Material delivery — confirm load is secured and within axle limits; dangerous-goods rules if applicable.' });
  tips.push({ tone: 'info', title: 'Live tracking on approval', body: 'On approval the journey is tracked live with check-in points and weather monitoring.' });
  return { tips, risk, riskLabel: 'Journey risk score' };
}
function openJourneyForm(rec) {
  const e = rec || {}; const dn = (id) => { try { return DB.staffById(id).name; } catch (x) { return ''; } };
  window.openAIAssist({ title: rec ? 'Edit ' + e.id : 'New journey plan', sub: 'Journey management · Sentinel scores route & fatigue risk', icon: 'truck', width: 860, compute: jmpCompute, submitLabel: rec ? 'Save changes' : 'Approve journey', done: rec ? 'Journey plan updated' : 'Journey plan created · routed for approval',
    fields: [
      { type: 'section', label: 'Journey plan' },
      { key: 'name', label: 'Journey name / route', type: 'text', value: e.name },
      { key: 'from', label: 'From', type: 'text', value: e.from, half: true },
      { key: 'to', label: 'To', type: 'text', value: e.to, half: true },
      { key: 'type', label: 'Journey type', type: 'select', options: ['Official', 'Inspection', 'Material Delivery', 'Training'], value: e.type || 'Official', half: true },
      { key: 'vehicle', label: 'Vehicle', type: 'select', options: DB.fleetVehicles.slice(0, 8).map((x) => x.id), value: e.vehicle, half: true },
      { key: 'driver', label: 'Driver', type: 'select', options: DB.staff.map((s) => s.name), value: e.driver ? dn(e.driver) : '', half: true },
      { key: 'depart', label: 'Departure date', type: 'date', value: _di(e.depart), half: true },
      { key: 'km', label: 'Distance (km)', type: 'number', value: String(e.km || 120), half: true },
    ],
    onSave: (v) => { const did = (DB.staff.find((s) => s.name === v.driver) || DB.staff[0]).id; return rec ? dbUpdate('journeys', 'id', e.id, { name: v.name, from: v.from, to: v.to, type: v.type, vehicle: v.vehicle, driver: did, depart: dDate(v.depart), km: +v.km }) : dbAdd('journeys', { id: _seq(DB.journeys, 'JRN-2024-00', 48), name: v.name || 'New journey', from: v.from || 'Base', to: v.to || 'Site', depart: dDate(v.depart), vehicle: v.vehicle || DB.fleetVehicles[0].id, driver: did, type: v.type || 'Official', status: 'Planned', km: +v.km || 120, comp: 100 }); } });
}
function App() {
  const [screen, setScreen] = useState('login');
  const [active, setActive] = useState('dashboard');
  const [detail, setDetail] = useState(null);
  const [aiOpen, setAiOpen] = useState(false);
  const [notifOpen, setNotifOpen] = useState(false);
  const [lang, setLang] = useState('en');
  const [aiOffline, setAiOffline] = useState(false);
  const [demoId, setDemoId] = useState('director');
  const [navCollapsed, setNavCollapsed] = useState(false);
  const [, setTick] = useState(0);
  useEffect(() => { window.__bump = () => setTick((t) => t + 1); return () => { window.__bump = null; }; }, []);
  const u = DB.demoUsers.find((x) => x.id === demoId) || DB.demoUsers[0];
  window.LANG = lang; window.AI_OFFLINE = aiOffline; window.DEMO_USER = demoId; window.DEMO_DEPT = u.deptTab || '';
  useEffect(() => { window._openSentinel = () => setAiOpen(true); }, []);
  useEffect(() => { document.documentElement.setAttribute('dir', lang === 'ar' ? 'rtl' : 'ltr'); document.documentElement.setAttribute('lang', lang); return () => document.documentElement.setAttribute('dir', 'ltr'); }, [lang]);
  const navTo = (id) => { setActive(id); setDetail(null); document.querySelector('.content')?.scrollTo(0, 0); };
  const onOpen = (type, data) => { setDetail({ type, data }); document.querySelector('.content')?.scrollTo(0, 0); };
  const switchUser = (id) => { const nu = DB.demoUsers.find((x) => x.id === id); if (!nu) return; setDemoId(id); window.DEMO_USER = id; window.DEMO_DEPT = nu.deptTab || ''; setDetail(null); setActive(nu.landing || 'dashboard'); document.querySelector('.content')?.scrollTo(0, 0); window.toast && window.toast(`Now viewing as ${nu.name} — ${nu.levelName} · ${nu.deptCode} ${nu.level}`, 'info'); };
  const resetDemo = () => { setDemoId('director'); window.DEMO_USER = 'director'; window.DEMO_DEPT = ''; setLang('en'); setAiOffline(false); setDetail(null); setActive('dashboard'); window.toast && window.toast('Demo reset to default user and state', 'ok'); };
  if (screen === 'login') return <QLogin onEnter={(role) => { if (role === 'auditor') { setScreen('auditor'); } else { const du = DB.demoUsers.find((x) => x.id === 'director') || {}; setScreen('app'); setDemoId('director'); window.DEMO_USER = 'director'; window.DEMO_DEPT = du.deptTab || ''; setActive(du.landing || 'depts'); } }} />;
  if (screen === 'auditor') return <AuditorView onLogout={() => setScreen('login')} />;
  const crumb = (DB.nav.flatMap((g) => g.items.flatMap((i) => [i, ...(i.children || [])])).find((i) => i.id === active) || {}).label || 'Dashboard';
  return (
    <div className={`app${navCollapsed ? ' rail' : ''}`}>
      <Sidebar active={active} onNav={navTo} onLogout={() => setScreen('login')} collapsed={navCollapsed} onToggleCollapse={() => setNavCollapsed((c) => !c)} />
      <div className="main">
        <Topbar crumb={crumb} lang={lang} onToggleLang={() => setLang((l) => l === 'ar' ? 'en' : 'ar')} aiOffline={aiOffline} onToggleAI={() => setAiOffline((o) => !o)} onOpenAI={() => setAiOpen(true)} onOpenNotif={() => setNotifOpen(true)} onNav={navTo} onLogout={() => setScreen('login')} onSwitch={switchUser} onReset={resetDemo} />
        {aiOffline && <div style={{ background: 'var(--warn-bg)', borderBottom: '1px solid var(--warn-line)', padding: '7px 24px', fontSize: 12, color: 'var(--warn)', display: 'flex', alignItems: 'center', gap: 8 }}><Icon name="alert" size={13} /><b>Sentinel is offline.</b> <span style={{ color: 'var(--text-2)' }}>All registers, forms, permits and approvals remain fully usable — AI guidance resumes automatically when it reconnects.</span></div>}
        <div className="content">
          {detail ? <DetailHost detail={detail} onBack={() => setDetail(null)} onNav={navTo} /> : <ModuleHost active={active} onNav={navTo} onOpen={onOpen} />}
        </div>
      </div>
      <SentinelDrawer open={aiOpen} onClose={() => setAiOpen(false)} onNav={navTo} />
      <NotifPanel open={notifOpen} onClose={() => setNotifOpen(false)} onNav={navTo} />
      <ToastHost />
      <FormHost />
      <AIAssistHost />
    </div>
  );
}
/* Boot: hydrate window.DB from the Neon-backed API (if available), then render.
   Falls back to the bundled static data when /api/data is unreachable (e.g. local
   preview). ISO date strings are revived to Date objects so DB.fmt/rel keep working. */
function _renderApp() { ReactDOM.createRoot(document.getElementById('root')).render(<App />); }
(function bootAICOS() {
  const reviver = (k, v) => (typeof v === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(v)) ? new Date(v) : v;
  let done = false; const go = () => { if (done) return; done = true; _renderApp(); };
  const timer = setTimeout(go, 4000); // never block render more than 4s
  fetch('/api/data').then((r) => (r.ok ? r.text() : null)).then((t) => {
    if (t) { try { const d = JSON.parse(t, reviver); Object.assign(window.DB, d); window.DB.__source = 'neon'; } catch (e) { /* keep static */ } }
  }).catch(() => { /* keep static */ }).finally(() => { clearTimeout(timer); go(); });
})();
