/* =====================================================================
   NOWILLS SQC ERP — Module pack 3
   Finance • Treasury • Budget • Ghana Tax • HSE • Environment •
   Documents • Reports • AI Command Centre • Administration
   ===================================================================== */
(function(){
'use strict';
const D=DATA,K=D.K,ts=D.ts,MON=D.MONTHS,C=Charts.palette;
const H=window.MH, S=H.S, ln=H.ln, ar=H.ar, br=H.br, hb=H.hb, dn=H.dn, pi=H.pi, gg=H.gg, rg=H.rg, wf=H.wf, hm=H.hm, scp=H.scp, fnl=H.fnl, tm=H.tm, item=H.item, fct=H.fct;
const DAYS30=H.DAYS30;
function f(){return (window.NWX&&NWX.scope)?NWX.scope().f:1;}

/* ============================ 21. FINANCE ============================ */
MODULES.finance=function(M){
 const f1=f();
 const cards=[K('Total Revenue',48.2e6,{u:'GHS',tgt:52e6}),K('Cost of Sales',35.3e6,{u:'GHS',good:'down'}),
  K('Gross Profit',12.9e6,{u:'GHS'}),K('Operating Expenses',5.1e6,{u:'GHS',good:'down'}),K('Operating Profit',7.8e6,{u:'GHS'}),
  K('Net Profit',5.3e6,{u:'GHS'}),K('Total Assets',142.6e6,{u:'GHS',neutral:1}),K('Total Liabilities',58.4e6,{u:'GHS',good:'down'}),
  K('Total Equity',84.2e6,{u:'GHS'}),K('Accounts Receivable',17.4e6,{u:'GHS',good:'down'}),K('Accounts Payable',9.8e6,{u:'GHS',good:'down'}),
  K('Cash Balance',2.1e6,{u:'GHS'}),K('Bank Balance',29.5e6,{u:'GHS',neutral:1}),K('Working Capital',22.4e6,{u:'GHS'}),
  K('Current Ratio',1.84,{u:'num',d:2,tgt:1.5}),K('Quick Ratio',1.32,{u:'num',d:2,tgt:1.0}),
  K('Debt-to-Equity',0.41,{u:'num',d:2,good:'down'}),K('Return on Assets',14.8,{u:'%',d:1}),K('Return on Equity',21.2,{u:'%',d:1}),
  K('EBITDA',11.4e6,{u:'GHS'}),K('Budget Variance',-3.2,{u:'%',good:'up',d:1,st:'amber'}),K('Unposted Journals',4,{u:'#',good:'down',d:0}),
  K('Suspense Balance',18400,{u:'GHS',good:'down'}),K('Control-Account Differences',0,{u:'GHS',good:'down',st:'green',d:0})];
 const secs=[
  {k:'html',id:'finstate',ti:'Financial Statement Summary — links open full statements',cls:'wide'},
  {k:'chart',id:'frp',ti:'Revenue & Profit Trend',cls:'wide',spec:ln(MON,[S('Revenue',fct(ts(12,4.0e6,.06,.008,'frp1'),f1),C[0],{area:true}),S('Gross profit',fct(ts(12,1.1e6,.08,.01,'frp2'),f1),C[2]),S('Net profit',fct(ts(12,0.44e6,.1,.012,'frp3'),f1),C[1])],{fmt:'money',height:290,drillDim:'GL 4xxx–7xxx'})},
  {k:'chart',id:'plcmp',ti:'P&L — This Year vs Last Year (₵M)',spec:br(['Revenue','COGS','Gross P.','Opex','EBITDA','Net P.'],[S('FY2026',fct([48.2,35.3,12.9,5.1,11.4,5.3],1e6),C[0]),S('FY2025',fct([41.6,30.9,10.7,4.8,9.4,4.1],1e6),C[8])],{fmt:'money'})},
  {k:'chart',id:'avl',ti:'Assets vs Liabilities (₵M)',spec:br(['Current','Fixed','AR','Inventory','Payables','Loans'],[S('Assets',fct([31.6,86.2,17.4,6.9,0,0],1e6),C[2]),S('Liabilities',fct([0,0,0,0,9.8,18.4],1e6),C[6])],{fmt:'money'})},
  {k:'chart',id:'fcf',ti:'Cash-Flow Trend',spec:wf([{label:'Opening cash',value:Math.round(21.4e6*f1),type:'abs'},{label:'Operations',value:Math.round(6.2e6*f1),type:'delta'},{label:'Working cap.',value:Math.round(-2.1e6*f1),type:'delta'},{label:'CAPEX',value:Math.round(-1.8e6*f1),type:'delta'},{label:'Financing',value:Math.round(1.1e6*f1),type:'delta'},{label:'Closing cash',value:Math.round(24.8e6*f1),type:'total'}],{fmt:'money',height:280})},
  {k:'chart',id:'ara',ti:'AR Aging (₵M)',spec:br(['Current','1–30d','31–60d','61–90d','>90d'],[S('₵',fct([8.9,4.2,2.3,1.2,0.8],1e6),C[1])],{fmt:'money'})},
  {k:'chart',id:'apa',ti:'AP Aging (₵M)',spec:br(['Current','1–30d','31–60d','61–90d','>90d'],[S('₵',fct([6.1,2.1,0.9,0.4,0.3],1e6),C[4])],{fmt:'money'})},
  {k:'chart',id:'bva',ti:'Budget vs Actual (₵/month)',spec:br(MON.slice(0,8),[S('Budget',fct(ts(8,4.3e6,.04,0,'bva1'),f1),C[8]),S('Actual',fct(ts(8,4.4e6,.05,0,'bva2'),f1),C[0])],{fmt:'money'})},
  {k:'chart',id:'edx',ti:'Expense Distribution',spec:tm([item('Materials',Math.round(11.2e6*f1),C[0]),item('Labour',Math.round(6.8e6*f1),C[1]),item('Fuel',Math.round(5.6e6*f1),C[4]),item('Equipment',Math.round(4.9e6*f1),C[3]),item('Subcontractors',Math.round(3.4e6*f1),C[6]),item('Maintenance',Math.round(2.2e6*f1),C[5]),item('Transport',Math.round(1.8e6*f1),C[8]),item('Admin',Math.round(2.4e6*f1),C[9])],{fmt:'money',height:280})},
  {k:'chart',id:'frt',ti:'Financial-Ratio Trend (%)',spec:ln(MON,[S('ROE',ts(12,20,.05,.005,'frt1'),C[0]),S('ROA',ts(12,14,.05,.004,'frt2'),C[1]),S('Net margin',ts(12,10.6,.05,.004,'frt3'),C[2])],{fmt:'pct'})},
  {k:'chart',id:'ccp',ti:'Cost-Centre Performance (variance %)',spec:hb(D.COSTC,[S('Variance %',[2.1,-3.4,1.2,-1.1,4.6,-0.8],C[4])],{fmt:'pct'})},
  {k:'chart',id:'pcp',ti:'Profit-Centre Performance (GP ₵M)',spec:hb(['Quarry Ops','Construction','Haulage','Equipment Hire','Materials'],[S('GP',fct([5.9,4.1,1.1,0.9,0.9],1e6),C[2])],{fmt:'money'})},
  {k:'chart',id:'pqp',ti:'Quarry Profitability (GP ₵M MTD)',spec:hb(['Shai Hills','Buoho','Nsawam South'],[S('GP',fct([3.4,1.9,0.6],1e6),C[0])],{fmt:'money'})},
  {k:'table',id:'jrn',ti:'Journal & Control Exceptions',cls:'wide',cfg:{id:'jrn',page:8,cols:[{k:'a',l:'Ref'},{k:'b',l:'Type'},{k:'c',l:'Entity'},{k:'d',l:'Amount',y:'money'},{k:'e',l:'Raised by'},{k:'f',l:'Age (d)',y:'num'},{k:'g',l:'Status',y:'badge'}],rows:[
   {a:'JV-26-0912',b:'Accrual — fuel',c:'NQL',d:486200,e:'R. Asante',f:2,g:'blue',gL:'Unposted'},
   {a:'JV-26-0908',b:'Reclass Dep->Opex',c:'NHL',d:98400,e:'F. Darko',f:4,g:'blue',gL:'Unposted'},
   {a:'JV-26-0899',b:'Suspense — Ecobank',c:'NCL',d:18400,e:'System',f:7,g:'amber',gL:'Open'},
   {a:'JV-26-0894',b:'FX revaluation USD',c:'NCL',d:66210,e:'System',f:9,g:'green',gL:'Posted'},
   {a:'JV-26-0891',b:'Provision — LTI levy',c:'Group',d:121000,e:'R. Asante',f:12,g:'green',gL:'Posted'}]}}
 ];
 return {title:'finance',sub:'IFRS-led • GL-reconciled • real-time close',cards:cards,sections:secs};
};

/* ============================ 22. TREASURY ============================ */
MODULES.treasury=function(M){
 const f1=f();
 const cards=[K('Total Cash',2.1e6,{u:'GHS'}),K('Total Bank Balance',29.5e6,{u:'GHS'}),K('Mobile Money Balance',0.6e6,{u:'GHS'}),
  K('Petty Cash',38e3,{u:'GHS'}),K('Receipts Today',1.86e6,{u:'GHS'}),K('Payments Today',1.42e6,{u:'GHS',good:'down'}),
  K('Bank Deposits Today',1.2e6,{u:'GHS'}),K('Withdrawals Today',0.9e6,{u:'GHS',good:'down'}),K('Transfers Today',0.4e6,{u:'GHS'}),
  K('Unreconciled Items',23,{u:'#',good:'down',d:0}),K('Outstanding Cheques',0.44e6,{u:'GHS',good:'down'}),K('Deposits in Transit',0.9e6,{u:'GHS'}),
  K('Available Liquidity',31.6e6,{u:'GHS'}),K('Weekly Cash Requirement',5.6e6,{u:'GHS'}),K('Monthly Cash Requirement',21.4e6,{u:'GHS'}),
  K('Loans Outstanding',18.4e6,{u:'GHS',good:'down'}),K('Investments',6.2e6,{u:'GHS'}),K('Interest Expense (MTD)',212e3,{u:'GHS',good:'down'}),
  K('Bank Charges (MTD)',18.4e3,{u:'GHS',good:'down'})];
 const secs=[
  {k:'chart',id:'dcp',ti:'Daily Cash Position (₵)',cls:'wide',spec:ln(DAYS30,[S('Closing position',fct(ts(30,31.4e6,.02,.004,'dcp'),f1),C[0],{area:true})],{fmt:'money',zoom:true,height:280})},
  {k:'chart',id:'bbt',ti:'Cash Inflow vs Outflow (₵/day)',spec:br(DAYS30.slice(-14),[S('Inflows',fct(ts(14,1.7e6,.15,0,'cio1'),f1),C[2]),S('Outflows',fct(ts(14,1.5e6,.15,0,'cio2'),f1),C[6])],{fmt:'money'})},
  {k:'chart',id:'lf',ti:'13-Week Liquidity Forecast',spec:ln(['W33','W34','W35','W36','W37','W38','W39','W40','W41','W42','W43','W44','W45'],[S('Forecast position',fct([31.6,33.1,30.8,26.2,28.9,31.2,33.8,31.4,29.2,32.8,35.1,36.4,38.2],1e6),C[1],{area:true}),S('Minimum covenant',Array(13).fill(20e6),C[6],{dash:true})],{fmt:'money'})},
  {k:'chart',id:'brs',ti:'Bank-Reconciliation Status (%)',spec:hb(['GCB HQ','Ecobank Ops','Stanbic Projects','Absa Payroll','CalBank USD','MoMo Float'],[S('Matched %',[99.2,96.1,98.4,99.8,100,94.2],C[2])],{fmt:'pct'})},
  {k:'chart',id:'cbb',ti:'Cash by Bank (₵M)',spec:dn([item('GCB Bank',Math.round(9.8e6*f1),C[0]),item('Ecobank',Math.round(7.2e6*f1),C[1]),item('Stanbic',Math.round(6.4e6*f1),C[2]),item('Absa',Math.round(3.1e6*f1),C[3]),item('CalBank',Math.round(2.4e6*f1),C[4]),item('MoMo float',Math.round(0.6e6*f1),C[5])],{fmt:'money',center:'Banks'})},
  {k:'chart',id:'cbc',ti:'Cash by Company (₵M)',spec:dn([item('Nowills Quarry',Math.round(14.2e6*f1),C[0]),item('Nowills Construction',Math.round(12.1e6*f1),C[1]),item('Haulage',Math.round(3.2e6*f1),C[3]),item('Equipment Hire',Math.round(2.1e6*f1),C[4])],{fmt:'money',center:'Group'})},
  {k:'chart',id:'mmt',ti:'Mobile Money Trend (₵/day)',spec:ar(DAYS30.slice(-14),[S('₵',fct(ts(14,92e3,.3,0,'mmt'),f1),C[3],{area:true})],{fmt:'money'})},
  {k:'chart',id:'lrt',ti:'Loan-Repayment Trend (₵/month)',spec:br(MON,[S('Principal',fct(ts(12,410e3,.02,0,'lrt1'),f1),C[0]),S('Interest',fct(ts(12,212e3,.02,-.008,'lrt2'),f1),C[6])],{fmt:'money',stacked:true})},
  {k:'chart',id:'ict',ti:'Interest-Cost Trend (₵)',spec:ln(MON,[S('₵/month',fct(ts(12,224e3,.04,-.02,'ict'),f1),C[4])],{fmt:'money'})},
  {k:'chart',id:'cex',ti:'Currency Exposure',spec:pi([item('GHS',Math.round(24.1e6*f1),C[0]),item('USD',Math.round(4.2e6*f1),C[1]),item('EUR',Math.round(2.4e6*f1),C[3]),item('GBP',Math.round(0.9e6*f1),C[4])],{fmt:'money'})},
  {k:'table',id:'brec',ti:'Unreconciled Bank Items',cls:'wide',cfg:{id:'brec',page:9,cols:[{k:'a',l:'Bank'},{k:'b',l:'Ref'},{k:'c',l:'Date',y:'date'},{k:'d',l:'Description'},{k:'e',l:'Amount',y:'money'},{k:'f',l:'Age (d)',y:'num'},{k:'g',l:'Match %',y:'pct'},{k:'h',l:'Status',y:'badge'}],rows:bankRows(),totals:['e']}}
 ];
 return {title:'treasury',sub:'Liquidity • recs • FX • facilities',cards:cards,sections:secs};
};
function bankRows(){const r=D.mulberry(131);const banks=['GCB HQ','Ecobank Ops','Stanbic Projects','Absa Payroll'];
 return Array.from({length:9},(_,i)=>({a:banks[i%4],b:'BNK-'+(77210-i*13),c:'2026-08-0'+(1+i),d:['Customer deposit — unmatched','Bank charge not in GL','Cheque 000441 not presented','MoMo settlement batch','Standing order — genset lease'][i%5],e:Math.round((18+r()*220)*1e3),f:1+i*2,g:Math.round(40+r()*55),h:i%3?'amber':'red',hL:i%3?'Matching':'Manual review'}));}

/* ============================ 23. BUDGET ============================ */
MODULES.budget=function(M){
 const f1=f();
 const cards=[K('Approved Budget (FY)',118.2e6,{u:'GHS',neutral:1}),K('Revised Budget',121.4e6,{u:'GHS'}),
  K('Actual Expenditure YTD',68.9e6,{u:'GHS'}),K('Committed Cost',11.4e6,{u:'GHS'}),K('Available Budget',41.1e6,{u:'GHS'}),
  K('Budget Utilization',58.3,{u:'%',d:1}),K('Revenue Budget',152e6,{u:'GHS'}),K('Actual Revenue',96.4e6,{u:'GHS'}),
  K('OPEX Budget',46.8e6,{u:'GHS'}),K('OPEX Actual',28.9e6,{u:'GHS',good:'down'}),K('CAPEX Budget',22.4e6,{u:'GHS'}),
  K('CAPEX Actual',11.8e6,{u:'GHS'}),K('Projects Over Budget',1,{u:'#',good:'down',d:0}),K('Cost Centres Over Budget',2,{u:'#',good:'down',d:0}),
  K('Forecast Revenue',154.2e6,{u:'GHS'}),K('Forecast Expenses',119.8e6,{u:'GHS'}),K('Forecast Profit',20.1e6,{u:'GHS'}),
  K('Forecast Cash (Dec)',38.2e6,{u:'GHS'})];
 const secs=[
  {k:'chart',id:'bva2',ti:'Budget vs Actual (cumulative ₵M)',cls:'wide',spec:ln(MON,[S('Budget',fct(ts(12,58e6,.01,.05,'bv1'),f1),C[8],{dash:true}),S('Actual',fct(ts(12,56e6,.03,.05,'bv2'),f1),C[0],{area:true}),S('Committed',fct(ts(12,8e6,.06,.04,'bv3'),f1),C[3])],{fmt:'money',height:280})},
  {k:'chart',id:'bvf',ti:'Budget vs Forecast (₵M)',spec:br(['Revenue','COGS','Opex','CAPEX','Profit'],[S('Budget',fct([152,96,46.8,22.4,19.6],1e6),C[8]),S('Forecast',fct([154.2,98.1,47.9,21.1,20.1],1e6),C[1])],{fmt:'money'})},
  {k:'chart',id:'rv',ti:'Revenue Variance (₵M/month)',spec:br(MON.slice(0,8),[S('Fav/(Adverse)',fct([0.8,-0.4,1.1,0.2,-0.9,1.4,0.6,1.1],1e6),C[2])],{fmt:'money'})},
  {k:'chart',id:'ev',ti:'Expense Variance (₵M/month)',spec:br(MON.slice(0,8),[S('(Over)/Under',fct([-0.2,0.3,-0.6,0.1,-0.4,-0.8,0.2,-0.5],1e6),C[6])],{fmt:'money'})},
  {k:'chart',id:'cxu',ti:'CAPEX Utilization (₵M)',spec:br(['Plant','Vehicles','Crushers','IT & Systems','Buildings'],[S('Budget',fct([8.2,6.4,4.1,1.9,1.8],1e6),C[8]),S('Actual',fct([4.6,3.8,2.2,0.6,0.6],1e6),C[0])],{fmt:'money'})},
  {k:'chart',id:'oxu',ti:'OPEX Utilization (%)',spec:hb(D.DEPTS.slice(0,7),[S('% used',[71,64,68,58,52,61,49],C[4])],{fmt:'pct'})},
  {k:'chart',id:'dv',ti:'Departmental Variance (%)',spec:hb(D.DEPTS.slice(0,7),[S('Δ%',[2.1,-3.4,1.2,-1.1,4.6,-0.8,1.9],C[3])],{fmt:'pct'})},
  {k:'chart',id:'pbp',ti:'Project Budget Performance (₵M)',spec:br(D.PROJECTS.map(p=>p.id),[S('Budget',D.PROJECTS.map(p=>Math.round(p.bud/1e5)/10),C[8]),S('Actual+Commit',D.PROJECTS.map(p=>Math.round((p.cost+p.comm)/1e5)/10),C[0])],{fmt:'num'})},
  {k:'chart',id:'qbp',ti:'Quarry Budget Performance (₵M)',spec:br(['Shai Hills','Buoho','Nsawam South'],[S('Budget',fct([18.2,11.4,6.2],1e6),C[8]),S('Actual',fct([17.1,10.9,5.1],1e6),C[0])],{fmt:'money'})},
  {k:'chart',id:'cff',ti:'Cash-Flow Forecast (₵M)',spec:ln(['Sep','Oct','Nov','Dec'],[S('Inflows',fct([16.1,17.4,18.9,21.2],1e6),C[2]),S('Outflows',fct([15.2,16.1,17.4,19.1],1e6),C[6])],{fmt:'money'})},
  {k:'chart',id:'scn',ti:'Scenario Comparison — FY profit (₵M)',spec:br(['Conservative','Base case','Optimistic','Blast delay -2wk','Diesel +15%'],[S('FY profit',[16.4,20.1,23.8,18.6,18.1],C[5])],{fmt:'num'})},
  {k:'chart',id:'fac',ti:'Forecast Accuracy (MAPE %)',spec:ln(MON,[S('MAPE',ts(12,8.2,.2,-.03,'fac'),C[1])],{fmt:'pct',min:0,max:16})},
  {k:'table',id:'brq',ti:'Budget Transfer / Supplement Requests',cls:'wide',cfg:{id:'brq',page:8,cols:[{k:'a',l:'Ref'},{k:'b',l:'From'},{k:'c',l:'To'},{k:'d',l:'Amount',y:'money'},{k:'e',l:'Reason'},{k:'f',l:'Owner'},{k:'g',l:'Status',y:'select',opts:['Draft','Submitted','Approved','Rejected']}],rows:[
   {a:'BT-26-044',b:'CC-600 Admin',c:'CC-200 Crushing',d:180000,e:'Wear parts escalation',f:'E. Osei',g:'Submitted'},
   {a:'BT-26-041',b:'CC-400 Fleet',c:'CC-500 Maintenance',d:95000,e:'Premature tyre failures',f:'Y. Oduro',g:'Approved'},
   {a:'BT-26-038',b:'Contingency',c:'P-2226',d:240000,e:'Slope stabilisation VO',f:'D. Amoah',g:'Submitted'},
   {a:'BT-26-031',b:'CC-100 Quarry',c:'CC-300 Projects',d:60000,e:'Drill rig hire shortfall',f:'K. Boateng',g:'Rejected'}]}}
 ];
 return {title:'budget',sub:'Plans • commitments • scenarios • accuracy',cards:cards,sections:secs};
};

/* ============================ 24. GHANA TAX ============================ */
MODULES.tax=function(M){
 const f1=f();
 const cards=[K('Output VAT (MTD)',2.42e6,{u:'GHS'}),K('Input VAT (MTD)',1.19e6,{u:'GHS',good:'down'}),K('Net VAT Payable',1.23e6,{u:'GHS'}),
  K('NHIL Payable',404e3,{u:'GHS'}),K('GETFund Levy Payable',404e3,{u:'GHS'}),K('Withholding Tax Payable',312e3,{u:'GHS'}),
  K('PAYE Payable',498e3,{u:'GHS'}),K('SSNIT Payable',312e3,{u:'GHS'}),K('Tier 2 Pension Payable',214e3,{u:'GHS'}),
  K('Corporate Tax Provision',1.32e6,{u:'GHS'}),K('Deferred Tax Asset',0.4e6,{u:'GHS'}),K('Deferred Tax Liability',1.1e6,{u:'GHS'}),
  K('Quarry Royalties (5%)',586e3,{u:'GHS'}),K('Returns Due (30d)',6,{u:'#',d:0,good:'down'}),K('Payments Due',9,{u:'#',d:0}),
  K('Overdue Tax Payments',0,{u:'#',good:'down',d:0,st:'green'}),K('E-Invoices Issued',1412,{u:'#',d:0}),K('Rejected E-Invoices',39,{u:'#',good:'down',d:0}),
  K('Reconciliation Differences',12400,{u:'GHS',good:'down'}),K('Compliance Score',96,{u:'%',tgt:95,st:'green'})];
 const secs=[
  {k:'chart',id:'mtl',ti:'Monthly Statutory Liability (₵)',cls:'wide',spec:br(MON,[S('VAT+levies',fct(ts(12,2.02e6,.07,.005,'mtl1'),f1),C[0]),S('PAYE',fct(ts(12,0.48e6,.05,.006,'mtl2'),f1),C[1]),S('SSNIT+Tier2',fct(ts(12,0.52e6,.04,.006,'mtl3'),f1),C[3]),S('WHT',fct(ts(12,0.3e6,.09,0,'mtl4'),f1),C[4]),S('Royalties',fct(ts(12,0.58e6,.07,.005,'mtl5'),f1),C[6])],{fmt:'money',stacked:true,height:290})},
  {k:'chart',id:'voi',ti:'VAT — Output vs Input (₵)',spec:ln(MON,[S('Output VAT',fct(ts(12,2.3e6,.07,.005,'voi1'),f1),C[0]),S('Input VAT',fct(ts(12,1.14e6,.09,.004,'voi2'),f1),C[1])],{fmt:'money'})},
  {k:'chart',id:'pyt',ti:'PAYE Trend (₵)',spec:ar(MON,[S('PAYE',fct(ts(12,0.46e6,.05,.008,'pyt'),f1),C[3],{area:true})],{fmt:'money'})},
  {k:'chart',id:'snt',ti:'SSNIT Trend (₵)',spec:ar(MON,[S('SSNIT 18.5%',fct(ts(12,0.3e6,.05,.008,'snt'),f1),C[4],{area:true})],{fmt:'money'})},
  {k:'chart',id:'wtt',ti:'Withholding-Tax Trend (₵)',spec:br(MON.slice(0,8),[S('WHT',fct(ts(8,0.29e6,.1,0,'wtt'),f1),C[5])],{fmt:'money'})},
  {k:'chart',id:'ctt',ti:'Corporate Tax — quarterly instalments (₵)',spec:br(['Q1','Q2','Q3','Q4'],[S('Provision',fct([1.18,1.32,1.41,1.5],1e6),C[0]),S('Paid',fct([1.18,1.32,0,0],1e6),C[2])],{fmt:'money'})},
  {k:'chart',id:'ryt',ti:'Mineral Royalty Trend (₵)',spec:ln(MON,[S('5% of quarry revenue',fct(ts(12,0.55e6,.07,.005,'ryt'),f1),C[6])],{fmt:'money'})},
  {k:'chart',id:'txp',ti:'Tax Payments (₵/month)',spec:br(MON.slice(0,8),[S('Paid',fct(ts(8,3.6e6,.08,.005,'txp'),f1),C[2])],{fmt:'money'})},
  {k:'chart',id:'eia',ti:'E-Invoice Acceptance Rate (%)',spec:ln(DAYS30.slice(-14),[S('Accepted %',ts(14,97.4,.015,-.002,'eia'),C[1])],{fmt:'pct',min:93,max:100,target:{value:99,label:'GRA target'}})},
  {k:'chart',id:'try',ti:'Tax-Risk Distribution',spec:dn([item('Low',26,C[2]),item('Medium',7,C[4]),item('High',2,C[6])],{fmt:'num',center:'Risks'})},
  {k:'html',id:'taxcal',ti:'Filing Calendar — next 45 days',cls:'wide'},
  {k:'table',id:'txr',ti:'Statutory Rate Table (effective-dated, configurable)',cls:'wide',cfg:{id:'txr',page:14,cols:[{k:'a',l:'Levy / Tax'},{k:'b',l:'Rate'},{k:'c',l:'Effective from',y:'date'},{k:'d',l:'Authority'},{k:'e',l:'Status',y:'badge'}],rows:D.TAXRATES.map(t=>({a:t[0],b:t[1],c:t[2],d:t[3],e:'green',eL:t[4][0].toUpperCase()+t[4].slice(1)})),addRow:{label:'+ Add effective-dated rate',form:[['Levy / Tax','text'],['Rate','text'],['Effective from','date'],['Authority','text']]}}}
 ]
 return {title:'tax',sub:'GRA e-VAT • levies • pensions • royalties',cards:cards,sections:secs};
};

/* ============================ 25. HSE ============================ */
MODULES.hse=function(M){
 const cards=[K('Safety Incidents (MTD)',8,{u:'#',good:'down',d:0}),K('Accidents',1,{u:'#',good:'down',d:0}),
  K('Near Misses',5,{u:'#',d:0}),K('Lost-Time Injuries',1,{u:'#',good:'down',d:0}),K('Fatalities',0,{u:'#',d:0,st:'green'}),
  K('First-Aid Cases',2,{u:'#',d:0}),K('Open Corrective Actions',11,{u:'#',good:'down',d:0}),K('Overdue Corrective Actions',5,{u:'#',good:'down',d:0,st:'red'}),
  K('Safety Inspections (MTD)',26,{u:'#',d:0,tgt:24}),K('Toolbox Meetings (wk)',12,{u:'#',d:0,tgt:12}),
  K('PPE Compliance',94,{u:'%',tgt:95}),K('Safety Training Compliance',93,{u:'%',tgt:95}),K('Permit-to-Work Compliance',98,{u:'%',tgt:98}),
  K('Days without LTI',42,{u:'#',d:0,info:'Group-wide'}),K('HSE Compliance Score',91,{u:'%',tgt:92})];
 const secs=[
  {k:'html',id:'safemap',ti:'Shai Hills Site — Safety & Risk Map',cls:'wide'},
  {k:'chart',id:'it',ti:'Incident Trend (12 months)',cls:'wide',spec:ln(MON,[S('Incidents',ts(12,7,.4,-.04,'it1'),C[6]),S('Near misses',ts(12,9,.3,-.03,'it2'),C[4]),S('First aid',ts(12,3,.4,-.02,'it3'),C[1])],{fmt:'num',min:0,height:280})},
  {k:'chart',id:'ibs',ti:'Incidents by Site',spec:hb(['Shai Hills','Buoho','Nsawam','P-2201','P-2210','Haulage'],[S('YTD',[21,14,9,12,11,7],C[6])],{fmt:'num'})},
  {k:'chart',id:'ibd',ti:'Incidents by Department',spec:dn([item('Quarry Ops',32,C[6]),item('Crushing',18,C[4]),item('Projects',23,C[0]),item('Fleet',11,C[1]),item('Workshops',7,C[3])],{fmt:'num',center:'YTD'})},
  {k:'chart',id:'isev',ti:'Incident Severity',spec:pi([item('Minor',54,C[2]),item('Moderate',21,C[4]),item('Major',4,C[6]),item('Reportable (GRA/MinCom)',2,C[8])],{fmt:'num'})},
  {k:'chart',id:'rcd',ti:'Root-Cause Distribution',spec:hb(['Behaviour','Housekeeping','Equipment','Procedure','Environment','PPE'],[S('Count',[26,18,14,11,8,6],C[3])],{fmt:'num'})},
  {k:'chart',id:'cac',ti:'Corrective-Action Completion (%)',spec:ln(MON,[S('Closed on time %',ts(12,82,.05,.008,'cac'),C[2],{area:true})],{fmt:'pct',min:60,max:100})},
  {k:'chart',id:'ppe',ti:'PPE Compliance by Site (%)',spec:hb(['Shai Hills','Buoho','Nsawam','P-2201','P-2210'],[S('%',[96,93,91,95,94],C[2])],{fmt:'pct'})},
  {k:'chart',id:'stc',ti:'Training Completion by Topic (%)',spec:hb(['Blast safety','Working at height','LOTO','Fire watch','First aid','Defensive driving'],[S('%',[98,92,96,90,84,88],C[1])],{fmt:'pct'})},
  {k:'chart',id:'lti',ti:'LTIFR & TRIR (per 200k hrs)',spec:ln(['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug'],[S('LTIFR',[1.8,1.4,1.1,0.9,1.2,0.7,0.6,0.82],C[6]),S('TRIR',[4.2,3.8,3.1,2.9,2.6,2.4,2.2,2.31],C[4])],{fmt:'num',min:0})},
  {k:'table',id:'hset',ti:'Incident Register',cls:'wide',cfg:{id:'hset',page:9,search:1,cols:[{k:'a',l:'Ref'},{k:'b',l:'Date',y:'date'},{k:'c',l:'Site'},{k:'d',l:'Type',y:'badge'},{k:'e',l:'Severity',y:'badge'},{k:'f',l:'Description'},{k:'g',l:'Injured'},{k:'h',l:'Corrective actions',y:'num'},{k:'i',l:'Status',y:'select',opts:['Open','Investigating','Corrective action','Closed']}],rows:incRows()}}
 ];
 return {title:'hse',sub:'Zero-harm • LTIFR • permit control',cards:cards,sections:secs};
};
function incRows(){const types=[['amber','Near-miss'],['red','LTI'],['blue','First aid'],['amber','Property damage'],['red','Dangerous occurrence']];const sev=[['green','Minor'],['amber','Moderate'],['red','Major']];
 const r=D.mulberry(141);return Array.from({length:12},(_,i)=>{const t=types[i%5],s=sev[(i*2)%3];
  return {a:'INC-26-0'+(412-i),b:'2026-08-0'+(10-(i%9)),c:['Shai Hills','Buoho','P-2210','Nsawam','Haulage'][i%5],d:t[0],dL:t[1],e:s[0],eL:s[1],f:['LV entered blast exclusion zone','Hand injury — pinch point','Hydraulic hose burst on EX-060','Dust mask non-compliance','Falling object from bench crest','Fuel spill at bowser 2'][i%6],g:i%6===1?'1 operator':'—',h:1+(i%4),i:['Open','Investigating','Corrective action','Closed'][i%4]};});}

/* ============================ 26. ENVIRONMENTAL ============================ */
MODULES.env=function(M){
 const f1=f();
 const cards=[K('Dust PM10 (max today)',78,{u:'num',good:'down',st:'red',info:'µg/m³ · limit 70'}),K('Noise (max today)',71,{u:'num',good:'down',info:'dB · limit 75'}),
  K('Vibration PPV',3.1,{u:'num',d:1,good:'down',info:'mm/s · limit 5'}),K('Water-Quality Status','Compliant',{u:'text',st:'green'}),
  K('Air-Quality Status','Breach — Buoho E',{u:'text',st:'red'}),K('Waste Generated (MTD)',184,{u:'t'}),K('Waste Recycled',62,{u:'%',tgt:60}),
  K('Hazardous Waste',1.8,{u:'t',good:'down'}),K('Environmental Incidents',2,{u:'#',good:'down',d:0}),K('Community Complaints',3,{u:'#',good:'down',d:0}),
  K('Rehabilitation Progress',38,{u:'%',d:0,tgt:40}),K('Permit Expiry Alerts',2,{u:'#',good:'down',d:0}),
  K('Compliance Score',92.4,{u:'%',tgt:95,d:1}),K('Carbon Emissions (MTD)',312,{u:'num',info:'tCO₂e',good:'down'}),
  K('Energy Consumption',148e3,{u:'num',info:'kWh MTD'}),K('Water Consumption',2140,{u:'num',info:'m³ MTD',good:'down'})];
 const secs=[
  {k:'chart',id:'dlt',ti:'Dust PM10 Trend (µg/m³)',cls:'wide',spec:ln(DAYS30,[S('Buoho East',ts(30,58,.18,.004,'dlt1'),C[6]),S('Shai North',ts(30,44,.12,0,'dlt2'),C[0]),S('Nsawam',ts(30,39,.1,0,'dlt3'),C[1])],{fmt:'num',target:{value:70,label:'EPA limit'},zoom:true,ann:[{x:DAYS30[DAYS30.length-1],text:'Breach'}],height:280})},
  {k:'chart',id:'nlt',ti:'Noise Level Trend (dB)',spec:ln(DAYS30.slice(-14),[S('Buoho E',ts(14,68,.06,0,'nlt1'),C[0]),S('Limit',Array(14).fill(75),C[6],{dash:true})],{fmt:'num',min:55,max:85})},
  {k:'chart',id:'vbt',ti:'Blast Vibration PPV (mm/s)',spec:br(['B-118','B-119','B-120','B-121','B-122','B-123','B-124'],[S('PPV',[2.8,3.4,2.1,3.9,4.4,2.6,3.1],C[3])],{fmt:'num',})},
  {k:'chart',id:'wct',ti:'Water Consumption (m³/day)',spec:ar(DAYS30.slice(-14),[S('m³',fct(ts(14,72,.14,0,'wct'),f1),C[1],{area:true})],{fmt:'num'})},
  {k:'chart',id:'ect',ti:'Energy Consumption (kWh/day)',spec:ar(DAYS30.slice(-14),[S('kWh',fct(ts(14,4860,.09,0,'ect'),f1),C[4],{area:true})],{fmt:'num'})},
  {k:'chart',id:'fet',ti:'Fuel Emissions tCO₂e / month',spec:br(MON.slice(0,8),[S('tCO₂e',fct(ts(8,298,.06,0,'fet'),f1),C[8])],{fmt:'num'})},
  {k:'chart',id:'wg',ti:'Waste Generation vs Recycling (t)',spec:br(MON.slice(0,8),[S('Generated',fct(ts(8,178,.08,0,'wg1'),f1),C[6]),S('Recycled',fct(ts(8,108,.1,.02,'wg2'),f1),C[2])],{fmt:'t'})},
  {k:'chart',id:'ei',ti:'Environmental Incidents (12 months)',spec:br(MON,[S('Incidents',ts(12,2.2,.6,-.06,'ei'),C[6])],{fmt:'num',min:0})},
  {k:'chart',id:'rhp',ti:'Rehabilitation Progress (ha)',spec:ln(MON,[S('Completed',ts(12,4.1,.06,.09,'rhp'),C[2],{area:true}),S('Planned',ts(12,4.6,.02,.08,'rhp2'),C[8],{dash:true})],{fmt:'num'})},
  {k:'chart',id:'cct',ti:'Community Complaint Trend',spec:br(MON.slice(0,8),[S('Complaints',[2,4,1,3,2,5,3,3],C[4])],{fmt:'num'})},
  {k:'chart',id:'cbs2',ti:'Compliance by Site (%)',spec:hb(['Shai Hills','Buoho','Nsawam South'],[S('Score',[96,88,93],C[2])],{fmt:'pct'})},
  {k:'table',id:'envp',ti:'Permits & Consents Register',cls:'wide',cfg:{id:'envp',page:9,cols:[{k:'a',l:'Permit'},{k:'b',l:'Authority'},{k:'c',l:'Site'},{k:'d',l:'Issued',y:'date'},{k:'e',l:'Expiry',y:'date'},{k:'f',l:'Days left',y:'num'},{k:'g',l:'Status',y:'badge'}],rows:[
   {a:'EPA Permit BU-2219',b:'EPA Ghana',c:'Buoho',d:'2023-09-01',e:'2026-08-31',f:21,g:'amber',gL:'Renewal filed'},
   {a:'MinCom Operating Permit SH-1108',b:'Minerals Commission',c:'Shai Hills',d:'2024-01-15',e:'2027-01-14',f:158,g:'green',gL:'Valid'},
   {a:'Water Use Permit WR-77',b:'Water Resources Com.',c:'Nsawam',d:'2024-05-20',e:'2026-05-19',f:283?282:282,g:'green',gL:'Valid'},
   {a:'Blasting Permit MC-BL-2210',b:'Minerals Commission',c:'Shai Hills',d:'2026-02-01',e:'2026-10-31',f:82,g:'green',gL:'Valid'},
   {a:'EPA EIA Cert NS-0661',b:'EPA Ghana',c:'Nsawam',d:'2023-06-01',e:'2026-08-12',f:2,g:'red',gL:'Expiry imminent'}]}}
 ];
 return {title:'env',sub:'EPA compliance • dust/noise/vibration • rehab',cards:cards,sections:secs};
};

/* ============================ 27. DOCUMENTS ============================ */
MODULES.docs=function(M){
 const f1=f();
 const cards=[K('Documents Uploaded',4820,{u:'#',d:0,neutral:1}),K('Awaiting Review',18,{u:'#',d:0}),K('Awaiting Approval',24,{u:'#',d:0,good:'down'}),
  K('Expiring (30d)',11,{u:'#',good:'down',d:0}),K('Expired',3,{u:'#',good:'down',d:0}),K('Contracts Expiring',2,{u:'#',good:'down',d:0}),
  K('Licences Expiring',2,{u:'#',good:'down',d:0}),K('Insurance Expiring',1,{u:'#',good:'down',d:0}),K('Permits Expiring',2,{u:'#',good:'down',d:0}),
  K('Outstanding Approvals',24,{u:'#',good:'down',d:0}),K('Overdue Approvals',6,{u:'#',good:'down',d:0,st:'red'}),K('Rejected Requests',4,{u:'#',good:'down',d:0})];
 const secs=[
  {k:'html',id:'apprq',ti:'Approval Queue — act inline or select for bulk action',cls:'wide'},
  {k:'chart',id:'dbc',ti:'Documents by Category',spec:dn([item('Contracts',614,C[0]),item('Certificates',882,C[1]),item('Licences & permits',146,C[2]),item('Invoices',1910,C[3]),item('Drawings',428,C[4]),item('HSE records',512,C[5]),item('HR records',328,C[8])],{fmt:'num',center:'DMS'})},
  {k:'chart',id:'ast',ti:'Approval Status',spec:pi([item('Approved',186,C[2]),item('Pending',24,C[4]),item('Overdue',6,C[6]),item('Rejected',4,C[8])],{fmt:'num'})},
  {k:'chart',id:'att',ti:'Approval Turnaround (days)',spec:ln(MON,[S('Avg days',ts(12,2.8,.2,-.05,'att'),C[4],{area:true})],{fmt:'num'})},
  {k:'chart',id:'edm',ti:'Expiring Documents by Month',spec:br(['Aug','Sep','Oct','Nov','Dec','Jan-27'],[S('Count',[11,9,7,4,6,5],C[4])],{fmt:'num'})},
  {k:'chart',id:'dbp',ti:'Documents by Project / Quarry',spec:hb(['P-2201','P-2210','P-2214','Shai Hills','Buoho','Corporate'],[S('Docs',[612,488,214,390,286,410],C[1])],{fmt:'num'})},
  {k:'chart',id:'rra',ti:'Rejection-Reason Analysis',spec:hb(['Missing backup','Wrong cost centre','Over budget','Duplicate','Policy breach'],[S('Count',[9,6,4,3,2],C[6])],{fmt:'num'})},
  {k:'table',id:'dreg',ti:'Document Register',cls:'wide',cfg:{id:'dreg',page:9,search:1,cols:[{k:'a',l:'Doc №'},{k:'b',l:'Title'},{k:'c',l:'Category'},{k:'d',l:'Entity'},{k:'e',l:'Version'},{k:'f',l:'Uploaded',y:'date'},{k:'g',l:'Owner'},{k:'h',l:'Status',y:'badge'}],rows:docRows()}}
 ];
 return {title:'docs',sub:'Controlled DMS • OCR-indexed • e-sign workflows',cards:cards,sections:secs};
};
function docRows(){const r=D.mulberry(151);const cats=['Contract','Certificate','Licence','Invoice','Drawing','HSE record'];
 return Array.from({length:14},(_,i)=>{const st=i%6===0?['red','Expired']:i%4===0?['amber','Review']:i%3===0?['blue','Awaiting approval']:['green','Approved'];
  return {a:'D-'+(8800-i*7),b:['EPC Contract P-2201 rev3','IPC-141 signed copy','Blasting permit MC-BL-2210','Orica invoice OG-8841','Interchange drawings set C','Toolbox talk minutes wk32','Insurance — fleet GT-4411','EPA monitoring report Jul','Subcontract — rebar fixing','Advance guarantee P-2226','QA lab test 20mm wk31','Employment contract batch 12','Board resolution BR-26-04','Tax clearance certificate'][i],c:cats[i%6],d:['NCL','NQL','NQL','NQL','NCL','NQL','NHL','NQL','NCL','NCL','NCL','NQL','Group','Group'][i],e:'v'+(1+i%3),f:'2026-08-0'+(1+i%9),g:['E. Osei','A. Mensah','K. Boateng','R. Asante'][i%4],h:st[0],hL:st[1]};});}

/* ============================ 28. REPORTS ============================ */
MODULES.reports=function(M){
 const REP=[['Executive pack','Board-ready KPIs, trends & risks','exec'],['Daily quarry production','Shift, bench & plant detail','quarry'],['Drilling & blasting log','Explosives & fragmentation','drill'],['Crusher performance','Hours, yield, downtime','crush'],['Weighbridge audit','Tickets, overrides, voids','weigh'],['Stockpile reconciliation','Physical vs system','stockpile'],['Sales & debtors','Invoices, aging, exposure','sales'],['Customer statements','Per-account transactions','crm'],['Project cost report','Earned value per project','projects'],['BOQ measured works','Item-level certification','contracts'],['IPC tracker','Certification & cash','ipc'],['Site diary pack','Daily reports & photos','site'],['Equipment cost report','Per-unit hourly costing','equip'],['Fleet profitability','Per-vehicle P&L','fleet'],['Fuel reconciliation','Issues vs burn vs book','fuel'],['Maintenance cost report','WO costing & backlog','maint'],['Spend analysis','Supplier & category','proc'],['Stock valuation','FIFO/AVCO valuation','inventory'],['Supplier statements','Balances & disputes','suppliers'],['Payroll register','Earnings & deductions','hr'],['PAYE / SSNIT returns','Statutory filings','tax'],['Trial balance','GL to control a/c','finance'],['P&L by segment','Company × profit centre','finance'],['Balance sheet pack','IFS statements','finance'],['Cash-flow forecast','13-week direct method','treasury'],['Budget vs actual','Variance narrative','budget'],['Tax compliance pack','GRA calendar & filings','tax'],['HSE statistics','LTIFR, TRIR, actions','hse'],['Environmental monitoring','Dust, noise, vibration','env'],['Approval audit trail','Workflow evidence','docs'],['AI forecast pack','Projections & risk scores','ai'],['Security & access','Roles, sessions, devices','admin']];
 const f1=f();
 const cards=[K('Report Library',REP.length,{u:'#',d:0,neutral:1}),K('Generated This Month',212,{u:'#',d:0}),K('Scheduled Subscriptions',34,{u:'#',d:0}),
  K('Board Packs Issued',6,{u:'#',d:0,neutral:1}),K('Avg Generation Time',2.4,{u:'num',d:1,info:'seconds'}),K('Data Freshness','38 s',{u:'text',st:'green'})];
 const secs=[{k:'html',id:'repcat',ti:'Report Catalogue — run, schedule or export',cls:'wide'},
  {k:'chart',id:'rgt',ti:'Reports Generated (per month)',spec:br(MON.slice(0,8),[S('Reports',fct(ts(8,196,.1,.02,'rgt'),f1),C[1])],{fmt:'num'})},
  {k:'table',id:'rsch',ti:'Scheduled Deliveries',cls:'wide',cfg:{id:'rsch',page:8,cols:[{k:'a',l:'Report'},{k:'b',l:'Frequency'},{k:'c',l:'Recipients'},{k:'d',l:'Format'},{k:'e',l:'Next run'},{k:'f',l:'Status',y:'badge'}],rows:[
   {a:'Executive pack',b:'Daily 06:00',c:'Board, MD, CFO',d:'PDF + Board pack',e:'2026-08-11 06:00',f:'green',fL:'Active'},
   {a:'Daily quarry production',b:'Daily 22:15',c:'COO, Quarry Managers',d:'PDF + Excel',e:'2026-08-10 22:15',f:'green',fL:'Active'},
   {a:'Cash-flow forecast',b:'Monday 06:30',c:'CFO, Treasurer',d:'Excel',e:'2026-08-11 06:30',f:'green',fL:'Active'},
   {a:'Tax compliance pack',b:'25th monthly',c:'CFO, Chief Accountant',d:'PDF',e:'2026-08-25 07:00',f:'amber',fL:'Retry (SMTP)'},{a:'HSE statistics',b:'Monthly',c:'HSE Committee',d:'PDF',e:'2026-09-01 08:00',f:'green',fL:'Active'}]}}];
 return {title:'reports',sub:'Catalogue • schedules • board packs',cards:cards,sections:secs,catalogue:REP};
};

/* ============================ 29. AI COMMAND CENTRE ============================ */
MODULES.ai=function(M){
 const f1=f();const fc=D.forecast;
 const prod=ts(12,118e3,.07,.006,'aip');
 const cards=[K('High-Risk Projects',3,{u:'#',good:'down',d:0,st:'red'}),K('Production Forecast (Sep)',124200,{u:'t'}),
  K('Sales Forecast (Sep)',2.21e7,{u:'GHS'}),K('Cash-Flow Forecast (13w)',38.2e6,{u:'GHS'}),
  K('Fuel-Theft Risk',34,{u:'num',good:'down',st:'amber',info:'AI score /100'}),K('Equipment-Failure Risk','Crusher A · 6d',{u:'text',st:'amber'}),
  K('Customer Default Risk',2,{u:'#',good:'down',d:0}),K('Supplier Risk',9,{u:'#',good:'down',d:0}),
  K('Inventory Shortage Risk',3,{u:'#',good:'down',d:0}),K('Budget Overrun Risk',2,{u:'#',good:'down',d:0}),
  K('Safety Risk','Moderate',{u:'text',st:'amber'}),K('Environmental Risk','Buoho dust',{u:'text',st:'amber'}),
  K('Tax Compliance Risk','Low',{u:'text',st:'green'}),K('Fraud Alerts',2,{u:'#',good:'down',d:0,st:'red'})];
 const secs=[
  {k:'html',id:'airecs',ti:'AI Recommendations — advisory only, human review required',cls:'wide'},
  {k:'chart',id:'aifp',ti:'Production Forecast (t)',cls:'wide',spec:ln(MON.concat(['Sep*','Oct*','Nov*']),[S('Actual',prod.concat([null,null,null]),C[0],{area:true}),S('Forecast',Array(11).fill(null).concat(prod.slice(-1)).concat(fc(prod,3)),C[1],{dash:true})],{fmt:'t',height:280})},
  {k:'chart',id:'aifs',ti:'Sales Forecast (₵)',spec:ln(MON.concat(['Sep*','Oct*','Nov*']).slice(0,15),[S('Actual',ts(12,1.62e7,.08,.006,'aifs1').concat([null,null,null]),C[0]),S('Forecast',Array(11).fill(null).concat(ts(12,1.62e7,.08,.006,'aifs1').slice(-1)).concat(fc(ts(12,1.62e7,.08,.006,'aifs1'),3)),C[1],{dash:true})],{fmt:'money'})},
  {k:'chart',id:'aifc',ti:'Cash-Flow Forecast (₵M, 13 weeks)',spec:ar(['W33','W34','W35','W36','W37','W38','W39','W40','W41','W42','W43','W44','W45'],[S('AI central',fct([31.6,33.1,30.8,26.2,28.9,31.2,33.8,31.4,29.2,32.8,35.1,36.4,38.2],1e6),C[1],{area:true}),S('Downside P10',fct([31.6,32,29,24,26,28,30,27,25,29,31,32,33],1e6),C[6],{dash:true})],{fmt:'money',min:20e6})},
  {k:'chart',id:'aimd',ti:'Material Demand Forecast (t, next 8 wks)',spec:br(['W33','W34','W35','W36','W37','W38','W39','W40'],[S('20mm',fct(ts(8,9800,.1,.02,'md1'),f1),C[0]),S('14mm',fct(ts(8,7200,.1,.04,'md2'),f1),C[1]),S('10mm',fct(ts(8,4100,.09,.06,'md3'),f1),C[3])],{fmt:'t',stacked:true})},
  {k:'chart',id:'aief',ti:'Equipment-Failure Probability (%)',spec:hb(['Crusher A','EX-060','TRK-1407','LD-122','CR-903','GN-202'],[S('P(fail ≤14d)',[78,64,58,41,33,29],C[6])],{fmt:'pct'})},
  {k:'chart',id:'aiop',ti:'Project-Overrun Probability (%)',spec:hb(D.PROJECTS.map(p=>p.id),[S('P(overrun)',[22,58,9,31,12,64,71],C[4])],{fmt:'pct'})},
  {k:'chart',id:'aicc',ti:'Customer-Credit Risk (score)',spec:scp(D.CLIENTS.map((c,i)=>({x:Math.round(10+i*9),y:[22,14,31,9,18,26,44,68,12,37][i],label:c,r:7,c:[22,14,31,9,18,26,44,68,12,37][i]>50?'#ef4444':[22,14,31,9,18,26,44,68,12,37][i]>30?'#f59e0b':'#22c55e'})),{xl:'Exposure rank',yl:'Default score /100',refY:50})},
  {k:'chart',id:'aift',ti:'Fuel-Anomaly Trend (flags/wk)',spec:br(['W24','W25','W26','W27','W28','W29','W30','W31','W32'],[S('Anomaly flags',[1,0,2,1,1,2,1,4,3],C[6])],{fmt:'num'})},
  {k:'chart',id:'aiil',ti:'Inventory-Loss Risk by Warehouse (score)',spec:hb(['WH-1 HQ','WH-2 Shai','WH-3 Buoho','Tema Yard','Magazine'],[S('Risk score',[62,34,41,28,12],C[4])],{fmt:'num'})},
  {k:'chart',id:'aisr',ti:'Safety-Risk Heatmap (site × hazard)',cls:'wide',spec:hm(['Shai Hills','Buoho','Nsawam','P-2201','P-2210'],['Blast','Mobile plant','Work at height','Confined space','Public interface'],[[4,3,2,1,3],[3,3,1,1,2],[2,2,1,1,2],[1,2,4,3,4],[1,3,3,2,5]],{dec:0})},
  {k:'chart',id:'aier',ti:'Environmental-Risk Heatmap',spec:hm(['Shai Hills','Buoho','Nsawam'],['Dust','Noise','Vibration','Water','Community'],[[2,3,4,1,2],[5,4,3,2,4],[3,2,3,2,3]],{dec:0})},
  {k:'chart',id:'airm',ti:'Enterprise Risk Matrix',cls:'w4',spec:{type:'riskmat',items:D.AI_RISKS,fmt:'num',legend:false,height:330}},
  {k:'table',id:'aiml',ti:'Model Registry & Data Lineage',cls:'wide',cfg:{id:'aiml',page:8,cols:[{k:'a',l:'Model'},{k:'b',l:'Coverage'},{k:'c',l:'Trained on'},{k:'d',l:'MAPE / AUC'},{k:'e',l:'Last run',y:'date'},{k:'f',l:'Status',y:'badge'}],rows:[
   {a:'Production forecaster v3.2',b:'All quarries',c:'24 mo telemetry',d:'MAPE 6.8%',e:'2026-08-10 04:00',f:'green',fL:'Champion'},
   {a:'Cash-flow model v2.8',b:'Group treasury',c:'36 mo bank + AR/AP',d:'MAPE 8.1%',e:'2026-08-10 04:00',f:'green',fL:'Champion'},
   {a:'Equipment-failure v1.9',b:'31 critical assets',c:'CMMS 3 yrs',d:'AUC 0.91',e:'2026-08-10 04:00',f:'green',fL:'Champion'},
   {a:'Fuel-anomaly v1.4',b:'Fleet + tanks',c:'14 mo issues',d:'AUC 0.87',e:'2026-08-10 04:00',f:'amber',fL:'Challenger'},
   {a:'Credit-risk v2.1',b:'236 customers',c:'AR ledger 4 yrs',d:'AUC 0.89',e:'2026-08-09 04:00',f:'green',fL:'Champion'}]}}
 ];
 return {title:'ai',sub:'Explainable forecasts • advisory guardrails',cards:cards,sections:secs};
};

/* ============================ 30. ADMIN ============================ */
MODULES.admin=function(M){
 const cards=[K('Active Users',118,{u:'#',d:0,neutral:1}),K('Roles Defined',28,{u:'#',d:0,neutral:1}),K('Sessions (now)',42,{u:'#',d:0}),
  K('Failed Logins (24h)',6,{u:'#',good:'down',d:0}),K('Audit Events Today',3128,{u:'#',d:0}),K('Sync Queue',0,{u:'#',d:0,st:'green'}),
  K('API Uptime (30d)',99.97,{u:'%',st:'green',d:2}),K('DB Size',412,{u:'num',info:'GB · 38.4M records'})];
 const secs=[
  {k:'html',id:'secset',ti:'Security Posture & Controls',cls:'wide'},
  {k:'table',id:'audit',ti:'Immutable Audit Trail (hash-chained)',cls:'wide',cfg:{id:'audit',page:12,search:1,cols:[{k:'a',l:'When',y:'date'},{k:'b',l:'User'},{k:'c',l:'Role'},{k:'d',l:'Action'},{k:'e',l:'Scope'},{k:'f',l:'Device / IP'},{k:'g',l:'Correlation ID'},{k:'h',l:'Hash'}],rows:(window.NWLOG||[]).slice(-40).reverse()}},
  {k:'table',id:'roles',ti:'Role-Based Access Matrix',cfg:{id:'roles',page:10,search:1,cols:[{k:'a',l:'Role'},{k:'b',l:'Modules',y:'num'},{k:'c',l:'Restrictions'},{k:'d',l:'Users',y:'num'},{k:'e',l:'MFA',y:'badge'}],rows:D.ROLES.map((r,i)=>({a:r.n,b:r.mods.length,c:[r.ro?'Read-only':'',r.mask?'Amounts masked':'',r.qry?'Quarry-scoped':'',r.prj?'Project-scoped':'',r.adm?'Full admin':''].filter(Boolean).join(' · ')||'Full read/write',d:2+(i%9),e:i%7?'green':'amber',eL:i%7?'Enforced':'Pending'}))}},
  {k:'table',id:'sync2',ti:'Offline Synchronization Log',cfg:{id:'sync2',page:8,cols:[{k:'a',l:'Node'},{k:'b',l:'Last sync',y:'date'},{k:'c',l:'Records up',y:'num'},{k:'d',l:'Records down',y:'num'},{k:'e',l:'Conflicts',y:'num'},{k:'f',l:'Status',y:'badge'}],rows:[
   {a:'Shai Hills weighbridge',b:'2026-08-10 08:58',c:214,d:38,e:0,f:'green',fL:'Healthy'},
   {a:'Buoho site node',b:'2026-08-10 08:56',c:96,d:41,e:0,f:'green',fL:'Healthy'},
   {a:'Nsawam mobile units ×6',b:'2026-08-10 08:41',c:57,d:112,e:1,f:'amber',fL:'1 conflict held'},
   {a:'Tema Interchange node',b:'2026-08-09 21:12',c:0,d:0,e:0,f:'red',fL:'Offline 12h'}]}}
 ];
 return {title:'admin',sub:'RBAC/ABAC • audit • sync • tenancy',cards:cards,sections:secs};
};
window.__MH3=1;
})();
