<?php
/* PayrunDashboard.php - Payrun Management Dashboard
   Pattern: PHP-embedded data for main view + AJAX for detail drilldown (original SPA)
   Enhanced: OT insights, allowance breakdowns, gauge charts, radar, polar area
*/
error_reporting(E_ALL & ~E_NOTICE);
$PageSecurity = 0;

include('includes/session.inc');
include('includes/SQL_CommonFunctions.inc');

$Title = _('Payrun Dashboard');
$userid = isset($_SESSION['UserID']) ? $_SESSION['UserID'] : '';
$curYear = date('Y');
$prevYear = $curYear - 1;

/* ================================================================
   API MODE - Detail view AJAX endpoints
   ================================================================ */
if (isset($_GET['api'])) {
    if (ob_get_level() > 0) { ob_end_clean(); }
    header('Content-Type: application/json');
    $api = $_GET['api'];

    if ($api === 'period_kpis') {
        $pid = isset($_GET['pid']) ? DB_escape_string($_GET['pid']) : '0';
        $r = DB_fetch_array(DB_query("SELECT COUNT(*) AS emp_count,
            COALESCE(SUM(normal_hours),0) AS total_normal_hrs,
            COALESCE(SUM(timehalf_hours),0) AS total_th_hrs,
            COALESCE(SUM(double_hours),0) AS total_dt_hrs,
            COALESCE(SUM(public_holiday_hours),0) AS total_ph_hrs,
            COALESCE(SUM(normal_pay),0) AS total_normal_pay, COALESCE(SUM(timehalf_amount),0) AS total_th_pay,
            COALESCE(SUM(double_amount),0) AS total_dt_pay, COALESCE(SUM(public_holiday_amount),0) AS total_ph_pay,
            COALESCE(SUM(premium),0) AS total_premium, COALESCE(SUM(stay_away),0) AS total_stayaway,
            COALESCE(SUM(call_out_allowances),0) AS total_callout, COALESCE(SUM(leave_allowances),0) AS total_leave_allow,
            COALESCE(SUM(meal_allowance),0) AS total_meal,
            COALESCE(SUM(other_allowances_fnpf),0) AS total_allow_fnpf, COALESCE(SUM(other_allowances_nonfnpf),0) AS total_allow_nonfnpf,
            COALESCE(SUM(total_bonus),0) AS total_bonus, COALESCE(SUM(totalgross_amount),0) AS total_gross,
            COALESCE(SUM(income_tax_to_withhold),0) AS total_income_tax, COALESCE(SUM(srt_tax_to_withhold),0) AS total_srt,
            COALESCE(SUM(ecal_tax_to_withhold),0) AS total_ecal, COALESCE(SUM(total_tax_to_withhold),0) AS total_tax,
            COALESCE(SUM(employee_fnpf),0) AS total_fnpf_emp, COALESCE(SUM(fnpf_employer),0) AS total_fnpf_er,
            COALESCE(SUM(fixed_deductions),0) AS total_fixed_ded, COALESCE(SUM(other_deductions),0) AS total_other_ded,
            COALESCE(SUM(net_pay),0) AS total_net
            FROM payrun_details WHERE id='".$pid."'"));
        $cm = DB_fetch_array(DB_query("SELECT period, status FROM calendar_management WHERE id='".$pid."'"));
        $out = $r ? $r : array();
        if ($cm) { $out['period_label'] = $cm['period']; $out['status'] = $cm['status']; }
        echo json_encode($out); exit;
    }
    if ($api === 'period_employees') {
        $pid = isset($_GET['pid']) ? DB_escape_string($_GET['pid']) : '0';
        $rows = array();
        $q = DB_query("SELECT pd.payid, pd.employeeid, pd.full_name, COALESCE(d.departmentname, pd.department) AS department, pd.employee_type, pd.normal_hours, pd.base_wage, pd.normal_pay,
            pd.timehalf_hours, pd.timehalf_amount, pd.double_hours, pd.double_amount, pd.public_holiday_hours, pd.public_holiday_amount, pd.premium,
            pd.stay_away, pd.call_out_allowances, pd.leave_allowances, pd.meal_allowance, pd.other_allowances_fnpf, pd.other_allowances_nonfnpf,
            pd.total_bonus, pd.totalgross_amount, pd.income_tax_to_withhold, pd.srt_tax_to_withhold, pd.ecal_tax_to_withhold, pd.total_tax_to_withhold,
            pd.employee_fnpf, pd.fnpf_employer, pd.fixed_deductions, pd.other_deductions, pd.net_pay, pd.method_of_payment
            FROM payrun_details pd LEFT JOIN department d ON pd.department=d.departmentid WHERE pd.id='".$pid."' ORDER BY pd.full_name");
        if ($q) { while ($r = DB_fetch_array($q)) { $rows[] = $r; } }
        echo json_encode($rows); exit;
    }
    if ($api === 'period_depts') {
        $pid = isset($_GET['pid']) ? DB_escape_string($_GET['pid']) : '0';
        $rows = array();
        $q = DB_query("SELECT COALESCE(d.departmentname, pd.department) AS department, COUNT(*) AS emps,
            SUM(pd.totalgross_amount) AS gross, SUM(pd.net_pay) AS net, SUM(pd.total_tax_to_withhold) AS tax,
            COALESCE(SUM(pd.timehalf_hours),0) AS th_hrs, COALESCE(SUM(pd.double_hours),0) AS dt_hrs,
            COALESCE(SUM(pd.timehalf_amount),0) AS th_pay, COALESCE(SUM(pd.double_amount),0) AS dt_pay
            FROM payrun_details pd LEFT JOIN department d ON pd.department=d.departmentid WHERE pd.id='".$pid."' GROUP BY department ORDER BY gross DESC");
        if ($q) { while ($r = DB_fetch_array($q)) { $rows[] = $r; } }
        echo json_encode($rows); exit;
    }
    echo json_encode(array('error'=>'unknown')); exit;
}

/* ================================================================
   STEP 1: Output header + loading modal FIRST so browser shows it
   ================================================================ */
include('includes/newheader.php');
?>
<!-- ═══ LOADING MODAL — rendered immediately while PHP queries run ═══ -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"/>
<div id="prLM" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(15,23,42,0.45);backdrop-filter:blur(4px);z-index:99999;display:flex;align-items:center;justify-content:center;transition:opacity 0.35s ease">
<div style="background:#fff;border-radius:16px;padding:36px 44px;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,0.15);min-width:280px">
<div style="width:52px;height:52px;border-radius:13px;background:linear-gradient(135deg,#2AABB3,#187278);display:flex;align-items:center;justify-content:center;margin:0 auto 18px;box-shadow:0 4px 14px rgba(42,171,179,0.3)"><i class="fas fa-money-check-alt" style="color:#fff;font-size:22px"></i></div>
<div style="width:200px;height:5px;background:#E5E7EB;border-radius:5px;overflow:hidden;margin:0 auto 12px"><div id="prLB" style="height:100%;width:0%;background:linear-gradient(90deg,#2AABB3,#1E8F96);border-radius:5px;transition:width 0.3s ease"></div></div>
<p id="prLT" style="font-size:13px;color:#6B7280;margin:0;font-family:'Poppins',-apple-system,sans-serif;font-weight:500">Loading Payrun Dashboard...</p>
<p id="prLTm" style="font-size:11px;color:#9CA3AF;margin:6px 0 0;font-family:'Poppins',-apple-system,sans-serif;font-weight:400"><i class="fas fa-clock" style="margin-right:4px"></i>Elapsed: 0s</p>
</div></div>
<script>
(function(){var b=document.getElementById('prLB'),p=8,t=document.getElementById('prLT'),tm=document.getElementById('prLTm'),sec=0;
var iv=setInterval(function(){p+=Math.random()*10+4;if(p>88)p=88;b.style.width=p+'%';
if(p>35&&t.textContent.indexOf('data')<0)t.textContent='Fetching payroll data...';
if(p>65&&t.textContent.indexOf('chart')<0)t.textContent='Rendering charts...';},250);
var tv=setInterval(function(){sec++;tm.innerHTML='<i class="fas fa-clock" style="margin-right:4px"></i>Elapsed: '+sec+'s';},1000);
window._prLI=iv;window._prHL=function(){clearInterval(iv);clearInterval(tv);b.style.width='100%';t.textContent='Ready!';tm.innerHTML='<i class="fas fa-check-circle" style="margin-right:4px;color:#52C41A"></i>Loaded in '+sec+'s';
setTimeout(function(){var m=document.getElementById('prLM');if(m){m.style.opacity='0';setTimeout(function(){m.style.display='none';},350);}},250);};})();
</script>
<?php
/* Force browser to render the loading modal NOW before heavy queries */
if(function_exists('ob_flush')){@ob_flush();}
@flush();

/* ================================================================
   STEP 2: Now run heavy DB queries (browser shows modal during this)
   ================================================================ */
$kpi_periods=0;$kpi_emps=0;$kpi_gross=0;$kpi_net=0;$kpi_tax=0;$kpi_fnpf_emp=0;$kpi_fnpf_er=0;
$kpi_normal_hrs=0;$kpi_th_hrs=0;$kpi_dt_hrs=0;$kpi_ph_hrs=0;$kpi_ot_pay=0;$kpi_normal_pay=0;
$kpi_meal=0;$kpi_stay=0;$kpi_allow_fnpf=0;$kpi_allow_nonfnpf=0;$kpi_callout=0;$kpi_premium=0;$kpi_bonus=0;$kpi_leave_allow=0;
$periods_data=array();$trend_data=array();$dept_data=array();$ot_trend=array();

/* ── Main KPIs with OT and Allowance data ── */
$r=DB_fetch_array(DB_query("SELECT COUNT(DISTINCT pd.id) AS cnt FROM payrun_details pd JOIN calendar_management cm ON pd.id=cm.id WHERE cm.period LIKE '%".$curYear."%'"));
if($r) $kpi_periods=(int)$r['cnt'];
$r=DB_fetch_array(DB_query("SELECT COUNT(DISTINCT pd.employeeid) AS cnt FROM payrun_details pd JOIN calendar_management cm ON pd.id=cm.id WHERE cm.period LIKE '%".$curYear."%'"));
if($r) $kpi_emps=(int)$r['cnt'];

$r=DB_fetch_array(DB_query("SELECT
    COALESCE(SUM(pd.totalgross_amount),0) AS gross, COALESCE(SUM(pd.net_pay),0) AS net,
    COALESCE(SUM(pd.total_tax_to_withhold),0) AS tax,
    COALESCE(SUM(pd.employee_fnpf),0) AS fnpf_emp, COALESCE(SUM(pd.fnpf_employer),0) AS fnpf_er,
    COALESCE(SUM(pd.normal_hours),0) AS normal_hrs, COALESCE(SUM(pd.timehalf_hours),0) AS th_hrs,
    COALESCE(SUM(pd.double_hours),0) AS dt_hrs, COALESCE(SUM(pd.public_holiday_hours),0) AS ph_hrs,
    COALESCE(SUM(pd.normal_pay),0) AS normal_pay,
    COALESCE(SUM(pd.timehalf_amount + pd.double_amount),0) AS ot_pay,
    COALESCE(SUM(pd.meal_allowance),0) AS meal, COALESCE(SUM(pd.stay_away),0) AS stay,
    COALESCE(SUM(pd.other_allowances_fnpf),0) AS allow_fnpf, COALESCE(SUM(pd.other_allowances_nonfnpf),0) AS allow_nonfnpf,
    COALESCE(SUM(pd.call_out_allowances),0) AS callout, COALESCE(SUM(pd.premium),0) AS premium,
    COALESCE(SUM(pd.total_bonus),0) AS bonus, COALESCE(SUM(pd.leave_allowances),0) AS leave_allow
    FROM payrun_details pd JOIN calendar_management cm ON pd.id=cm.id WHERE cm.period LIKE '%".$curYear."%'"));
if($r){
    $kpi_gross=round((float)$r['gross'],2);$kpi_net=round((float)$r['net'],2);$kpi_tax=round((float)$r['tax'],2);
    $kpi_fnpf_emp=round((float)$r['fnpf_emp'],2);$kpi_fnpf_er=round((float)$r['fnpf_er'],2);
    $kpi_normal_hrs=round((float)$r['normal_hrs'],2);$kpi_th_hrs=round((float)$r['th_hrs'],2);
    $kpi_dt_hrs=round((float)$r['dt_hrs'],2);$kpi_ph_hrs=round((float)$r['ph_hrs'],2);
    $kpi_ot_pay=round((float)$r['ot_pay'],2);$kpi_normal_pay=round((float)$r['normal_pay'],2);
    $kpi_meal=round((float)$r['meal'],2);$kpi_stay=round((float)$r['stay'],2);
    $kpi_allow_fnpf=round((float)$r['allow_fnpf'],2);$kpi_allow_nonfnpf=round((float)$r['allow_nonfnpf'],2);
    $kpi_callout=round((float)$r['callout'],2);$kpi_premium=round((float)$r['premium'],2);
    $kpi_bonus=round((float)$r['bonus'],2);$kpi_leave_allow=round((float)$r['leave_allow'],2);
}

/* Previous Year KPIs for comparison */
$kpi_prev_gross=0;$kpi_prev_ot_pay=0;$kpi_prev_net=0;$kpi_prev_th_hrs=0;$kpi_prev_dt_hrs=0;
$r=DB_fetch_array(DB_query("SELECT
    COALESCE(SUM(pd.totalgross_amount),0) AS gross, COALESCE(SUM(pd.net_pay),0) AS net,
    COALESCE(SUM(pd.timehalf_amount + pd.double_amount),0) AS ot_pay,
    COALESCE(SUM(pd.timehalf_hours),0) AS th_hrs, COALESCE(SUM(pd.double_hours),0) AS dt_hrs
    FROM payrun_details pd JOIN calendar_management cm ON pd.id=cm.id WHERE cm.period LIKE '%".$prevYear."%'"));
if($r){$kpi_prev_gross=round((float)$r['gross'],2);$kpi_prev_ot_pay=round((float)$r['ot_pay'],2);$kpi_prev_net=round((float)$r['net'],2);$kpi_prev_th_hrs=round((float)$r['th_hrs'],2);$kpi_prev_dt_hrs=round((float)$r['dt_hrs'],2);}

/* ── Periods table data ── */
$q=DB_query("SELECT cm.id, cm.period, cm.status,
    (SELECT COUNT(*) FROM payrun_details pd WHERE pd.id=cm.id) AS emp_count,
    (SELECT COALESCE(SUM(totalgross_amount),0) FROM payrun_details pd WHERE pd.id=cm.id) AS total_gross,
    (SELECT COALESCE(SUM(net_pay),0) FROM payrun_details pd WHERE pd.id=cm.id) AS total_net,
    (SELECT COALESCE(SUM(total_tax_to_withhold),0) FROM payrun_details pd WHERE pd.id=cm.id) AS total_tax
    FROM calendar_management cm ORDER BY cm.id DESC LIMIT 100");
if($q){while($r=DB_fetch_array($q)){$periods_data[]=$r;}}

/* ── Trend data (last 12 periods) ── */
$q=DB_query("SELECT pd.id, cm.period, SUM(pd.totalgross_amount) AS gross, SUM(pd.net_pay) AS net, SUM(pd.total_tax_to_withhold) AS tax, COUNT(*) AS emp_count,
    COALESCE(SUM(pd.timehalf_hours),0) AS th_hrs, COALESCE(SUM(pd.double_hours),0) AS dt_hrs,
    COALESCE(SUM(pd.timehalf_amount + pd.double_amount),0) AS ot_pay, COALESCE(SUM(pd.normal_hours),0) AS normal_hrs
    FROM payrun_details pd LEFT JOIN calendar_management cm ON pd.id=cm.id GROUP BY pd.id, cm.period ORDER BY pd.id DESC LIMIT 12");
if($q){while($r=DB_fetch_array($q)){$trend_data[]=$r;}}
$trend_data=array_reverse($trend_data);

/* ── Department breakdown ── */
$q=DB_query("SELECT COALESCE(d.departmentname, pd.department) AS department, COUNT(DISTINCT pd.employeeid) AS emps,
    SUM(pd.totalgross_amount) AS gross, SUM(pd.net_pay) AS net,
    COALESCE(SUM(pd.timehalf_hours + pd.double_hours),0) AS ot_hrs,
    COALESCE(SUM(pd.timehalf_amount + pd.double_amount),0) AS ot_pay
    FROM payrun_details pd JOIN calendar_management cm ON pd.id=cm.id LEFT JOIN department d ON pd.department=d.departmentid
    WHERE cm.period LIKE '%".$curYear."%' GROUP BY department ORDER BY gross DESC LIMIT 10");
if($q){while($r=DB_fetch_array($q)){$dept_data[]=$r;}}

$js_kpis=json_encode(array('periods'=>$kpi_periods,'employees'=>$kpi_emps,'gross'=>$kpi_gross,'net'=>$kpi_net,'tax'=>$kpi_tax,
    'fnpf_emp'=>$kpi_fnpf_emp,'fnpf_er'=>$kpi_fnpf_er,
    'normal_hrs'=>$kpi_normal_hrs,'th_hrs'=>$kpi_th_hrs,'dt_hrs'=>$kpi_dt_hrs,'ph_hrs'=>$kpi_ph_hrs,
    'ot_pay'=>$kpi_ot_pay,'normal_pay'=>$kpi_normal_pay,
    'meal'=>$kpi_meal,'stay'=>$kpi_stay,'allow_fnpf'=>$kpi_allow_fnpf,'allow_nonfnpf'=>$kpi_allow_nonfnpf,
    'callout'=>$kpi_callout,'premium'=>$kpi_premium,'bonus'=>$kpi_bonus,'leave_allow'=>$kpi_leave_allow,
    'prev_gross'=>$kpi_prev_gross,'prev_ot_pay'=>$kpi_prev_ot_pay,'prev_net'=>$kpi_prev_net,
    'prev_th_hrs'=>$kpi_prev_th_hrs,'prev_dt_hrs'=>$kpi_prev_dt_hrs));
$js_periods=json_encode($periods_data);
$js_trend=json_encode($trend_data);
$js_depts=json_encode($dept_data);
?>

<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
:root{--pr:#2AABB3;--prd:#1E8F96;--prdd:#187278;--prl:#E6F7F8;--bl:#1890FF;--bld:#096DD9;--bll:#E6F7FF;--gn:#52C41A;--gnd:#389E0D;--gnl:#F6FFED;--or:#FA8C16;--orl:#FFF7E6;--pu:#722ED1;--pul:#F9F0FF;--rd:#FF4D4F;--rdl:#FFF2F0;--go:#FAAD14;--gol:#FFFBE6;--cy:#13C2C2;--cyl:#E6FFFB;--tx:#1F2937;--tm:#6B7280;--bd:#E5E7EB;--bg:#FFFFFF;--ra:10px;--sh:0 2px 8px rgba(0,0,0,0.06);--shh:0 4px 16px rgba(0,0,0,0.1)}
.prw{font-family:'Poppins',-apple-system,BlinkMacSystemFont,sans-serif;color:var(--tx);padding:0}.prw *{box-sizing:border-box}
.pr-hdr{background:linear-gradient(135deg,#0D4F52 0%,var(--prdd) 30%,var(--prd) 60%,var(--pr) 100%);color:#fff;padding:28px 32px 24px;border-radius:14px 14px 0 0;position:relative;overflow:hidden;margin:-10px -10px 0 -10px}
.pr-hdr::before{content:'';position:absolute;top:-40%;right:-5%;width:350px;height:350px;background:radial-gradient(circle,rgba(255,255,255,0.07) 0%,transparent 70%);border-radius:50%}
.pr-hdr-c{position:relative;z-index:1;display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:16px}
.pr-hdr h2{margin:0 0 4px;font-size:22px;font-weight:600;color:#fff}.pr-hdr p{margin:0;font-size:13px;opacity:0.85}
.pr-bc{display:flex;align-items:center;gap:8px;font-size:12px;opacity:0.75;margin-bottom:12px}.pr-bc a{color:#fff;text-decoration:none}.pr-bc a:hover{text-decoration:underline}.pr-bc span{opacity:0.6}
.pr-db{display:inline-block;background:rgba(255,255,255,0.15);padding:4px 14px;border-radius:20px;font-size:12px;margin-top:8px}
.pr-hb{background:rgba(255,255,255,0.2);color:#fff;border:1.5px solid rgba(255,255,255,0.35);padding:9px 20px;border-radius:8px;font-size:13px;font-weight:500;cursor:pointer;transition:all 0.2s;font-family:'Poppins',sans-serif;display:flex;align-items:center;gap:8px}.pr-hb:hover{background:rgba(255,255,255,0.3);transform:translateY(-1px)}
.kg{display:grid;grid-template-columns:repeat(6,1fr);gap:14px;padding:20px 0}@media(max-width:1200px){.kg{grid-template-columns:repeat(3,1fr)}}@media(max-width:768px){.kg{grid-template-columns:repeat(2,1fr)}}
.kg4{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;padding:0 0 20px 0}@media(max-width:992px){.kg4{grid-template-columns:repeat(2,1fr)}}
.kc{background:var(--bg);border:1px solid var(--bd);border-radius:var(--ra);padding:18px;display:flex;align-items:center;gap:14px;box-shadow:var(--sh);transition:all 0.2s;border-left:4px solid transparent}.kc:hover{box-shadow:var(--shh);transform:translateY(-2px)}
.ki{width:44px;height:44px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0}
.kv h3{margin:0;font-size:20px;font-weight:700;line-height:1.2}.kv p{margin:2px 0 0;font-size:11px;color:var(--tm);font-weight:400}
.kv .kd{font-size:10px;margin-top:3px;font-weight:500;display:inline-flex;align-items:center;gap:3px;padding:1px 6px;border-radius:10px}
.kd.up{color:#389E0D;background:#F6FFED}.kd.dn{color:#CF1322;background:#FFF2F0}
.kt{border-left-color:var(--pr)}.kt .ki{background:var(--prl);color:var(--pr)}
.kb{border-left-color:var(--bl)}.kb .ki{background:var(--bll);color:var(--bl)}
.kgn{border-left-color:var(--gn)}.kgn .ki{background:var(--gnl);color:var(--gn)}
.ko{border-left-color:var(--or)}.ko .ki{background:var(--orl);color:var(--or)}
.kp{border-left-color:var(--pu)}.kp .ki{background:var(--pul);color:var(--pu)}
.kr{border-left-color:var(--rd)}.kr .ki{background:var(--rdl);color:var(--rd)}
.kgo{border-left-color:var(--go)}.kgo .ki{background:var(--gol);color:var(--go)}
.kcy{border-left-color:var(--cy)}.kcy .ki{background:var(--cyl);color:var(--cy)}
.cd{background:var(--bg);border:1px solid var(--bd);border-radius:var(--ra);box-shadow:var(--sh);overflow:hidden;margin-bottom:20px}
.cdh{padding:14px 20px;border-bottom:1px solid var(--bd);display:flex;justify-content:space-between;align-items:center}.cdh h4{margin:0;font-size:15px;font-weight:600}.cdb{padding:20px}
.g2{display:grid;grid-template-columns:1fr 1fr;gap:20px;margin-bottom:20px}@media(max-width:768px){.g2{grid-template-columns:1fr}}
.g3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px;margin-bottom:20px}@media(max-width:992px){.g3{grid-template-columns:1fr}}
.g4{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:20px;margin-bottom:20px}@media(max-width:1200px){.g4{grid-template-columns:1fr 1fr}}@media(max-width:768px){.g4{grid-template-columns:1fr}}
.chc{position:relative;height:280px}
.chc-sm{position:relative;height:220px}
.ttb{padding:14px 20px;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--bd);flex-wrap:wrap;gap:10px}.ttb h4{margin:0;font-size:15px;font-weight:600}
.sb{position:relative}.sb input{padding:8px 12px 8px 34px;border:1.5px solid var(--bd);border-radius:8px;font-size:13px;font-family:'Poppins',sans-serif;width:220px;outline:none;transition:all 0.2s;background:#FAFBFC}.sb input:focus{border-color:var(--pr);box-shadow:0 0 0 3px rgba(42,171,179,0.12);background:#fff}.si{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--tm);font-size:14px}
.ppsel{padding:7px 10px;border:1.5px solid var(--bd);border-radius:8px;font-size:13px;font-family:'Poppins',sans-serif;background:#FAFBFC;outline:none;cursor:pointer}
.tw{overflow-x:auto}
.tb{width:100%;border-collapse:collapse;font-size:13px}.tb thead th{background:#F9FAFB;padding:12px 14px;text-align:left;font-weight:600;font-size:11px;color:var(--tm);text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid var(--bd);white-space:nowrap}.tb tbody tr{border-bottom:1px solid #F3F4F6;transition:background 0.15s;cursor:pointer}.tb tbody tr:hover{background:var(--prl)}.tb tbody td{padding:11px 14px;vertical-align:middle}
.dtb{width:100%;border-collapse:collapse;font-size:12px}.dtb thead th{background:#F9FAFB;padding:10px 12px;text-align:left;font-weight:600;font-size:10px;color:var(--tm);text-transform:uppercase;letter-spacing:0.5px;border-bottom:2px solid var(--bd);white-space:nowrap}.dtb tbody tr{border-bottom:1px solid #F3F4F6}.dtb tbody tr:hover{background:#FAFCFD}.dtb tbody td{padding:9px 12px;vertical-align:middle}
.st{display:inline-flex;align-items:center;gap:5px;padding:3px 12px;border-radius:20px;font-size:11px;font-weight:600;text-transform:capitalize}
.st-a{background:var(--gnl);color:var(--gnd);border:1px solid #B7EB8F}.st-l{background:var(--rdl);color:var(--rd);border:1px solid #FFD6D6}.st-p{background:var(--gol);color:#D48806;border:1px solid #FFE58F}.st-pr{background:var(--bll);color:var(--bld);border:1px solid #91D5FF}.st-u{background:#F3F4F6;color:var(--tm);border:1px solid var(--bd)}
.am{font-weight:600;font-family:'Poppins',monospace}.amg{color:var(--gnd)}
.ab{padding:5px 14px;border-radius:6px;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s;font-family:'Poppins',sans-serif;border:1px solid;display:inline-flex;align-items:center;gap:5px;text-decoration:none}
.abv{background:var(--prl);color:var(--prd);border-color:#B8E6EA}.abv:hover{background:var(--pr);color:#fff}
.abp{background:var(--gnl);color:var(--gnd);border-color:#B7EB8F}.abp:hover{background:var(--gn);color:#fff}
.pg{display:flex;justify-content:space-between;align-items:center;padding:14px 20px;border-top:1px solid var(--bd);flex-wrap:wrap;gap:10px}.pgi{font-size:13px;color:var(--tm)}.pgb{display:flex;gap:4px}
.pgn{min-width:34px;height:34px;display:flex;align-items:center;justify-content:center;border:1px solid var(--bd);border-radius:6px;background:#fff;color:var(--tx);font-size:13px;cursor:pointer;transition:all 0.15s;font-family:'Poppins',sans-serif}.pgn:hover{border-color:var(--pr);color:var(--pr)}.pgn.ac{background:var(--pr);color:#fff;border-color:var(--pr)}.pgn:disabled{opacity:0.4;cursor:not-allowed}
.dh{background:linear-gradient(135deg,var(--prdd),var(--pr));color:#fff;padding:18px 24px;border-radius:var(--ra) var(--ra) 0 0;display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px}.dh h3{margin:0;font-size:18px;font-weight:600}
.bkb{background:rgba(255,255,255,0.2);color:#fff;border:1px solid rgba(255,255,255,0.3);padding:7px 16px;border-radius:6px;font-size:13px;cursor:pointer;font-family:'Poppins',sans-serif;display:flex;align-items:center;gap:6px;text-decoration:none}.bkb:hover{background:rgba(255,255,255,0.3)}
.eav{width:30px;height:30px;border-radius:50%;background:linear-gradient(135deg,var(--pr),var(--prd));color:#fff;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;margin-right:8px;vertical-align:middle}
.bdi{display:flex;justify-content:space-between;align-items:center;padding:10px 0;border-bottom:1px solid #F3F4F6}.bdi:last-child{border-bottom:none}.bdl{display:flex;align-items:center;gap:10px;font-size:13px}.bdd{width:8px;height:8px;border-radius:50%;flex-shrink:0}.bdv{font-weight:600;font-size:13px}
.em{text-align:center;padding:50px 20px;color:var(--tm)}.emi{font-size:48px;margin-bottom:10px;opacity:0.4}
.prld{text-align:center;padding:60px 20px;color:var(--tm)}.prld-sp{width:40px;height:40px;border:4px solid var(--bd);border-top-color:var(--pr);border-radius:50%;animation:prSp 0.8s linear infinite;margin:0 auto 16px}@keyframes prSp{to{transform:rotate(360deg)}}
.pv{display:none}.pv.act{display:block}
/* Section headers */
.sec-hdr{display:flex;align-items:center;gap:10px;margin:24px 0 14px;padding-bottom:10px;border-bottom:2px solid var(--bd)}.sec-hdr i{font-size:18px;color:var(--pr)}.sec-hdr h3{margin:0;font-size:16px;font-weight:600;color:var(--tx)}.sec-hdr .sec-badge{font-size:11px;background:var(--prl);color:var(--prd);padding:2px 10px;border-radius:12px;font-weight:500}
/* Gauge canvas */
.gauge-wrap{position:relative;width:100%;display:flex;flex-direction:column;align-items:center}
.gauge-val{font-size:22px;font-weight:700;color:var(--tx);margin-top:-30px}.gauge-lbl{font-size:11px;color:var(--tm);margin-top:2px}
/* Progress bar mini */
.mpb{height:6px;background:#F3F4F6;border-radius:3px;overflow:hidden;margin-top:8px}.mpb-f{height:100%;border-radius:3px;transition:width 0.6s ease}
@media print{@page{size:A4 landscape;margin:10mm}.pr-hdr,.ttb,.pg,.pr-hb,.bkb,.ab,.sec-hdr{display:none!important}.cd{box-shadow:none;border:1px solid #ddd}}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.min.js"></script>

<div class="prw">
  <div class="pr-hdr"><div class="pr-hdr-c"><div>
    <div class="pr-bc"><a href="index.php">Home</a><span>›</span><a href="index.php">HRM</a><span>›</span><span style="opacity:1">Payrun Dashboard</span></div>
    <h2><i class="fas fa-money-check-alt" style="margin-right:10px;opacity:0.9"></i>Payrun Dashboard</h2>
    <p>Process and manage payroll runs across all periods</p>
    <div class="pr-db"><i class="far fa-calendar-alt" style="margin-right:6px"></i><?php echo date('l, d M Y'); ?></div>
  </div><div style="display:flex;gap:10px"><button class="pr-hb" onclick="prExCSV()"><i class="fas fa-download"></i> Export</button></div></div></div>

  <!-- MAIN VIEW -->
  <div class="pv act" id="prMain">
    <!-- Row 1: Core KPIs -->
    <div class="kg">
      <div class="kc kt"><div class="ki"><i class="fas fa-calendar-alt"></i></div><div class="kv"><h3 id="kP">–</h3><p>Periods (<?php echo $curYear;?>)</p></div></div>
      <div class="kc kb"><div class="ki"><i class="fas fa-users"></i></div><div class="kv"><h3 id="kE">–</h3><p>Employees Paid</p></div></div>
      <div class="kc kgn"><div class="ki"><i class="fas fa-dollar-sign"></i></div><div class="kv"><h3 id="kG">–</h3><p>Gross Pay</p><div id="kGd" class="kd"></div></div></div>
      <div class="kc kcy"><div class="ki"><i class="fas fa-hand-holding-usd"></i></div><div class="kv"><h3 id="kN">–</h3><p>Net Pay</p><div id="kNd" class="kd"></div></div></div>
      <div class="kc ko"><div class="ki"><i class="fas fa-file-invoice-dollar"></i></div><div class="kv"><h3 id="kT">–</h3><p>Tax Withheld</p></div></div>
      <div class="kc kp"><div class="ki"><i class="fas fa-piggy-bank"></i></div><div class="kv"><h3 id="kF">–</h3><p>FNPF Total</p></div></div>
    </div>

    <!-- Row 2: OT Insights -->
    <div class="sec-hdr"><i class="fas fa-business-time"></i><h3>Overtime Insights</h3><span class="sec-badge"><?php echo $curYear;?></span></div>
    <div class="kg4">
      <div class="kc ko"><div class="ki"><i class="fas fa-clock"></i></div><div class="kv"><h3 id="kTHrs">–</h3><p>Time &amp; Half Hours</p></div></div>
      <div class="kc kr"><div class="ki"><i class="fas fa-forward"></i></div><div class="kv"><h3 id="kDHrs">–</h3><p>Double Time Hours</p></div></div>
      <div class="kc kgo"><div class="ki"><i class="fas fa-star"></i></div><div class="kv"><h3 id="kPHrs">–</h3><p>Public Holiday Hrs</p></div></div>
      <div class="kc kr"><div class="ki"><i class="fas fa-coins"></i></div><div class="kv"><h3 id="kOTPay">–</h3><p>Total OT Pay</p><div id="kOTd" class="kd"></div></div></div>
    </div>

    <!-- Row 3: Allowances -->
    <div class="sec-hdr"><i class="fas fa-wallet"></i><h3>Allowances &amp; Extras</h3><span class="sec-badge"><?php echo $curYear;?></span></div>
    <div class="kg4">
      <div class="kc kcy"><div class="ki"><i class="fas fa-utensils"></i></div><div class="kv"><h3 id="kMeal">–</h3><p>Meal Allowance</p></div></div>
      <div class="kc kp"><div class="ki"><i class="fas fa-bed"></i></div><div class="kv"><h3 id="kStay">–</h3><p>Stay Allowance</p></div></div>
      <div class="kc kgn"><div class="ki"><i class="fas fa-plus-circle"></i></div><div class="kv"><h3 id="kAFnpf">–</h3><p>Other Allow (FNPF)</p></div></div>
      <div class="kc kgo"><div class="ki"><i class="fas fa-minus-circle"></i></div><div class="kv"><h3 id="kANon">–</h3><p>Other Allow (Non-FNPF)</p></div></div>
    </div>

    <!-- Charts Row 1: Trend + Department -->
    <div class="g2">
      <div class="cd"><div class="cdh"><h4><i class="fas fa-chart-line" style="margin-right:8px;color:var(--pr)"></i>Gross vs Net Trend</h4></div><div class="cdb"><div class="chc"><canvas id="cTrend"></canvas></div></div></div>
      <div class="cd"><div class="cdh"><h4><i class="fas fa-chart-pie" style="margin-right:8px;color:var(--pu)"></i>Department Breakdown (<?php echo $curYear;?>)</h4></div><div class="cdb"><div class="chc"><canvas id="cDept"></canvas></div></div></div>
    </div>

    <!-- Charts Row 2: OT Trend + OT Gauge + OT Breakdown -->
    <div class="g3">
      <div class="cd"><div class="cdh"><h4><i class="fas fa-chart-area" style="margin-right:8px;color:var(--or)"></i>OT Pay Trend (Last 12)</h4></div><div class="cdb"><div class="chc"><canvas id="cOTTrend"></canvas></div></div></div>
      <div class="cd"><div class="cdh"><h4><i class="fas fa-tachometer-alt" style="margin-right:8px;color:var(--rd)"></i>OT Cost Ratio</h4></div><div class="cdb"><div class="gauge-wrap"><canvas id="cGauge" width="240" height="150"></canvas><div class="gauge-val" id="gVal">–</div><div class="gauge-lbl">OT % of Gross Pay</div></div></div></div>
      <div class="cd"><div class="cdh"><h4><i class="fas fa-chart-bar" style="margin-right:8px;color:var(--bl)"></i>OT Hours Breakdown</h4></div><div class="cdb"><div class="chc"><canvas id="cOTBar"></canvas></div></div></div>
    </div>

    <!-- Charts Row 3: Allowance Polar + Pay Component Radar -->
    <div class="g2">
      <div class="cd"><div class="cdh"><h4><i class="fas fa-bullseye" style="margin-right:8px;color:var(--cy)"></i>Allowance Distribution</h4></div><div class="cdb"><div class="chc"><canvas id="cAllow"></canvas></div></div></div>
      <div class="cd"><div class="cdh"><h4><i class="fas fa-spider" style="margin-right:8px;color:var(--pu)"></i>Pay Component Radar</h4></div><div class="cdb"><div class="chc"><canvas id="cRadar"></canvas></div></div></div>
    </div>

    <!-- Periods Table -->
    <div class="cd">
      <div class="ttb"><h4><i class="fas fa-list-ol" style="margin-right:8px;color:var(--pr)"></i>Pay Periods</h4>
        <div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
          <div class="sb"><span class="si"><i class="fas fa-search"></i></span><input type="text" id="pSrch" placeholder="Search periods..." oninput="pFilt()" /></div>
          <select class="ppsel" id="pPPSel" onchange="pPPCh()"><option value="10">10 / page</option><option value="20">20 / page</option><option value="50">50 / page</option></select>
        </div>
      </div>
      <div class="tw"><table class="tb"><thead><tr><th>ID</th><th>Period</th><th>Status</th><th>Employees</th><th>Total Gross</th><th>Total Net</th><th>Total Tax</th><th>Actions</th></tr></thead><tbody id="pTB"></tbody></table></div>
      <div class="pg"><div class="pgi" id="pPI"></div><div class="pgb" id="pPB"></div></div>
    </div>
  </div>

  <!-- DETAIL VIEW -->
  <div class="pv" id="prDetail"><div id="prDC"></div></div>
</div>

<script>
(function(){
  var K=<?php echo $js_kpis;?>,P=<?php echo $js_periods;?>,TR=<?php echo $js_trend;?>,D=<?php echo $js_depts;?>;
  var API='<?php echo basename($_SERVER["PHP_SELF"]);?>';
  var CY='<?php echo $curYear;?>',PY='<?php echo $prevYear;?>';
  var F=function(n){return parseFloat(n||0).toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});};
  var FK=function(n){n=parseFloat(n||0);return n>=1e6?'$'+(n/1e6).toFixed(1)+'M':n>=1e3?'$'+(n/1e3).toFixed(1)+'K':'$'+n.toFixed(2);};
  var FH=function(n){n=parseFloat(n||0);return n>=1e3?(n/1e3).toFixed(1)+'K':n.toFixed(1);};
  var sC=function(s){s=(s||'').toLowerCase();return s==='approved'?'st-a':s==='locked'?'st-l':s==='pending'?'st-p':s==='processed'?'st-pr':'st-u';};
  var sI=function(s){s=(s||'').toLowerCase();return s==='approved'?'<i class="fas fa-check-circle"></i>':s==='locked'?'<i class="fas fa-lock"></i>':s==='pending'?'<i class="fas fa-clock"></i>':s==='processed'?'<i class="fas fa-cogs"></i>':'<i class="fas fa-question-circle"></i>';};
  var ini=function(n){var p=(n||'').trim().split(/\s+/);return p.length>=2?(p[0][0]+p[p.length-1][0]).toUpperCase():(n||'??').substring(0,2).toUpperCase();};
  function api(ep,cb){var x=new XMLHttpRequest();x.open('GET',API+'?api='+ep,true);x.onload=function(){if(x.status===200){try{cb(JSON.parse(x.responseText));}catch(e){cb(null);}}else cb(null);};x.onerror=function(){cb(null);};x.send();}
  /* YoY delta helper */
  function yoyHtml(cur,prev){if(!prev||prev===0)return'';var pct=((cur-prev)/prev*100).toFixed(1);var up=pct>=0;return'<span class="kd '+(up?'up':'dn')+'"><i class="fas fa-arrow-'+(up?'up':'down')+'" style="font-size:8px"></i> '+(up?'+':'')+pct+'% vs '+PY+'</span>';}

  /* ═══ MAIN DASHBOARD ═══ */
  var aP=[],fP=[],pg=1,pp=10;
  document.getElementById('kP').textContent=K.periods;
  document.getElementById('kE').textContent=K.employees;
  document.getElementById('kG').textContent=FK(K.gross);
  document.getElementById('kN').textContent=FK(K.net);
  document.getElementById('kT').textContent=FK(K.tax);
  document.getElementById('kF').textContent=FK(K.fnpf_emp+K.fnpf_er);
  document.getElementById('kGd').innerHTML=yoyHtml(K.gross,K.prev_gross);
  document.getElementById('kNd').innerHTML=yoyHtml(K.net,K.prev_net);

  /* OT KPIs */
  document.getElementById('kTHrs').textContent=FH(K.th_hrs)+' hrs';
  document.getElementById('kDHrs').textContent=FH(K.dt_hrs)+' hrs';
  document.getElementById('kPHrs').textContent=FH(K.ph_hrs)+' hrs';
  document.getElementById('kOTPay').textContent=FK(K.ot_pay);
  document.getElementById('kOTd').innerHTML=yoyHtml(K.ot_pay,K.prev_ot_pay);

  /* Allowance KPIs */
  document.getElementById('kMeal').textContent=FK(K.meal);
  document.getElementById('kStay').textContent=FK(K.stay);
  document.getElementById('kAFnpf').textContent=FK(K.allow_fnpf);
  document.getElementById('kANon').textContent=FK(K.allow_nonfnpf);

  /* ── Chart: Gross vs Net Trend ── */
  if(TR.length>0){new Chart(document.getElementById('cTrend'),{type:'bar',data:{labels:TR.map(function(r){return r.period||('#'+r.id);}),datasets:[{label:'Gross',data:TR.map(function(r){return parseFloat(r.gross||0);}),backgroundColor:'rgba(42,171,179,0.7)',borderRadius:4,order:2},{label:'Net',data:TR.map(function(r){return parseFloat(r.net||0);}),backgroundColor:'rgba(82,196,26,0.7)',borderRadius:4,order:2},{label:'Tax',data:TR.map(function(r){return parseFloat(r.tax||0);}),type:'line',borderColor:'#FA8C16',backgroundColor:'transparent',pointBackgroundColor:'#FA8C16',borderWidth:2,tension:0.3,order:1}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'top',labels:{usePointStyle:true,padding:15,font:{family:'Poppins',size:11}}}},scales:{x:{grid:{display:false},ticks:{font:{family:'Poppins',size:10},maxRotation:45}},y:{grid:{color:'#F3F4F6'},ticks:{font:{family:'Poppins',size:10},callback:function(v){return'$'+v.toLocaleString();}}}}}})}

  /* ── Chart: Department Doughnut ── */
  if(D.length>0){var dc=['#2AABB3','#1890FF','#52C41A','#FA8C16','#722ED1','#FF4D4F','#13C2C2','#FAAD14','#EB2F96','#A0D911'];new Chart(document.getElementById('cDept'),{type:'doughnut',data:{labels:D.map(function(r){return r.department||'Unknown';}),datasets:[{data:D.map(function(r){return parseFloat(r.gross||0);}),backgroundColor:dc.slice(0,D.length),borderWidth:2,borderColor:'#fff'}]},options:{responsive:true,maintainAspectRatio:false,cutout:'55%',plugins:{legend:{position:'right',labels:{usePointStyle:true,padding:10,font:{family:'Poppins',size:11}}},tooltip:{callbacks:{label:function(ctx){var t=ctx.dataset.data.reduce(function(a,b){return a+b;},0);var pct=t>0?(ctx.parsed/t*100).toFixed(1):'0';return ctx.label+': $'+F(ctx.parsed)+' ('+pct+'%)';}}}}}})}

  /* ── Chart: OT Pay Trend (gradient area) ── */
  if(TR.length>0){var otCtx=document.getElementById('cOTTrend').getContext('2d');
    var grad=otCtx.createLinearGradient(0,0,0,280);grad.addColorStop(0,'rgba(250,140,22,0.35)');grad.addColorStop(1,'rgba(250,140,22,0.02)');
    new Chart(otCtx,{type:'line',data:{labels:TR.map(function(r){return r.period||('#'+r.id);}),datasets:[{label:'OT Pay',data:TR.map(function(r){return parseFloat(r.ot_pay||0);}),borderColor:'#FA8C16',backgroundColor:grad,fill:true,pointBackgroundColor:'#FA8C16',pointBorderColor:'#fff',pointBorderWidth:2,pointRadius:4,pointHoverRadius:6,borderWidth:2.5,tension:0.4}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{display:false},tooltip:{callbacks:{label:function(ctx){return'OT Pay: $'+F(ctx.parsed.y);}}}},scales:{x:{grid:{display:false},ticks:{font:{family:'Poppins',size:10},maxRotation:45}},y:{grid:{color:'#F3F4F6'},ticks:{font:{family:'Poppins',size:10},callback:function(v){return'$'+v.toLocaleString();}},beginAtZero:true}}}})}

  /* ── Gauge: OT ratio (canvas drawn) ── */
  function drawGauge(canvasId,valId,pct){
    var c=document.getElementById(canvasId);if(!c)return;
    var ctx=c.getContext('2d'),w=c.width,h=c.height,cx=w/2,cy=h-10,radius=Math.min(w,h*1.4)/2-10;
    ctx.clearRect(0,0,w,h);
    /* Background arc */
    ctx.beginPath();ctx.arc(cx,cy,radius,Math.PI,2*Math.PI);ctx.lineWidth=20;ctx.strokeStyle='#F3F4F6';ctx.lineCap='round';ctx.stroke();
    /* Value arc */
    var clampPct=Math.min(pct,100);
    var angle=Math.PI+(clampPct/100)*Math.PI;
    var grad=ctx.createLinearGradient(cx-radius,cy,cx+radius,cy);
    grad.addColorStop(0,'#52C41A');grad.addColorStop(0.4,'#FAAD14');grad.addColorStop(0.7,'#FA8C16');grad.addColorStop(1,'#FF4D4F');
    ctx.beginPath();ctx.arc(cx,cy,radius,Math.PI,angle);ctx.lineWidth=20;ctx.strokeStyle=grad;ctx.lineCap='round';ctx.stroke();
    /* Tick marks */
    for(var i=0;i<=10;i++){var ta=Math.PI+(i/10)*Math.PI;var ix1=cx+Math.cos(ta)*(radius+14),iy1=cy+Math.sin(ta)*(radius+14);
      var ix2=cx+Math.cos(ta)*(radius+8),iy2=cy+Math.sin(ta)*(radius+8);
      ctx.beginPath();ctx.moveTo(ix1,iy1);ctx.lineTo(ix2,iy2);ctx.lineWidth=1.5;ctx.strokeStyle='#D1D5DB';ctx.stroke();
      if(i%2===0){var lx=cx+Math.cos(ta)*(radius+26),ly=cy+Math.sin(ta)*(radius+26);ctx.font='500 9px Poppins';ctx.fillStyle='#9CA3AF';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText((i*10)+'%',lx,ly);}}
    /* Needle */
    var na=Math.PI+(clampPct/100)*Math.PI;var nx=cx+Math.cos(na)*(radius-8),ny=cy+Math.sin(na)*(radius-8);
    ctx.beginPath();ctx.moveTo(cx,cy);ctx.lineTo(nx,ny);ctx.lineWidth=2.5;ctx.strokeStyle='#374151';ctx.stroke();
    ctx.beginPath();ctx.arc(cx,cy,5,0,2*Math.PI);ctx.fillStyle='#374151';ctx.fill();
    document.getElementById(valId).textContent=pct.toFixed(1)+'%';
  }
  var otRatio=K.gross>0?(K.ot_pay/K.gross*100):0;
  drawGauge('cGauge','gVal',otRatio);

  /* ── Chart: OT Hours Horizontal Stacked Bar ── */
  if(TR.length>0){new Chart(document.getElementById('cOTBar'),{type:'bar',data:{labels:TR.map(function(r){return r.period||('#'+r.id);}),datasets:[{label:'Time & Half',data:TR.map(function(r){return parseFloat(r.th_hrs||0);}),backgroundColor:'#1890FF',borderRadius:2},{label:'Double Time',data:TR.map(function(r){return parseFloat(r.dt_hrs||0);}),backgroundColor:'#FF4D4F',borderRadius:2}]},options:{responsive:true,maintainAspectRatio:false,indexAxis:'y',plugins:{legend:{position:'top',labels:{usePointStyle:true,padding:10,font:{family:'Poppins',size:10}}},tooltip:{callbacks:{label:function(ctx){return ctx.dataset.label+': '+parseFloat(ctx.parsed.x||0).toFixed(1)+' hrs';}}}},scales:{x:{stacked:true,grid:{color:'#F3F4F6'},ticks:{font:{family:'Poppins',size:10},callback:function(v){return v+' hrs';}}},y:{stacked:true,grid:{display:false},ticks:{font:{family:'Poppins',size:9}}}}}})}

  /* ── Chart: Allowance Polar Area ── */
  var alData=[{l:'Meal',v:K.meal,c:'#13C2C2'},{l:'Stay Away',v:K.stay,c:'#722ED1'},{l:'Call-Out',v:K.callout,c:'#FA8C16'},{l:'Leave Allow.',v:K.leave_allow,c:'#52C41A'},{l:'Allow (FNPF)',v:K.allow_fnpf,c:'#1890FF'},{l:'Allow (Non-FNPF)',v:K.allow_nonfnpf,c:'#FAAD14'},{l:'Premium',v:K.premium,c:'#FF4D4F'},{l:'Bonus',v:K.bonus,c:'#EB2F96'}];
  var alFilt=alData.filter(function(a){return parseFloat(a.v)>0;});
  if(alFilt.length>0){var alTotal=alFilt.reduce(function(s,a){return s+parseFloat(a.v);},0);
    new Chart(document.getElementById('cAllow'),{type:'polarArea',data:{labels:alFilt.map(function(a){return a.l;}),datasets:[{data:alFilt.map(function(a){return parseFloat(a.v);}),backgroundColor:alFilt.map(function(a){return a.c+'B3';}),borderColor:alFilt.map(function(a){return a.c;}),borderWidth:1.5}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'right',labels:{usePointStyle:true,padding:8,font:{family:'Poppins',size:10}}},tooltip:{callbacks:{label:function(ctx){var pct=alTotal>0?(ctx.parsed/alTotal*100).toFixed(1):'0';return ctx.label+': $'+F(ctx.parsed)+' ('+pct+'%)';}}}},scales:{r:{ticks:{display:false},grid:{color:'rgba(0,0,0,0.05)'}}}}})}

  /* ── Chart: Pay Component Radar ── */
  var radarMax=Math.max(K.normal_pay||0,K.ot_pay||0,K.meal+K.stay+K.callout+K.premium||0,K.allow_fnpf+K.allow_nonfnpf||0,K.bonus||0,K.fnpf_emp+K.fnpf_er||0,K.tax||0);
  if(radarMax>0){new Chart(document.getElementById('cRadar'),{type:'radar',data:{labels:['Normal Pay','OT Pay','Allowances','Other Allow.','Bonus','FNPF','Tax'],datasets:[{label:CY,data:[K.normal_pay,K.ot_pay,K.meal+K.stay+K.callout+K.premium,K.allow_fnpf+K.allow_nonfnpf,K.bonus,K.fnpf_emp+K.fnpf_er,K.tax],backgroundColor:'rgba(42,171,179,0.2)',borderColor:'#2AABB3',borderWidth:2,pointBackgroundColor:'#2AABB3',pointBorderColor:'#fff',pointBorderWidth:2,pointRadius:4}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'top',labels:{usePointStyle:true,font:{family:'Poppins',size:11}}}},scales:{r:{grid:{color:'rgba(0,0,0,0.06)'},ticks:{display:false},pointLabels:{font:{family:'Poppins',size:10,weight:'500'}}}}}})}

  /* ═══ PERIODS TABLE ═══ */
  aP=P;fP=P.slice();pg=1;rP();
  function rP(){
    var tb=document.getElementById('pTB'),tot=fP.length;
    if(!tot){tb.innerHTML='<tr><td colspan="8"><div class="em"><div class="emi">📋</div><h4>No Pay Periods Found</h4></div></td></tr>';document.getElementById('pPI').textContent='No records';document.getElementById('pPB').innerHTML='';return;}
    var tp=Math.ceil(tot/pp);if(pg>tp)pg=tp;var s=(pg-1)*pp,e=Math.min(s+pp,tot),h='';
    for(var i=s;i<e;i++){var r=fP[i],ec=parseInt(r.emp_count||0),g=parseFloat(r.total_gross||0),n=parseFloat(r.total_net||0),t=parseFloat(r.total_tax||0),st=(r.status||'').toLowerCase(),cp=(st==='approved');
      h+='<tr onclick="prVP(\''+r.id+'\')">'+'<td><strong>#'+r.id+'</strong></td><td style="font-weight:500">'+(r.period||'Period #'+r.id)+'</td>'+'<td><span class="st '+sC(st)+'">'+sI(st)+' '+st+'</span></td>'+'<td>'+(ec>0?'<i class="fas fa-users" style="margin-right:5px;color:var(--pr)"></i>'+ec:'<span style="color:var(--tm)">–</span>')+'</td>'+'<td class="am">$'+F(g)+'</td><td class="am amg">$'+F(n)+'</td><td class="am" style="color:var(--or)">$'+F(t)+'</td>'+'<td onclick="event.stopPropagation()"><a class="ab abv" onclick="prVP(\''+r.id+'\')"><i class="fas fa-chart-bar"></i> View</a></td></tr>';}
    tb.innerHTML=h;
    document.getElementById('pPI').textContent='Showing '+(s+1)+'–'+e+' of '+tot;
    var ph='<button class="pgn" onclick="gP('+(pg-1)+')" '+(pg<=1?'disabled':'')+'>&laquo;</button>';var sp=Math.max(1,pg-2),ep=Math.min(tp,pg+2);
    if(sp>1){ph+='<button class="pgn" onclick="gP(1)">1</button>';if(sp>2)ph+='<span style="padding:0 6px;color:#9CA3AF">…</span>';}
    for(var p=sp;p<=ep;p++)ph+='<button class="pgn '+(p===pg?'ac':'')+'" onclick="gP('+p+')">'+p+'</button>';
    if(ep<tp){if(ep<tp-1)ph+='<span style="padding:0 6px;color:#9CA3AF">…</span>';ph+='<button class="pgn" onclick="gP('+tp+')">'+tp+'</button>';}
    ph+='<button class="pgn" onclick="gP('+(pg+1)+')" '+(pg>=tp?'disabled':'')+'>&raquo;</button>';document.getElementById('pPB').innerHTML=ph;
  }
  window.pFilt=function(){var q=document.getElementById('pSrch').value.toLowerCase();fP=aP.filter(function(r){return(r.id+'').indexOf(q)!==-1||(r.period||'').toLowerCase().indexOf(q)!==-1||(r.status||'').toLowerCase().indexOf(q)!==-1;});pg=1;rP();};
  window.gP=function(p){var tp=Math.ceil(fP.length/pp);if(p<1||p>tp)return;pg=p;rP();};
  window.pPPCh=function(){pp=parseInt(document.getElementById('pPPSel').value)||10;pg=1;rP();};
  window.prExCSV=function(){var hd=['ID','Period','Status','Employees','Gross','Net','Tax'],csv=[hd.join(',')];fP.forEach(function(r){csv.push([r.id,'"'+(r.period||'')+'"',r.status,r.emp_count,r.total_gross,r.total_net,r.total_tax].join(','));});var b=new Blob([csv.join('\n')],{type:'text/csv'}),a=document.createElement('a');a.href=URL.createObjectURL(b);a.download='payrun_periods.csv';a.click();};

  /* ═══ DETAIL VIEW (AJAX) ═══ */
  var _de=[],_df=[],_dp=1,_dpp=20;

  window.prVP=function(pid){
    document.getElementById('prMain').classList.remove('act');
    document.getElementById('prDetail').classList.add('act');
    var c=document.getElementById('prDC');
    c.innerHTML='<div class="prld"><div class="prld-sp"></div><p>Loading period #'+pid+' data...</p></div>';
    window.scrollTo({top:0,behavior:'smooth'});
    var kd=null,ed=null,dd=null,ld=0;
    function chk(){ld++;if(ld>=3)renderD(pid,kd,ed,dd);}
    api('period_kpis&pid='+pid,function(d){kd=d;chk();});
    api('period_employees&pid='+pid,function(d){ed=d||[];chk();});
    api('period_depts&pid='+pid,function(d){dd=d||[];chk();});
  };

  function renderD(pid,kpi,emps,depts){
    if(!kpi)kpi={};var c=document.getElementById('prDC');
    var st=(kpi.status||'unknown').toLowerCase(),cp=(st==='approved');
    var g=parseFloat(kpi.total_gross||0),n=parseFloat(kpi.total_net||0),t=parseFloat(kpi.total_tax||0);
    var fnpf=parseFloat(kpi.total_fnpf_emp||0)+parseFloat(kpi.total_fnpf_er||0),ec=parseInt(kpi.emp_count||0);
    var thHrs=parseFloat(kpi.total_th_hrs||0),dtHrs=parseFloat(kpi.total_dt_hrs||0),phHrs=parseFloat(kpi.total_ph_hrs||0);
    var thPay=parseFloat(kpi.total_th_pay||0),dtPay=parseFloat(kpi.total_dt_pay||0),phPay=parseFloat(kpi.total_ph_pay||0);
    var totalOTPay=thPay+dtPay,totalOTHrs=thHrs+dtHrs;
    var totalAllow=parseFloat(kpi.total_meal||0)+parseFloat(kpi.total_stayaway||0)+parseFloat(kpi.total_callout||0)+parseFloat(kpi.total_leave_allow||0)+parseFloat(kpi.total_allow_fnpf||0)+parseFloat(kpi.total_allow_nonfnpf||0);

    var h='<div class="dh"><div style="display:flex;align-items:center;gap:16px;flex-wrap:wrap">'
      +'<button class="bkb" onclick="prBack()"><i class="fas fa-arrow-left"></i> Back</button>'
      +'<div><h3>Period: '+(kpi.period_label||'#'+pid)+'</h3><span style="font-size:12px;opacity:0.8">ID: #'+pid+'</span></div></div>'
      +'<div style="display:flex;gap:10px;align-items:center"><span class="st '+sC(st)+'">'+sI(st)+' '+st+'</span></div></div>';

    /* ── Row 1: Core KPIs ── */
    h+='<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;padding:20px 0">'
      +'<div class="kc kb"><div class="ki"><i class="fas fa-users"></i></div><div class="kv"><h3>'+ec+'</h3><p>Employees</p></div></div>'
      +'<div class="kc kgn"><div class="ki"><i class="fas fa-dollar-sign"></i></div><div class="kv"><h3>$'+F(g)+'</h3><p>Total Gross</p></div></div>'
      +'<div class="kc kcy"><div class="ki"><i class="fas fa-hand-holding-usd"></i></div><div class="kv"><h3>$'+F(n)+'</h3><p>Total Net Pay</p></div></div>'
      +'<div class="kc ko"><div class="ki"><i class="fas fa-file-invoice-dollar"></i></div><div class="kv"><h3>$'+F(t)+'</h3><p>Total Tax</p></div></div></div>';

    /* ── Row 2: FNPF + Normal + OT Pay + Bonus ── */
    h+='<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;padding-bottom:20px">'
      +'<div class="kc kp"><div class="ki"><i class="fas fa-piggy-bank"></i></div><div class="kv"><h3>$'+F(fnpf)+'</h3><p>FNPF Total</p></div></div>'
      +'<div class="kc kgo"><div class="ki"><i class="fas fa-coins"></i></div><div class="kv"><h3>$'+F(kpi.total_normal_pay)+'</h3><p>Normal Pay</p></div></div>'
      +'<div class="kc kr"><div class="ki"><i class="fas fa-clock"></i></div><div class="kv"><h3>$'+F(totalOTPay)+'</h3><p>Overtime Pay</p></div></div>'
      +'<div class="kc kt"><div class="ki"><i class="fas fa-gift"></i></div><div class="kv"><h3>$'+F(kpi.total_bonus)+'</h3><p>Total Bonus</p></div></div></div>';

    /* ── Row 3: OT Hours Breakdown ── */
    h+='<div class="sec-hdr"><i class="fas fa-business-time"></i><h3>Overtime Hours &amp; Pay Breakdown</h3></div>';
    h+='<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;padding-bottom:20px">'
      +'<div class="kc ko"><div class="ki"><i class="fas fa-hourglass-half"></i></div><div class="kv"><h3>'+FH(thHrs)+' hrs</h3><p>Time &amp; Half Hours</p><span style="font-size:10px;color:var(--tm)">$'+F(thPay)+' pay</span></div></div>'
      +'<div class="kc kr"><div class="ki"><i class="fas fa-forward"></i></div><div class="kv"><h3>'+FH(dtHrs)+' hrs</h3><p>Double Time Hours</p><span style="font-size:10px;color:var(--tm)">$'+F(dtPay)+' pay</span></div></div>'
      +'<div class="kc kgo"><div class="ki"><i class="fas fa-star"></i></div><div class="kv"><h3>'+FH(phHrs)+' hrs</h3><p>Public Holiday Hrs</p><span style="font-size:10px;color:var(--tm)">$'+F(phPay)+' pay</span></div></div>'
      +'<div class="kc kgn"><div class="ki"><i class="fas fa-percent"></i></div><div class="kv"><h3>'+(g>0?(totalOTPay/g*100).toFixed(1):'0')+'%</h3><p>OT as % of Gross</p><span style="font-size:10px;color:var(--tm)">'+FH(totalOTHrs)+' total OT hrs</span></div></div></div>';

    /* ── Row 4: Allowances ── */
    h+='<div class="sec-hdr"><i class="fas fa-wallet"></i><h3>Allowances</h3><span class="sec-badge">$'+F(totalAllow)+' total</span></div>';
    h+='<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;padding-bottom:20px">'
      +'<div class="kc kcy"><div class="ki"><i class="fas fa-utensils"></i></div><div class="kv"><h3>$'+F(kpi.total_meal)+'</h3><p>Meal Allowance</p></div></div>'
      +'<div class="kc kp"><div class="ki"><i class="fas fa-bed"></i></div><div class="kv"><h3>$'+F(kpi.total_stayaway)+'</h3><p>Stay Allowance</p></div></div>'
      +'<div class="kc kgn"><div class="ki"><i class="fas fa-plus-circle"></i></div><div class="kv"><h3>$'+F(kpi.total_allow_fnpf)+'</h3><p>Other Allow (FNPF)</p></div></div>'
      +'<div class="kc kgo"><div class="ki"><i class="fas fa-minus-circle"></i></div><div class="kv"><h3>$'+F(kpi.total_allow_nonfnpf)+'</h3><p>Other Allow (Non-FNPF)</p></div></div></div>';

    /* ── Charts section ── */
    h+='<div class="g3">';
    /* OT Doughnut with % */
    h+='<div class="cd"><div class="cdh"><h4><i class="fas fa-chart-pie" style="margin-right:8px;color:var(--or)"></i>OT Pay Mix</h4></div><div class="cdb"><div class="chc"><canvas id="cOTMix"></canvas></div></div></div>';
    /* Gauge */
    h+='<div class="cd"><div class="cdh"><h4><i class="fas fa-tachometer-alt" style="margin-right:8px;color:var(--rd)"></i>OT Cost Gauge</h4></div><div class="cdb"><div class="gauge-wrap"><canvas id="cDGauge" width="240" height="150"></canvas><div class="gauge-val" id="dGVal">–</div><div class="gauge-lbl">OT % of Gross</div></div></div></div>';
    /* Allowance Polar */
    h+='<div class="cd"><div class="cdh"><h4><i class="fas fa-bullseye" style="margin-right:8px;color:var(--cy)"></i>Allowance Spread</h4></div><div class="cdb"><div class="chc"><canvas id="cDAllow"></canvas></div></div></div>';
    h+='</div>';

    h+='<div class="g3">';
    /* Pay Components doughnut */
    h+='<div class="cd"><div class="cdh"><h4><i class="fas fa-chart-pie" style="margin-right:8px;color:var(--bl)"></i>Pay Components</h4></div><div class="cdb"><div class="chc"><canvas id="cComp"></canvas></div></div></div>';
    /* Department bar */
    h+='<div class="cd"><div class="cdh"><h4><i class="fas fa-sitemap" style="margin-right:8px;color:var(--pu)"></i>By Department</h4></div><div class="cdb"><div class="chc"><canvas id="cPDept"></canvas></div></div></div>';
    /* Deductions list */
    var deds=[{l:'Income Tax',v:kpi.total_income_tax,c:'#FA8C16'},{l:'SRT Tax',v:kpi.total_srt,c:'#FAAD14'},{l:'ECAL Tax',v:kpi.total_ecal,c:'#FF7A45'},{l:'FNPF Employee',v:kpi.total_fnpf_emp,c:'#722ED1'},{l:'FNPF Employer',v:kpi.total_fnpf_er,c:'#B37FEB'},{l:'Fixed Deductions',v:kpi.total_fixed_ded,c:'#FF4D4F'},{l:'Other Deductions',v:kpi.total_other_ded,c:'#CF1322'}];
    var dedTotal=deds.reduce(function(s,d){return s+parseFloat(d.v||0);},0);
    h+='<div class="cd"><div class="cdh"><h4><i class="fas fa-receipt" style="margin-right:8px;color:var(--or)"></i>Deductions</h4></div><div class="cdb">';
    for(var i=0;i<deds.length;i++){var dv=parseFloat(deds[i].v||0);var dpct=dedTotal>0?(dv/dedTotal*100).toFixed(1):'0';
      h+='<div class="bdi"><div class="bdl"><div class="bdd" style="background:'+deds[i].c+'"></div>'+deds[i].l+'</div><div style="display:flex;align-items:center;gap:8px"><span style="font-size:11px;color:var(--tm)">'+dpct+'%</span><span class="bdv">$'+F(deds[i].v)+'</span></div></div>';}
    h+='</div></div></div>';

    /* ── Dept OT Breakdown ── */
    h+='<div class="cd"><div class="cdh"><h4><i class="fas fa-building" style="margin-right:8px;color:var(--pr)"></i>Department OT Breakdown</h4></div><div class="cdb"><div class="chc"><canvas id="cDeptOT"></canvas></div></div></div>';

    /* Employee table with pagination */
    h+='<div class="cd"><div class="ttb"><h4><i class="fas fa-users" style="margin-right:8px;color:var(--pr)"></i>Employee Details (<span id="dEC">'+emps.length+'</span>)</h4>'
      +'<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">'
      +'<div class="sb"><span class="si"><i class="fas fa-search"></i></span><input type="text" id="dES" placeholder="Search employees..." oninput="dEF()" /></div>'
      +'<select class="ppsel" id="dEPP" onchange="dEPPC()"><option value="20">20 / page</option><option value="50">50 / page</option><option value="100">100 / page</option></select>'
      +'<button class="ab abv" onclick="dECSV()"><i class="fas fa-download"></i> CSV</button></div></div>'
      +'<div class="tw"><table class="dtb"><thead><tr><th>Employee</th><th>Dept</th><th>Type</th><th>Hrs</th><th>Rate</th><th>Normal</th><th>T&frac12; Hrs</th><th>2x Hrs</th><th>OT $</th><th>Gross</th><th>Tax</th><th>FNPF</th><th>Net</th></tr></thead><tbody id="dETB"></tbody></table></div>'
      +'<div class="pg"><div class="pgi" id="dEPI"></div><div class="pgb" id="dEPB"></div></div></div>';

    c.innerHTML=h;
    _de=emps;_df=emps.slice();_dp=1;_dpp=20;rDE();

    /* ── Render detail charts ── */
    /* OT Pay Mix Doughnut */
    var otItems=[{l:'Time & Half',v:thPay,c:'#1890FF'},{l:'Double Time',v:dtPay,c:'#FF4D4F'},{l:'Public Holiday',v:phPay,c:'#FAAD14'},{l:'Premium',v:parseFloat(kpi.total_premium||0),c:'#722ED1'}];
    var otFilt=otItems.filter(function(x){return parseFloat(x.v)>0;});
    if(otFilt.length){var otT=otFilt.reduce(function(s,x){return s+parseFloat(x.v);},0);
      new Chart(document.getElementById('cOTMix'),{type:'doughnut',data:{labels:otFilt.map(function(x){return x.l;}),datasets:[{data:otFilt.map(function(x){return parseFloat(x.v);}),backgroundColor:otFilt.map(function(x){return x.c;}),borderWidth:2,borderColor:'#fff'}]},options:{responsive:true,maintainAspectRatio:false,cutout:'55%',plugins:{legend:{position:'bottom',labels:{usePointStyle:true,padding:8,font:{family:'Poppins',size:10}}},tooltip:{callbacks:{label:function(ctx){var pct=otT>0?(ctx.parsed/otT*100).toFixed(1):'0';return ctx.label+': $'+F(ctx.parsed)+' ('+pct+'%)';}}}}}});}

    /* Gauge */
    var dOTR=g>0?(totalOTPay/g*100):0;
    drawGauge('cDGauge','dGVal',dOTR);

    /* Allowance Polar */
    var da=[{l:'Meal',v:kpi.total_meal,c:'#13C2C2'},{l:'Stay Away',v:kpi.total_stayaway,c:'#722ED1'},{l:'Call-Out',v:kpi.total_callout,c:'#FA8C16'},{l:'Leave',v:kpi.total_leave_allow,c:'#52C41A'},{l:'Allow (FNPF)',v:kpi.total_allow_fnpf,c:'#1890FF'},{l:'Allow (Non-FNPF)',v:kpi.total_allow_nonfnpf,c:'#FAAD14'}];
    var daF=da.filter(function(x){return parseFloat(x.v||0)>0;});
    if(daF.length){var daT=daF.reduce(function(s,x){return s+parseFloat(x.v);},0);
      new Chart(document.getElementById('cDAllow'),{type:'polarArea',data:{labels:daF.map(function(x){return x.l;}),datasets:[{data:daF.map(function(x){return parseFloat(x.v);}),backgroundColor:daF.map(function(x){return x.c+'B3';}),borderColor:daF.map(function(x){return x.c;}),borderWidth:1.5}]},options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:'right',labels:{usePointStyle:true,padding:8,font:{family:'Poppins',size:10}}},tooltip:{callbacks:{label:function(ctx){var pct=daT>0?(ctx.parsed/daT*100).toFixed(1):'0';return ctx.label+': $'+F(ctx.parsed)+' ('+pct+'%)';}}}},scales:{r:{ticks:{display:false},grid:{color:'rgba(0,0,0,0.05)'}}}}})}

    /* Pay Components Doughnut */
    if(g>0){var cl=['Normal','T&Half','Double','PH','Premium','Allow','Meal','Leave'],cd=[parseFloat(kpi.total_normal_pay||0),thPay,dtPay,phPay,parseFloat(kpi.total_premium||0),parseFloat(kpi.total_allow_fnpf||0)+parseFloat(kpi.total_allow_nonfnpf||0),parseFloat(kpi.total_meal||0),parseFloat(kpi.total_leave_allow||0)],cc=['#2AABB3','#1890FF','#096DD9','#722ED1','#FA8C16','#13C2C2','#FAAD14','#52C41A'];
      var fl=[],fd=[],fc=[];for(var x=0;x<cd.length;x++){if(cd[x]>0){fl.push(cl[x]);fd.push(cd[x]);fc.push(cc[x]);}}
      var compT=fd.reduce(function(s,v){return s+v;},0);
      if(fd.length)new Chart(document.getElementById('cComp'),{type:'doughnut',data:{labels:fl,datasets:[{data:fd,backgroundColor:fc,borderWidth:2,borderColor:'#fff'}]},options:{responsive:true,maintainAspectRatio:false,cutout:'50%',plugins:{legend:{position:'bottom',labels:{usePointStyle:true,padding:8,font:{family:'Poppins',size:10}}},tooltip:{callbacks:{label:function(ctx){var pct=compT>0?(ctx.parsed/compT*100).toFixed(1):'0';return ctx.label+': $'+F(ctx.parsed)+' ('+pct+'%)';}}}}}});}

    /* Department bar */
    if(depts&&depts.length){new Chart(document.getElementById('cPDept'),{type:'bar',data:{labels:depts.map(function(r){return r.department||'?';}),datasets:[{label:'Gross',data:depts.map(function(r){return parseFloat(r.gross||0);}),backgroundColor:'rgba(42,171,179,0.7)',borderRadius:4},{label:'Net',data:depts.map(function(r){return parseFloat(r.net||0);}),backgroundColor:'rgba(82,196,26,0.7)',borderRadius:4}]},options:{responsive:true,maintainAspectRatio:false,indexAxis:depts.length>5?'y':'x',plugins:{legend:{position:'top',labels:{usePointStyle:true,font:{family:'Poppins',size:10}}}},scales:{x:{grid:{display:false}},y:{grid:{color:'#F3F4F6'}}}}});}

    /* Dept OT Breakdown horizontal stacked */
    if(depts&&depts.length){var dLabels=depts.map(function(r){return r.department||'?';});
      new Chart(document.getElementById('cDeptOT'),{type:'bar',data:{labels:dLabels,datasets:[{label:'Time & Half',data:depts.map(function(r){return parseFloat(r.th_pay||0);}),backgroundColor:'#1890FF',borderRadius:2},{label:'Double Time',data:depts.map(function(r){return parseFloat(r.dt_pay||0);}),backgroundColor:'#FF4D4F',borderRadius:2}]},options:{responsive:true,maintainAspectRatio:false,indexAxis:'y',plugins:{legend:{position:'top',labels:{usePointStyle:true,padding:10,font:{family:'Poppins',size:10}}},tooltip:{callbacks:{label:function(ctx){return ctx.dataset.label+': $'+F(ctx.parsed.x);}}}},scales:{x:{stacked:true,grid:{color:'#F3F4F6'},ticks:{font:{family:'Poppins',size:10},callback:function(v){return'$'+v.toLocaleString();}}},y:{stacked:true,grid:{display:false},ticks:{font:{family:'Poppins',size:9}}}}}});}
  }

  /* ── Paginated employee table ── */
  function rDE(){
    var tb=document.getElementById('dETB'),tot=_df.length;
    document.getElementById('dEC').textContent=tot;
    if(!tot){tb.innerHTML='<tr><td colspan="13"><div class="em"><div class="emi">👤</div><h4>No employee records</h4><p>Period may not be processed yet.</p></div></td></tr>';document.getElementById('dEPI').textContent='No records';document.getElementById('dEPB').innerHTML='';return;}
    var tp=Math.ceil(tot/_dpp);if(_dp>tp)_dp=tp;
    var s=(_dp-1)*_dpp,end=Math.min(s+_dpp,tot),h='';
    for(var j=s;j<end;j++){var e=_df[j],ot=parseFloat(e.timehalf_amount||0)+parseFloat(e.double_amount||0);
      var thH=parseFloat(e.timehalf_hours||0),dtH=parseFloat(e.double_hours||0);
      h+='<tr><td><span class="eav">'+ini(e.full_name)+'</span><span style="font-weight:500">'+e.full_name+'</span><br><span style="font-size:10px;color:var(--tm)">#'+e.employeeid+'</span></td>'
        +'<td>'+(e.department||'–')+'</td><td><span class="st '+(e.employee_type==='Timesheet'?'st-a':'st-pr')+'">'+e.employee_type+'</span></td>'
        +'<td>'+parseFloat(e.normal_hours||0).toFixed(1)+'</td><td>$'+F(e.base_wage)+'</td><td>$'+F(e.normal_pay)+'</td>'
        +'<td>'+(thH>0?'<span style="color:var(--bl);font-weight:600">'+thH.toFixed(1)+'</span>':'–')+'</td>'
        +'<td>'+(dtH>0?'<span style="color:var(--rd);font-weight:600">'+dtH.toFixed(1)+'</span>':'–')+'</td>'
        +'<td style="color:var(--or);font-weight:600">'+(ot>0?'$'+F(ot):'–')+'</td>'
        +'<td class="am">$'+F(e.totalgross_amount)+'</td><td style="color:var(--or)">$'+F(e.total_tax_to_withhold)+'</td>'
        +'<td style="color:var(--pu)">$'+F(e.employee_fnpf)+'</td><td class="am amg">$'+F(e.net_pay)+'</td></tr>';}
    tb.innerHTML=h;
    document.getElementById('dEPI').textContent='Showing '+(s+1)+'–'+end+' of '+tot+' employees';
    var ph='<button class="pgn" onclick="dEGP('+(_dp-1)+')" '+(_dp<=1?'disabled':'')+'>&laquo;</button>';
    var sp=Math.max(1,_dp-2),ep=Math.min(tp,_dp+2);
    if(sp>1){ph+='<button class="pgn" onclick="dEGP(1)">1</button>';if(sp>2)ph+='<span style="padding:0 6px;color:#9CA3AF">…</span>';}
    for(var p=sp;p<=ep;p++)ph+='<button class="pgn '+(p===_dp?'ac':'')+'" onclick="dEGP('+p+')">'+p+'</button>';
    if(ep<tp){if(ep<tp-1)ph+='<span style="padding:0 6px;color:#9CA3AF">…</span>';ph+='<button class="pgn" onclick="dEGP('+tp+')">'+tp+'</button>';}
    ph+='<button class="pgn" onclick="dEGP('+(_dp+1)+')" '+(_dp>=tp?'disabled':'')+'>&raquo;</button>';
    document.getElementById('dEPB').innerHTML=ph;
  }

  window.dEF=function(){var q=document.getElementById('dES').value.toLowerCase();_df=_de.filter(function(e){return(e.full_name||'').toLowerCase().indexOf(q)!==-1||(e.employeeid||'').toLowerCase().indexOf(q)!==-1||(e.department||'').toLowerCase().indexOf(q)!==-1||(e.employee_type||'').toLowerCase().indexOf(q)!==-1;});_dp=1;rDE();};
  window.dEGP=function(p){var tp=Math.ceil(_df.length/_dpp);if(p<1||p>tp)return;_dp=p;rDE();};
  window.dEPPC=function(){_dpp=parseInt(document.getElementById('dEPP').value)||20;_dp=1;rDE();};
  window.dECSV=function(){var hd=['PayID','EmpID','Name','Dept','Type','Hrs','Rate','Normal','TH_Hrs','DT_Hrs','OT_Pay','Gross','Tax','FNPF','Net'],csv=[hd.join(',')];_de.forEach(function(e){var ot=parseFloat(e.timehalf_amount||0)+parseFloat(e.double_amount||0);csv.push([e.payid,e.employeeid,'"'+e.full_name+'"','"'+(e.department||'')+'"',e.employee_type,e.normal_hours,e.base_wage,e.normal_pay,e.timehalf_hours||0,e.double_hours||0,ot.toFixed(2),e.totalgross_amount,e.total_tax_to_withhold,e.employee_fnpf,e.net_pay].join(','));});var b=new Blob([csv.join('\n')],{type:'text/csv'}),a=document.createElement('a');a.href=URL.createObjectURL(b);a.download='payrun_detail.csv';a.click();};
  window.prBack=function(){document.getElementById('prDetail').classList.remove('act');document.getElementById('prMain').classList.add('act');window.scrollTo({top:0,behavior:'smooth'});};

  /* Hide loading modal */
  if(window._prHL) window._prHL();
})();
</script>

<?php echo '</div></div></div>'; ?>
<div id="m_scroll_top" class="m-scroll-top"><i class="la la-arrow-up"></i></div>
<script src="includes/vendors/owl.carousel/dist/owl.carousel.js" type="text/javascript"></script>
</body></html>