const {useEffect,useMemo,useState}=React; const NAV=[ {g:'Command',items:[['dashboard','fa-chart-pie','Executive Dashboard'],['projects','fa-folder-tree','Projects']]}, {g:'HSE Assurance',items:[['docs','fa-file-signature','HSE Documents'],['hemp','fa-triangle-exclamation','HEMP / Risk Register'],['mersa','fa-heart-pulse','MERSA'],['nerf','fa-truck-medical','NERF'],['vessel','fa-ship','Vessel Assurance']]}, {g:'Operations',items:[['daily_hse','fa-clipboard-check','Daily HSE'],['simops','fa-tower-observation','SIMOPS'],['incidents','fa-bolt','Incidents'],['actions','fa-list-check','Actions & Close-Out']]}, {g:'Resources',items:[['personnel','fa-users','Personnel'],['equipment','fa-plane-up','UAV & Equipment'],['audit','fa-clock-rotate-left','Audit Trail']]}, {g:'Administration',items:[['client_admin','fa-user-shield','Client Portal']]}, ]; const statusType=(s='')=>{s=s.toLowerCase();if(s.includes('approv')||s.includes('verified')||s.includes('closed')||s.includes('ready')||s.includes('active'))return'safe';if(s.includes('critical')||s.includes('reject')||s.includes('overdue')||s.includes('open incident'))return'crit';if(s.includes('review')||s.includes('progress')||s.includes('conditional'))return'info';if(s.includes('pending')||s.includes('draft')||s.includes('tbc')||s.includes('not started'))return'warn';return'wait'}; const typeClass={safe:'text-status-safe border-status-safe/50 bg-status-safe/10',crit:'text-status-crit border-status-crit/50 bg-status-crit/10',info:'text-status-info border-status-info/50 bg-status-info/10',warn:'text-status-warn border-status-warn/50 bg-status-warn/10',wait:'text-status-wait border-status-wait/50 bg-status-wait/10'}; const Badge=({children,type})=>{children||'—'}; const fmtDate=v=>v?new Date(v.replace(' ','T')).toLocaleDateString('en-MY',{day:'2-digit',month:'short',year:'numeric'}):'—'; const today=()=>new Date().toISOString().slice(0,10); async function api(action,payload,opts={}){ const res=await fetch(`api.php?action=${encodeURIComponent(action)}`,{method:payload?'POST':'GET',headers:payload&&!opts.form?{'Content-Type':'application/json'}:undefined,body:payload?(opts.form?payload:JSON.stringify(payload)):undefined}); let data;try{data=await res.json()}catch{data={ok:false,error:'Invalid server response'}} if(!res.ok||data.ok===false)throw new Error(data.error||`Request failed (${res.status})`);return data; } function IconButton({icon,title,onClick,danger=false}){return } function Card({title,sub,action,children,className=''}){return

{title}

{sub&&

{sub}

}
{action}
{children}
} function KPI({label,value,icon,sub,tone='pgr'}){const bg=tone==='crit'?'bg-status-crit/10 text-status-crit':tone==='warn'?'bg-status-warn/10 text-status-warn':tone==='info'?'bg-status-info/10 text-status-info':'bg-pgr/10 text-pgr';return
{value}
{label}
{sub&&
{sub}
}
} function Modal({title,onClose,children,wide=false}){return
{if(e.target===e.currentTarget)onClose()}}>

{title}

{children}
} function FormModal({title,fields,initial={},onClose,onSave}){ const [form,setForm]=useState({...initial});const [busy,setBusy]=useState(false);const set=(k,v)=>setForm(f=>({...f,[k]:v})); const submit=async e=>{e.preventDefault();setBusy(true);try{await onSave(form);onClose()}finally{setBusy(false)}}; return
{fields.map(f=>
{f.type==='textarea'?