<?php
/* PayRunsManual.php - General Staff Payroll with Dashboard
   Enhanced: React/Ant Design style dashboard with KPIs, charts, year comparison
   Pattern: Loading modal → flush → heavy queries → dashboard + xcrud table
   General staff: employee_type='Timesheet', weekly pay cycle, hours-based KPIs
   All existing xcrud buttons and nested tables preserved.
*/
error_reporting(E_ALL & ~E_NOTICE);
$PageSecurity = 0;

include('includes/session.inc');
$Title = _('ERP Home');

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

/* ═══════════════════════════════════════════
   PHASE 1: Output header + loading modal FIRST, then flush
   Browser sees the modal immediately while PHP crunches data
   ═══════════════════════════════════════════ */
include('includes/newheader.php');
?>

<!-- ═══ LOADING MODAL ═══ -->
<div id="gnLoadModal" style="position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(15,23,42,0.45);backdrop-filter:blur(4px);z-index:999999;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-hard-hat" 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="gnLoadBar" style="height:100%;width:0%;background:linear-gradient(90deg,#2AABB3,#1E8F96);border-radius:5px;transition:width 0.3s ease"></div>
    </div>
    <p id="gnLoadTxt" style="font-size:13px;color:#6B7280;margin:0;font-family:'Poppins',-apple-system,sans-serif;font-weight:500">Loading General Staff Payroll...</p>
  </div>
</div>
<script>
(function(){
  var bar=document.getElementById('gnLoadBar'),pct=8,txt=document.getElementById('gnLoadTxt');
  var iv=setInterval(function(){
    pct+=Math.random()*10+4;if(pct>88)pct=88;
    bar.style.width=pct+'%';
    if(pct>35&&txt.textContent.indexOf('data')<0)txt.textContent='Fetching payroll data...';
    if(pct>65&&txt.textContent.indexOf('chart')<0)txt.textContent='Rendering charts...';
  },250);
  window._gnLoadIv=iv;
  window._gnHideLoader=function(){
    clearInterval(iv);bar.style.width='100%';txt.textContent='Ready!';
    setTimeout(function(){
      var m=document.getElementById('gnLoadModal');
      if(m){m.style.opacity='0';setTimeout(function(){m.style.display='none';},350);}
    },300);
  };
})();
</script>
<?php
if(function_exists('ob_flush')){ob_flush();}
flush();

/* ═══════════════════════════════════════════
   PHASE 2: Heavy DB queries while modal is showing
   ═══════════════════════════════════════════ */
$db2 = new mysqli('localhost', 'sooggoo', '4Compassion*', 'evergreenint');
if ($db2->connect_error) { $db2 = null; }

$kpi_cur = array('periods'=>0,'employees'=>0,'gross'=>0,'net'=>0,'tax'=>0,'fnpf_emp'=>0,'fnpf_er'=>0,'deductions'=>0,
                  'normal_hrs'=>0,'ot15_hrs'=>0,'ot2_hrs'=>0,'overtime_pay'=>0);
$kpi_prev = array('periods'=>0,'employees'=>0,'gross'=>0,'net'=>0,'tax'=>0,'fnpf_emp'=>0,'fnpf_er'=>0,'deductions'=>0,
                  'normal_hrs'=>0,'ot15_hrs'=>0,'ot2_hrs'=>0,'overtime_pay'=>0);
$monthly_data = array();
$dept_data = array();
$recent_runs = array();
$hours_data = array();

if ($db2) {
    /* ── Current Year KPIs ── */
    $sql = "SELECT 
        COUNT(DISTINCT pd.id) AS periods,
        COUNT(DISTINCT pd.employeeid) AS employees,
        ROUND(SUM(pd.totalgross_amount),2) AS gross,
        ROUND(SUM(pd.net_pay),2) AS net,
        ROUND(SUM(pd.total_tax_to_withhold),2) AS tax,
        ROUND(SUM(pd.employee_fnpf),2) AS fnpf_emp,
        ROUND(SUM(pd.fnpf_employer),2) AS fnpf_er,
        ROUND(SUM(pd.fixed_deductions + pd.other_deductions),2) AS deductions,
        ROUND(SUM(pd.normal_hours),2) AS normal_hrs,
        ROUND(SUM(pd.timehalf_hours),2) AS ot15_hrs,
        ROUND(SUM(pd.double_hours),2) AS ot2_hrs,
        ROUND(SUM(pd.timehalf_amount + pd.double_amount),2) AS overtime_pay
    FROM payrun_details pd
    JOIN calendar_management cm ON pd.id = cm.id
    WHERE pd.employee_type = 'Timesheet'
    AND cm.period LIKE '%{$curYear}%'";
    $r = $db2->query($sql);
    if ($r && $row = $r->fetch_assoc()) {
        foreach ($row as $k => $v) {
            $kpi_cur[$k] = ($k === 'periods' || $k === 'employees') ? (int)$v : (float)$v;
        }
    }

    /* ── Previous Year KPIs ── */
    $sql2 = str_replace($curYear, $prevYear, $sql);
    $r2 = $db2->query($sql2);
    if ($r2 && $row2 = $r2->fetch_assoc()) {
        foreach ($row2 as $k => $v) {
            $kpi_prev[$k] = ($k === 'periods' || $k === 'employees') ? (int)$v : (float)$v;
        }
    }

    /* ── Monthly Trend (Current Year + Previous Year) ── */
    $sql3 = "SELECT 
        MONTH(cm.start_date) AS mn,
        YEAR(cm.start_date) AS yr,
        ROUND(SUM(pd.totalgross_amount),2) AS gross,
        ROUND(SUM(pd.net_pay),2) AS net,
        ROUND(SUM(pd.total_tax_to_withhold),2) AS tax,
        ROUND(SUM(pd.employee_fnpf),2) AS fnpf_emp,
        ROUND(SUM(pd.fnpf_employer),2) AS fnpf_er,
        ROUND(SUM(pd.normal_hours),2) AS normal_hrs,
        ROUND(SUM(pd.timehalf_hours),2) AS ot15_hrs,
        ROUND(SUM(pd.double_hours),2) AS ot2_hrs,
        ROUND(SUM(pd.timehalf_amount + pd.double_amount),2) AS overtime_pay,
        COUNT(DISTINCT pd.employeeid) AS emps
    FROM payrun_details pd
    JOIN calendar_management cm ON pd.id = cm.id
    WHERE pd.employee_type = 'Timesheet'
    AND (cm.period LIKE '%{$curYear}%' OR cm.period LIKE '%{$prevYear}%')
    GROUP BY yr, mn
    ORDER BY yr, mn";
    $r3 = $db2->query($sql3);
    if ($r3) {
        while ($row3 = $r3->fetch_assoc()) {
            $monthly_data[] = $row3;
        }
    }

    /* ── Department Breakdown (Current Year) ── */
    $sql4 = "SELECT 
        d.departmentname AS dept,
        ROUND(SUM(pd.totalgross_amount),2) AS gross,
        ROUND(SUM(pd.net_pay),2) AS net,
        COUNT(DISTINCT pd.employeeid) AS emps,
        ROUND(SUM(pd.normal_hours),2) AS normal_hrs,
        ROUND(SUM(pd.timehalf_hours + pd.double_hours),2) AS ot_hrs,
        ROUND(SUM(pd.timehalf_amount + pd.double_amount),2) 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 pd.employee_type = 'Timesheet'
    AND cm.period LIKE '%{$curYear}%'
    GROUP BY pd.department
    ORDER BY gross DESC
    LIMIT 10";
    $r4 = $db2->query($sql4);
    if ($r4) {
        while ($row4 = $r4->fetch_assoc()) {
            $dept_data[] = $row4;
        }
    }

    /* ── Recent Pay Runs (last 8 for weekly) ── */
    $sql5 = "SELECT 
        cm.id, cm.period, cm.start_date, cm.end_date, cm.status,
        ROUND(SUM(pd.totalgross_amount),2) AS gross,
        ROUND(SUM(pd.net_pay),2) AS net,
        ROUND(SUM(pd.total_tax_to_withhold),2) AS tax,
        ROUND(SUM(pd.normal_hours),2) AS normal_hrs,
        ROUND(SUM(pd.timehalf_hours + pd.double_hours),2) AS ot_hrs,
        COUNT(pd.payid) AS emp_count
    FROM calendar_management cm
    LEFT JOIN payrun_details pd ON cm.id = pd.id AND pd.employee_type = 'Timesheet'
    GROUP BY cm.id
    HAVING emp_count > 0
    ORDER BY cm.id DESC
    LIMIT 8";
    $r5 = $db2->query($sql5);
    if ($r5) {
        while ($row5 = $r5->fetch_assoc()) {
            $recent_runs[] = $row5;
        }
    }

    /* ── Monthly Hours Breakdown (Current Year for stacked chart) ── */
    $sql6 = "SELECT 
        MONTH(cm.start_date) AS mn,
        ROUND(SUM(pd.normal_hours),0) AS normal_hrs,
        ROUND(SUM(pd.timehalf_hours),0) AS ot15_hrs,
        ROUND(SUM(pd.double_hours),0) AS ot2_hrs,
        ROUND(SUM(pd.public_holiday_hours),0) AS ph_hrs
    FROM payrun_details pd
    JOIN calendar_management cm ON pd.id = cm.id
    WHERE pd.employee_type = 'Timesheet'
    AND cm.period LIKE '%{$curYear}%'
    GROUP BY mn
    ORDER BY mn";
    $r6 = $db2->query($sql6);
    if ($r6) {
        while ($row6 = $r6->fetch_assoc()) {
            $hours_data[] = $row6;
        }
    }

    $db2->close();
}

/* Encode for JS */
$js_kpi_cur  = json_encode($kpi_cur);
$js_kpi_prev = json_encode($kpi_prev);
$js_monthly  = json_encode($monthly_data);
$js_depts    = json_encode($dept_data);
$js_recent   = json_encode($recent_runs);
$js_hours    = json_encode($hours_data);
$js_curYear  = json_encode((int)$curYear);
$js_prevYear = json_encode((int)$prevYear);

/* ═══════════════════════════════════════════
   PHASE 3: Dashboard HTML + CSS + xcrud table
   ═══════════════════════════════════════════ */
?>

<script src="angular/angular.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>

<style>
/* ════════════ GENERAL STAFF PAYROLL DASHBOARD STYLES ════════════ */
:root {
  --gn-primary: #2AABB3;
  --gn-dark: #1E8F96;
  --gn-darker: #187278;
  --gn-light: #E6F7F8;
  --gn-success: #52C41A;
  --gn-warning: #FAAD14;
  --gn-danger: #FF4D4F;
  --gn-purple: #722ED1;
  --gn-blue: #1890FF;
  --gn-cyan: #13C2C2;
  --gn-orange: #FA8C16;
  --gn-border: #E5E7EB;
  --gn-text: #1F2937;
  --gn-text2: #6B7280;
  --gn-bg: #F8FAFC;
  --gn-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  --gn-shadow-md: 0 4px 12px rgba(0,0,0,0.08);
}

.gn-header {
  background: linear-gradient(135deg, #187278 0%, #2AABB3 50%, #1E8F96 100%);
  border-radius: 16px;
  padding: 28px 32px;
  margin: 0 0 20px 0;
  color: #fff;
  position: relative;
  overflow: hidden;
}
.gn-header::before {
  content: '';position: absolute;top: -50%;right: -10%;width: 300px;height: 300px;
  background: radial-gradient(circle, rgba(255,255,255,0.08) 0%, transparent 70%);border-radius: 50%;
}
.gn-header-inner { display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 1; }
.gn-header h2 { font-family: 'Poppins', sans-serif; font-size: 22px; font-weight: 600; margin: 0 0 4px 0; color: #fff; }
.gn-header p { font-size: 13px; opacity: 0.85; margin: 0; font-family: 'Poppins', sans-serif; }
.gn-breadcrumb { font-size: 12px; opacity: 0.7; margin-bottom: 8px; font-family: 'Poppins', sans-serif; }
.gn-date-badge { display: inline-block; background: rgba(255,255,255,0.15); border-radius: 20px; padding: 4px 14px; font-size: 12px; margin-top: 8px; backdrop-filter: blur(4px); }
.gn-pay-badge { display: inline-block; background: rgba(255,255,255,0.2); border-radius: 20px; padding: 4px 14px; font-size: 12px; margin-top: 8px; margin-left: 8px; }

.gn-toggle-wrap { text-align: center; margin: -10px 0 16px 0; }
.gn-toggle-btn {
  display: inline-flex; align-items: center; gap: 8px; padding: 8px 24px;
  background: #fff; border: 1px solid var(--gn-border); border-radius: 24px;
  font-family: 'Poppins', sans-serif; font-size: 13px; font-weight: 500;
  color: var(--gn-text); cursor: pointer; transition: all 0.2s; box-shadow: var(--gn-shadow);
}
.gn-toggle-btn:hover { border-color: var(--gn-primary); color: var(--gn-primary); box-shadow: var(--gn-shadow-md); }
.gn-toggle-btn i { transition: transform 0.3s; }
.gn-toggle-btn.collapsed i { transform: rotate(-90deg); }

.gn-dashboard { transition: max-height 0.5s ease, opacity 0.3s ease; overflow: hidden; }
.gn-dashboard.collapsed { max-height: 0 !important; opacity: 0; margin: 0; padding: 0; }

/* ── KPI Cards Grid ── */
.gn-kpi-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 20px;
}
@media (max-width: 1200px) { .gn-kpi-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px)  { .gn-kpi-grid { grid-template-columns: 1fr; } }

.gn-kpi-card {
  background: #fff; border-radius: 12px; padding: 18px 20px; display: flex;
  align-items: center; gap: 16px; border: 1px solid var(--gn-border);
  box-shadow: var(--gn-shadow); transition: all 0.2s; position: relative; overflow: hidden;
}
.gn-kpi-card:hover { box-shadow: var(--gn-shadow-md); transform: translateY(-2px); }
.gn-kpi-card::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; }
.gn-kpi-card.kpi-teal::before    { background: var(--gn-primary); }
.gn-kpi-card.kpi-blue::before    { background: var(--gn-blue); }
.gn-kpi-card.kpi-green::before   { background: var(--gn-success); }
.gn-kpi-card.kpi-cyan::before    { background: var(--gn-cyan); }
.gn-kpi-card.kpi-orange::before  { background: var(--gn-orange); }
.gn-kpi-card.kpi-purple::before  { background: var(--gn-purple); }
.gn-kpi-card.kpi-red::before     { background: var(--gn-danger); }
.gn-kpi-card.kpi-warning::before { background: var(--gn-warning); }

.gn-kpi-icon {
  width: 46px; height: 46px; border-radius: 12px; display: flex;
  align-items: center; justify-content: center; font-size: 20px; flex-shrink: 0;
}
.kpi-teal .gn-kpi-icon    { background: #E6F7F8; color: var(--gn-primary); }
.kpi-blue .gn-kpi-icon    { background: #E6F4FF; color: var(--gn-blue); }
.kpi-green .gn-kpi-icon   { background: #F0FFF4; color: var(--gn-success); }
.kpi-cyan .gn-kpi-icon    { background: #E6FFFB; color: var(--gn-cyan); }
.kpi-orange .gn-kpi-icon  { background: #FFF7E6; color: var(--gn-orange); }
.kpi-purple .gn-kpi-icon  { background: #F9F0FF; color: var(--gn-purple); }
.kpi-red .gn-kpi-icon     { background: #FFF1F0; color: var(--gn-danger); }
.kpi-warning .gn-kpi-icon { background: #FFFBE6; color: var(--gn-warning); }

.gn-kpi-info h3 { font-family: 'Poppins', sans-serif; font-size: 20px; font-weight: 700; margin: 0; color: var(--gn-text); line-height: 1.2; }
.gn-kpi-info p { font-family: 'Poppins', sans-serif; font-size: 12px; color: var(--gn-text2); margin: 2px 0 0 0; }
.gn-kpi-change { font-size: 11px; font-weight: 600; font-family: 'Poppins', sans-serif; margin-top: 2px; }
.gn-kpi-change.up   { color: var(--gn-success); }
.gn-kpi-change.down { color: var(--gn-danger); }
.gn-kpi-change.flat { color: var(--gn-text2); }

/* ── Cards ── */
.gn-card { background: #fff; border-radius: 12px; border: 1px solid var(--gn-border); box-shadow: var(--gn-shadow); margin-bottom: 16px; overflow: hidden; }
.gn-card-header { padding: 14px 20px; border-bottom: 1px solid var(--gn-border); display: flex; align-items: center; justify-content: space-between; }
.gn-card-header h4 { font-family: 'Poppins', sans-serif; font-size: 14px; font-weight: 600; margin: 0; color: var(--gn-text); }
.gn-card-body { padding: 16px 20px; }
.gn-chart-container { position: relative; height: 280px; }

/* ── Grid Layouts ── */
.gn-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; }
@media (max-width: 900px) { .gn-grid-2 { grid-template-columns: 1fr; } }
.gn-grid-3 { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; margin-bottom: 16px; }
@media (max-width: 900px) { .gn-grid-3 { grid-template-columns: 1fr; } }

/* ── Table ── */
.gn-table { width: 100%; border-collapse: collapse; font-family: 'Poppins', sans-serif; font-size: 13px; }
.gn-table th { background: var(--gn-bg); font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--gn-text2); padding: 10px 12px; text-align: left; border-bottom: 2px solid var(--gn-border); }
.gn-table td { padding: 10px 12px; color: var(--gn-text); border-bottom: 1px solid #F3F4F6; }
.gn-table tr:hover td { background: #F8FFFE; }
.gn-status-badge { display: inline-block; padding: 3px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; text-transform: capitalize; }
.gn-status-badge.completed, .gn-status-badge.approved { background: #F0FFF4; color: #389E0D; }
.gn-status-badge.pending { background: #FFFBE6; color: #D48806; }
.gn-status-badge.draft { background: #F0F0F0; color: #595959; }

/* ── Comparison Cards ── */
.gn-compare-row { display: flex; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.gn-compare-card { flex: 1; min-width: 140px; background: #fff; border: 1px solid var(--gn-border); border-radius: 10px; padding: 14px 16px; text-align: center; }
.gn-compare-card h5 { font-family: 'Poppins', sans-serif; font-size: 11px; font-weight: 600; color: var(--gn-text2); margin: 0 0 6px 0; text-transform: uppercase; letter-spacing: 0.5px; }
.gn-compare-card .val { font-family: 'Poppins', sans-serif; font-size: 18px; font-weight: 700; color: var(--gn-text); }
.gn-compare-card .yr { font-size: 11px; color: var(--gn-text2); margin-top: 2px; }

/* ── xcrud overlay ── */
.xcrud-ajax .dataTables_wrapper .dataTables_length, .xcrud-ajax .dataTables_wrapper .dataTables_filter { font-family: 'Poppins', sans-serif; font-size: 13px; }
.xcrud-ajax table.dataTable thead th { font-family: 'Poppins', sans-serif; font-size: 12px; }
.xcrud-ajax table.dataTable tbody td { font-family: 'Poppins', sans-serif; font-size: 13px; }
</style>

<div class="col-sm-12" style="font-family:'Poppins',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;">

  <!-- ════════════ HEADER BANNER ════════════ -->
  <div class="gn-header">
    <div class="gn-header-inner">
      <div>
        <div class="gn-breadcrumb">
          <span>HRMS</span>
          <span style="margin:0 6px;opacity:0.5">›</span>
          <span>Payroll</span>
          <span style="margin:0 6px;opacity:0.5">›</span>
          <span style="opacity:1">General Staff Pay Runs</span>
        </div>
        <h2><i class="fas fa-hard-hat" style="margin-right:10px;opacity:0.9"></i>General Staff Payroll</h2>
        <p>Process, manage, and track weekly timesheet-based pay runs for general staff</p>
        <div class="gn-date-badge"><i class="far fa-calendar-alt" style="margin-right:6px"></i><?php echo date('l, d M Y'); ?></div>
        <div class="gn-pay-badge"><i class="fas fa-sync-alt" style="margin-right:6px"></i>Weekly Pay Cycle</div>
      </div>
      <div>
        <span style="font-size:40px;opacity:0.15"><i class="fas fa-users-cog"></i></span>
      </div>
    </div>
  </div>

  <!-- ════════════ DASHBOARD TOGGLE ════════════ -->
  <div class="gn-toggle-wrap">
    <button class="gn-toggle-btn" id="gnToggleBtn" onclick="gnToggleDash()">
      <i class="fas fa-chevron-down"></i>
      <span>Dashboard Analytics</span>
    </button>
  </div>

  <!-- ════════════ COLLAPSIBLE DASHBOARD ════════════ -->
  <div class="gn-dashboard" id="gnDashboard">

    <!-- KPI Cards Row 1: Financial -->
    <div class="gn-kpi-grid" id="gnKpiGrid1">
      <div class="gn-kpi-card kpi-teal">
        <div class="gn-kpi-icon"><i class="fas fa-calendar-check"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiPeriods">–</h3><p>Pay Runs Processed</p><div class="gn-kpi-change" id="kpiPeriodsDelta"></div></div>
      </div>
      <div class="gn-kpi-card kpi-blue">
        <div class="gn-kpi-icon"><i class="fas fa-users"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiEmps">–</h3><p>Employees Paid</p><div class="gn-kpi-change" id="kpiEmpsDelta"></div></div>
      </div>
      <div class="gn-kpi-card kpi-green">
        <div class="gn-kpi-icon"><i class="fas fa-dollar-sign"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiGross">–</h3><p>Gross Pay (<?php echo $curYear; ?>)</p><div class="gn-kpi-change" id="kpiGrossDelta"></div></div>
      </div>
      <div class="gn-kpi-card kpi-cyan">
        <div class="gn-kpi-icon"><i class="fas fa-hand-holding-usd"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiNet">–</h3><p>Net Pay (<?php echo $curYear; ?>)</p><div class="gn-kpi-change" id="kpiNetDelta"></div></div>
      </div>
    </div>

    <!-- KPI Cards Row 2: Hours & Deductions -->
    <div class="gn-kpi-grid" id="gnKpiGrid2">
      <div class="gn-kpi-card kpi-orange">
        <div class="gn-kpi-icon"><i class="fas fa-clock"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiNormalHrs">–</h3><p>Normal Hours</p><div class="gn-kpi-change" id="kpiNormalHrsDelta"></div></div>
      </div>
      <div class="gn-kpi-card kpi-purple">
        <div class="gn-kpi-icon"><i class="fas fa-business-time"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiOvertimePay">–</h3><p>Overtime Pay (1.5x + 2x)</p><div class="gn-kpi-change" id="kpiOvertimePayDelta"></div></div>
      </div>
      <div class="gn-kpi-card kpi-red">
        <div class="gn-kpi-icon"><i class="fas fa-piggy-bank"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiFnpfTotal">–</h3><p>FNPF Total (8% + 10%)</p><div class="gn-kpi-change" id="kpiFnpfTotalDelta"></div></div>
      </div>
      <div class="gn-kpi-card kpi-warning">
        <div class="gn-kpi-icon"><i class="fas fa-file-invoice-dollar"></i></div>
        <div class="gn-kpi-info"><h3 id="kpiTax">–</h3><p>PAYE Tax Withheld</p><div class="gn-kpi-change" id="kpiTaxDelta"></div></div>
      </div>
    </div>

    <!-- Year Comparison Summary -->
    <div class="gn-compare-row">
      <div class="gn-compare-card">
        <h5>Total Cost to Company</h5>
        <div class="val" id="cmpCostCur">–</div>
        <div class="yr"><?php echo $curYear; ?> (Gross + FNPF ER)</div>
      </div>
      <div class="gn-compare-card">
        <h5>Total Cost to Company</h5>
        <div class="val" id="cmpCostPrev">–</div>
        <div class="yr"><?php echo $prevYear; ?></div>
      </div>
      <div class="gn-compare-card">
        <h5>Overtime Hours</h5>
        <div class="val" id="cmpOtCur">–</div>
        <div class="yr"><?php echo $curYear; ?> (1.5x + 2x)</div>
      </div>
      <div class="gn-compare-card">
        <h5>Overtime Hours</h5>
        <div class="val" id="cmpOtPrev">–</div>
        <div class="yr"><?php echo $prevYear; ?></div>
      </div>
      <div class="gn-compare-card">
        <h5>Avg Gross Per Employee</h5>
        <div class="val" id="cmpAvgCur">–</div>
        <div class="yr"><?php echo $curYear; ?></div>
      </div>
    </div>

    <!-- Charts Row 1: Gross/Net Trend + Hours Breakdown -->
    <div class="gn-grid-2">
      <div class="gn-card">
        <div class="gn-card-header">
          <h4><i class="fas fa-chart-line" style="margin-right:8px;color:var(--gn-primary)"></i>Monthly Gross vs Net (<?php echo $curYear; ?> vs <?php echo $prevYear; ?>)</h4>
        </div>
        <div class="gn-card-body"><div class="gn-chart-container"><canvas id="gnTrendChart"></canvas></div></div>
      </div>
      <div class="gn-card">
        <div class="gn-card-header">
          <h4><i class="fas fa-clock" style="margin-right:8px;color:var(--gn-orange)"></i>Monthly Hours Breakdown (<?php echo $curYear; ?>)</h4>
        </div>
        <div class="gn-card-body"><div class="gn-chart-container"><canvas id="gnHoursChart"></canvas></div></div>
      </div>
    </div>

    <!-- Charts Row 2: Tax/FNPF + Department -->
    <div class="gn-grid-3">
      <div class="gn-card">
        <div class="gn-card-header">
          <h4><i class="fas fa-list-alt" style="margin-right:8px;color:var(--gn-primary)"></i>Recent Pay Runs</h4>
        </div>
        <div class="gn-card-body" style="padding:0;overflow-x:auto;">
          <table class="gn-table" id="gnRecentTable">
            <thead><tr><th>Period</th><th>Dates</th><th>Status</th><th>Staff</th><th>Hrs</th><th>OT Hrs</th><th>Gross</th><th>Net</th></tr></thead>
            <tbody id="gnRecentBody"></tbody>
          </table>
        </div>
      </div>
      <div class="gn-card">
        <div class="gn-card-header">
          <h4><i class="fas fa-chart-pie" style="margin-right:8px;color:var(--gn-purple)"></i>By Department (<?php echo $curYear; ?>)</h4>
        </div>
        <div class="gn-card-body"><div class="gn-chart-container"><canvas id="gnDeptChart"></canvas></div></div>
      </div>
    </div>

  </div><!-- end dashboard -->

  <!-- ════════════ XCRUD TABLE (ALL ORIGINAL BUTTONS PRESERVED) ════════════ -->
<?php
include('xcrud/xcrud.php');
$userid = $_SESSION['UserID'];

if ($userid == 'admin' || $userid == 'ravinesh' || $userid == 'rajnal' || $userid == 'jprasad' || $userid == 'pritika' || $userid == 'pchand' || $userid == 'sharukh' ) {
    $ebusiness = Xcrud::get_instance();
    $ebusiness->table('calendar_management');
    $ebusiness->table_name('Payrun - General','Rostering','icon-leaf');
    $ebusiness->order_by('id','desc');
    $ebusiness->change_type('status','select','approved','approved');
    $ebusiness->set_attr('period',array('id'=>'period'));
    $ebusiness->set_attr('start_date',array('id'=>'startdate'));
    $ebusiness->set_attr('end_date',array('id'=>'enddate'));
    $ebusiness->unset_remove();
    $ebusiness->unset_add();
    $ebusiness->set_attr('created_by',array('id'=>'user'));
    $ebusiness->set_attr('date_created',array('id'=>'date'));

    $userid = $_SESSION['UserID'];
    $ebusiness->pass_default('created_by',$userid);
    $ebusiness->pass_var('created_by',$userid );

    $timenow = date('Y-m-d H:i:s');
    $ebusiness->pass_default('date_created',$timenow);
    $ebusiness->pass_var('date_created',$timenow );
    $ebusiness->disabled('date_created,created_by,period,start_date,end_date');
    $ebusiness->load_view('edit','calendar.php');
    $ebusiness->load_view('create','calendar.php');
    $ebusiness->load_view('view','calendar.php');

    $ebusiness->column_pattern('id', '<a href="#" class="xcrud-action" data-task="view" data-primary="{id}">{value}</a>');

    // Process Pay buttons - restricted to admin/jprasad
    if ($userid == 'admin' || $userid == 'jprasad'){
        $ebusiness->button('ProcessPayManual.php?id={id}&status={status}', 'Process Pay','glyphicon glyphicon-refresh','post');
        $ebusiness->button('ProcessPayManual-MissOuts.php?id={id}&status={status}', 'Process Pay','glyphicon glyphicon-refresh','post');
    }

    $ebusiness->button('PaySlips.php?id={id}', 'Print All Payslip','glyphicon glyphicon-download','payslip');
    $ebusiness->button('EmailPaySlips.php?id={id}', 'Email All Payslip','glyphicon glyphicon-envelope','payslipemail');
    $ebusiness->button('PaySlipsNoEmail.php?id={id}', 'Print Payslip for non email adress','glyphicon glyphicon-download','payslip');
    $ebusiness->button('Westpac.php?id={id}&startdate={start_date}&enddate={end_date}', 'Generate Westpac Quickpay File','glyphicon glyphicon-upload','post');
    $ebusiness->button('EmailWestpac.php?id={id}', 'Email Westpac Quickpay File','glyphicon glyphicon-envelope','post');
    $ebusiness->button('CheckTimesheet.php?id={id}&status={status}', 'Check employees in Adjustment that is not in Timesheet','	glyphicon glyphicon-filter','post');
    $ebusiness->button('CheckAbsent.php?id={id}&status={status}', 'Check employees in Leave Management that is not in Timesheet','	glyphicon glyphicon-filter','post');
    $ebusiness->button('CheckTimesheetPayRun.php?id={id}&status={status}', 'Check employees not in this pay','	glyphicon glyphicon-filter','post');

    $ebusiness1 = $ebusiness->nested_table('Employees','id','payrun_details','id');
    $ebusiness1->table_name('Employees in this Pay Run','Payrol','icon-leaf');
    $ebusiness1->where("payrun_details.employee_type = 'Timesheet'");
    $ebusiness1->disabled('payid,entered_by,last_update');
    $ebusiness1->relation('employeeid','employeemaster','employeeid','employeeid');
    $ebusiness1->button('PaySlipsIndividual.php?payid={payid}&employeeid={employeeid}', 'Print Payslip','glyphicon glyphicon-download','payslip');
    $ebusiness1->button('EmailPaySlipsIndividualNew.php?payid={payid}&employeeid={employeeid}', 'Email Payslip Second System','glyphicon glyphicon-envelope','payslipemail');

    $ebusiness->limit_list('20,50,100,1000');
    $ebusiness1->limit_list('20,50,100,1000');

    $ebusiness1->label('totalgross_amount','Total Gross Plus Bonus');
    $ebusiness1->sum('normal_pay,premium,stay_away,normal_hours,timehalf_hours,double_hours,timehalf_amount,double_amount,stay_away,leave_allowances,sick_leave,bl_leave,annual_leave,paternity_leave,maternity_leave,family_care_leave,other_allowances_fnpf,other_allowances_nonfnpf,meal_allowance,totalgross_amount,employee_fnpf,fnpf_employer,fixed_deductions,net_pay');
    $ebusiness1->relation('department','department','departmentid','departmentname');
    $ebusiness1->pass_var('entered_by',$userid );
    $ebusiness1->pass_var('last_update',$timenow);
    $ebusiness1->column_pattern('payid', '<a href="#" class="xcrud-action" data-task="view" data-primary="{payid}">{value}</a>');

    $ebusiness2 = $ebusiness1->nested_table('Employees Extra','payid','payrun_details_extra','payid');
    $ebusiness2->column_pattern('timesheet_id', '<a href="#" class="xcrud-action" data-task="view" data-primary="{p_id}">{value}</a>');
    $ebusiness2->relation('name','fixed_deduction_codecategory','id',array('name','code'));
    $ebusiness2->sum('amount');

    $ebusiness3 = $ebusiness2->nested_table('Employees Timesheet','timesheet_id','timesheetsuva','timesuvaid');
    $ebusiness3->unset_remove();

    $rostering_timesheet = $ebusiness3->nested_table('rostering_timesheet','timesuvaid','timesheetsuvadetails','timesuvaid');
    $rostering_timesheet->relation('employeeid','employeemaster','employeeid','employeeid');

    $rostering_timesheet->highlight('montime_in','>=','00:00:00','white');
    $rostering_timesheet->highlight('montime_in','>=','07:00:00','#00d8ff');
    $rostering_timesheet->highlight('montime_in','>=','12:00:00','#28B463');
    $rostering_timesheet->highlight('montime_in','>=','15:00:00','#FFFF33');

    $rostering_timesheet->highlight('tuestime_in','>=','00:00:00','white');
    $rostering_timesheet->highlight('tuestime_in','>=','07:00:00','#00d8ff');
    $rostering_timesheet->highlight('tuestime_in','>=','12:00:00','#28B463');
    $rostering_timesheet->highlight('tuestime_in','>=','15:00:00','#FFFF33');

    $rostering_timesheet->highlight('wedtime_in','>=','00:00:00','white');
    $rostering_timesheet->highlight('wedtime_in','>=','07:00:00','#00d8ff');
    $rostering_timesheet->highlight('wedtime_in','>=','12:00:00','#28B463');
    $rostering_timesheet->highlight('wedtime_in','>=','15:00:00','#FFFF33');

    $rostering_timesheet->highlight('thurstime_in','>=','00:00:00','white');
    $rostering_timesheet->highlight('thurstime_in','>=','07:00:00','#00d8ff');
    $rostering_timesheet->highlight('thurstime_in','>=','12:00:00','#28B463');
    $rostering_timesheet->highlight('thurstime_in','>=','15:00:00','#FFFF33');

    $rostering_timesheet->highlight('fritime_in','>=','00:00:00','white');
    $rostering_timesheet->highlight('fritime_in','>=','07:00:00','#00d8ff');
    $rostering_timesheet->highlight('fritime_in','>=','12:00:00','#28B463');
    $rostering_timesheet->highlight('fritime_in','>=','15:00:00','#FFFF33');

    $rostering_timesheet->highlight('sattime_in','>=','00:00:00','white');
    $rostering_timesheet->highlight('sattime_in','>=','07:00:00','#00d8ff');
    $rostering_timesheet->highlight('sattime_in','>=','12:00:00','#28B463');
    $rostering_timesheet->highlight('sattime_in','>=','15:00:00','#FFFF33');

    $rostering_timesheet->highlight('sunttime_in','>=','00:00:00','white');
    $rostering_timesheet->highlight('sunttime_in','>=','07:00:00','#00d8ff');
    $rostering_timesheet->highlight('sunttime_in','>=','12:00:00','#28B463');
    $rostering_timesheet->highlight('sunttime_in','>=','15:00:00','#FFFF33');

    $rostering_timesheet->before_insert('calculate_totalhoursperweek','functionstimesheetsuva.php');
    $rostering_timesheet->before_update('calculate_totalhoursperweek','functionstimesheetsuva.php');

    $rostering_timesheet->sum('mon_total,tues_total,wed_total,thurs_total,fri_total,sat_total,sun_total,total_hrs');
    $rostering_timesheet->columns('mon_gap,tues_gap,wed_gap,thurs_gap,fri_gap,sat_gap,sun_gap',true);
    $rostering_timesheet->table_name('Employee scheduling');
    $rostering_timesheet->duplicate_button();
    $rostering_timesheet->disabled('mon_total,tues_total,wed_total,thurs_total,fri_total,sat_total,sun_total,total_hrs,modified_by,date_modified');

    $rostering_timesheet->pass_default('modified_by',$userid);
    $rostering_timesheet->pass_var('modified_by',$userid );
    $timenow = date('Y-m-d H:i:s');
    $rostering_timesheet->pass_default('date_modified',$timenow);
    $rostering_timesheet->pass_var('date_modified',$timenow );

    $ebusiness3->relation('department','department','departmentid','departmentname');
    $ebusiness3->relation('internal_location','internal_location','id','location');
    $ebusiness3->relation('sectors','sectors','id','name');
    $ebusiness3->relation('jobno','projectdetails','projectid',array('projectid','project_name'));
    $ebusiness3->change_type('job_type ','select','Contracts','Contracts,FAS Small Jobs,FAS Surveys,Fire Training,FAS Testing,Extinguisher Servicing,Extinguisher Sales,Warranty Test,Leave');
    $ebusiness3->relation('patrol_location','guardforceclient','clientid',array('customername','patrollocation'),'','','','','','sectors','sectors');
    $ebusiness3->relation('required_guards','guardforceclient','req_guards','req_guards','','','','','','clientid','patrol_location');

    $ebusiness3->table_name('Timesheet by Location ','Employee Timesheet Scheduling','icon-leaf');
    $ebusiness3->change_type('status','select','pending','pending,approved,locked');

    // User-based department restrictions
    if ($userid=='kelera' ||$userid=='filiti'||$userid=='jona'){
        $ebusiness3->disabled('sectors,patrol_location,required_guards,jobno,job_type');
        $ebusiness3->where('department=','11');
        $rostering_timesheet->relation('employeeid','employeemaster','employeeid','employeeid',array('department' => '11'));
        $ebusiness3->pass_default('department','11');
        $ebusiness3->pass_var('department','11');
        $ebusiness3->pass_default('internal_location','3');
        $ebusiness3->pass_var('internal_location','3');
    }
    if ($userid=='controlroom'){
        $ebusiness3->disabled('sectors,patrol_location,required_guards,jobno,job_type');
        $ebusiness3->where('department=','1');
        $ebusiness3->pass_default('department','1');
        $ebusiness3->pass_var('department','1');
        $ebusiness3->pass_default('internal_location','4');
        $ebusiness3->pass_var('internal_location','4');
    }
    if ($userid=='ilimo' ||$userid=='vicky'){
        $ebusiness3->disabled('internal_location,jobno,job_type');
        $ebusiness3->where("timesheetsuva.department  = 1 OR timesheetsuva.department = 4");
        $ebusiness3->relation('department','department','departmentid','departmentname','department.departmentid = 4 OR  department.departmentid = 1');
        $rostering_timesheet->relation('employeeid','employeemaster','employeeid','employeeid');
    }
    if ($userid=='installssuva'){
        $ebusiness3->disabled('sectors,patrol_location,required_guards,internal_location');
        $ebusiness3->where('department=','9');
        $rostering_timesheet->relation('employeeid','employeemaster','employeeid','employeeid',array('job_role' => 'Technician'));
        $ebusiness3->pass_default('department','9');
        $ebusiness3->pass_var('department','9');
    }
    if ($userid=='installswest'){
        $ebusiness3->disabled('sectors,patrol_location,required_guards,internal_location');
        $ebusiness3->where('department=','10');
        $rostering_timesheet->relation('employeeid','employeemaster','employeeid','employeeid',array('job_role' => 'Technician'));
        $ebusiness3->pass_default('department','10');
        $ebusiness3->pass_var('department','10');
    }
    if ($userid=='schand'){
        $ebusiness3->disabled('sectors,patrol_location,required_guards,internal_location');
        $ebusiness3->where('department=','6');
        $rostering_timesheet->relation('employeeid','employeemaster','employeeid','employeeid',array('job_role' => 'Technician'));
        $ebusiness3->pass_default('department','6');
        $ebusiness3->pass_var('department','6');
    }
    if ($userid=='charles'){
        $ebusiness3->disabled('sectors,patrol_location,required_guards,internal_location');
        $ebusiness3->where('department=','7');
        $rostering_timesheet->relation('employeeid','employeemaster','employeeid','employeeid',array('job_role' => 'Technician'));
        $ebusiness3->pass_default('department','7');
        $ebusiness3->pass_var('department','7');
    }
    if ($userid=='akumar'){
        $ebusiness3->where("rostering.department  = 8 OR rostering.department = 3 OR rostering.department = 21" );
        $ebusiness3->relation('department','department','departmentid','departmentname','department.departmentid = 3 OR  department.departmentid = 8OR  department.departmentid = 21');
    }
    if ($userid=='saula'){
        $ebusiness3->disabled('sectors,required_guards');
        $ebusiness3->where("rostering.department  = 4 " );
        $ebusiness3->relation('department','department','departmentid','departmentname','department.departmentid = 4');
    }

    $rostering_timesheet->unset_print();
    $rostering_timesheet->unset_csv();
    $rostering_timesheet->benchmark(true);

    $ebusiness3->highlight('total_hrs','=',48,'#99FF66');
    $ebusiness3->highlight('total_hrs','>',48,'#ffe6f2');
    $ebusiness3->highlight('total_hrs','<',48,'#e6fff2');
    $ebusiness3->highlight_row('total_hrs','<',48,'white');

    $ebusiness3->disabled('last_modified_by,lastupdate');
    $ebusiness3->show_primary_ai_column(true);
    $ebusiness3->column_pattern('timesuvaid', '<a href="#" class="xcrud-action" data-task="view" data-primary="{timesuvaid}">{value}</a>');
    $ebusiness3->load_view('create','timesheet.php');
    $ebusiness3->load_view('edit','timesheet.php');
    $ebusiness3->load_view('view','timesheet.php');

    $ebusiness3->set_attr('internal_location',array('id'=>'internal'));
    $ebusiness3->set_attr('sectors',array('id'=>'sectors'));
    $ebusiness3->set_attr('patrol_location',array('id'=>'patrollocation'));
    $ebusiness3->set_attr('account_number',array('id'=>'account'));
    $ebusiness3->set_attr('id',array('id'=>'id'));
    $ebusiness3->set_attr('account_number',array('id'=>'account'));
    $ebusiness3->set_attr('status',array('id'=>'status'));
    $rostering_timesheet->show_primary_ai_column(false);
    $rostering_timesheet->load_view('list','rosteringlist.php');
    $rostering_timesheet->load_view('edit','timesheetsuvadetailedit.php');
    $rostering_timesheet->load_view('create','timesheetsuvadetailedit.php');
    $rostering_timesheet->load_view('view','timesheetsuvadetailedit.php');
    $ebusiness3->unset_print();
    $ebusiness3->unset_csv();
    $ebusiness3->duplicate_button();

    $userid = $_SESSION['UserID'];
    $ebusiness3->pass_var('last_modified_by',$userid );
    $timenow = date('Y-m-d H:i:s');
    $ebusiness3->order_by('timesuvaid','desc');
    $ebusiness3->pass_var('lastupdate',$timenow);
    $ebusiness3->column_class('sectors','align-center font-bold ');

    $ebusiness3->button('PDFPrintTimesheet-GFS.php?rosterid={timesuvaid}', 'Print Timesheet PDF','glyphicon glyphicon-download-alt','approve');
    $ebusiness3->button('PrintTimesheetExcel-GFS.php?rosterid={timesuvaid}', 'Print Timesheet Excel','glyphicon glyphicon-export','payslipemail');

    $rostering_timesheet->set_attr('employeeid',array('id'=>'employeeid'));
    $rostering_timesheet->set_attr('timesuvaid',array('id'=>'rosterid'));
    $rostering_timesheet->set_attr('calendar_id',array('id'=>'calendarid'));
    $rostering_timesheet->set_attr('montime_in',array('id'=>'monin'));
    $rostering_timesheet->set_attr('montime_out',array('id'=>'monout'));
    $rostering_timesheet->set_attr('mon_total',array('id'=>'montotal'));
    $rostering_timesheet->set_attr('tuestime_in',array('id'=>'tuesin'));
    $rostering_timesheet->set_attr('tuestime_out',array('id'=>'tuesout'));
    $rostering_timesheet->set_attr('tues_total',array('id'=>'tuestotal'));
    $rostering_timesheet->set_attr('wedtime_in',array('id'=>'wedin'));
    $rostering_timesheet->set_attr('wedtime_out',array('id'=>'wedout'));
    $rostering_timesheet->set_attr('wed_total',array('id'=>'wedtotal'));
    $rostering_timesheet->set_attr('thurstime_in',array('id'=>'thursin'));
    $rostering_timesheet->set_attr('thurstime_out',array('id'=>'thursout'));
    $rostering_timesheet->set_attr('thurs_total',array('id'=>'thurstotal'));
    $rostering_timesheet->set_attr('fritime_in',array('id'=>'friin'));
    $rostering_timesheet->set_attr('fritime_out',array('id'=>'friout'));
    $rostering_timesheet->set_attr('fri_total',array('id'=>'fritotal'));
    $rostering_timesheet->set_attr('sattime_in',array('id'=>'satin'));
    $rostering_timesheet->set_attr('sattime_out',array('id'=>'satout'));
    $rostering_timesheet->set_attr('sat_total',array('id'=>'sattotal'));
    $rostering_timesheet->set_attr('sunttime_in',array('id'=>'sunin'));
    $rostering_timesheet->set_attr('sunttime_out',array('id'=>'sunout'));
    $rostering_timesheet->set_attr('sun_total',array('id'=>'suntotal'));
    $rostering_timesheet->set_attr('calendar_id',array('id'=>'calendarid'));
    $rostering_timesheet->set_attr('locked',array('id'=>'locked'));

    $rostering_timesheet->column_class('employeeid,wed_total,tues_total','align-center font-bold ');
    $rostering_timesheet->column_pattern('employeeid', '<a href="#" class="xcrud-action" data-task="edit" data-primary="{id}">{value}</a>');
    $rostering_timesheet->unset_remove();

    echo $ebusiness->render();
} else {
    echo "Not Authorized to view this content";
}
?>

</div><!-- end col-sm-12 -->

<!-- ════════════ DASHBOARD JAVASCRIPT ════════════ -->
<script>
(function(){
  var kpiCur  = <?php echo $js_kpi_cur; ?>;
  var kpiPrev = <?php echo $js_kpi_prev; ?>;
  var monthly = <?php echo $js_monthly; ?>;
  var depts   = <?php echo $js_depts; ?>;
  var recent  = <?php echo $js_recent; ?>;
  var hoursData = <?php echo $js_hours; ?>;
  var CY      = <?php echo $js_curYear; ?>;
  var PY      = <?php echo $js_prevYear; ?>;

  var MONTHS = ['','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];

  function fmt(n){
    if(n===null||n===undefined)return'$0';
    return '$'+Number(n).toLocaleString('en-US',{minimumFractionDigits:0,maximumFractionDigits:0});
  }
  function fmtK(n){
    if(!n)return'$0';
    if(n>=1000000)return'$'+(n/1000000).toFixed(1)+'M';
    if(n>=1000)return'$'+(n/1000).toFixed(1)+'K';
    return fmt(n);
  }
  function fmtHrs(n){
    if(!n)return'0';
    return Number(n).toLocaleString('en-US',{maximumFractionDigits:0});
  }
  function delta(cur,prev){
    if(!prev||prev===0)return{cls:'flat',txt:'—'};
    var pct=((cur-prev)/prev*100).toFixed(1);
    if(pct>0)return{cls:'up',txt:'↑ '+pct+'% vs '+PY};
    if(pct<0)return{cls:'down',txt:'↓ '+Math.abs(pct)+'% vs '+PY};
    return{cls:'flat',txt:'→ No change'};
  }
  function setKPI(id,val,deltaId,cur,prev){
    var el=document.getElementById(id);if(el)el.textContent=val;
    if(deltaId){
      var d=delta(cur,prev);
      var del=document.getElementById(deltaId);
      if(del){del.className='gn-kpi-change '+d.cls;del.textContent=d.txt;}
    }
  }

  /* ── Populate KPIs ── */
  setKPI('kpiPeriods',kpiCur.periods,'kpiPeriodsDelta',kpiCur.periods,kpiPrev.periods);
  setKPI('kpiEmps',kpiCur.employees,'kpiEmpsDelta',kpiCur.employees,kpiPrev.employees);
  setKPI('kpiGross',fmtK(kpiCur.gross),'kpiGrossDelta',kpiCur.gross,kpiPrev.gross);
  setKPI('kpiNet',fmtK(kpiCur.net),'kpiNetDelta',kpiCur.net,kpiPrev.net);
  setKPI('kpiNormalHrs',fmtHrs(kpiCur.normal_hrs),'kpiNormalHrsDelta',kpiCur.normal_hrs,kpiPrev.normal_hrs);
  setKPI('kpiOvertimePay',fmtK(kpiCur.overtime_pay),'kpiOvertimePayDelta',kpiCur.overtime_pay,kpiPrev.overtime_pay);
  var fnpfTotalCur = kpiCur.fnpf_emp + kpiCur.fnpf_er;
  var fnpfTotalPrev = kpiPrev.fnpf_emp + kpiPrev.fnpf_er;
  setKPI('kpiFnpfTotal',fmtK(fnpfTotalCur),'kpiFnpfTotalDelta',fnpfTotalCur,fnpfTotalPrev);
  setKPI('kpiTax',fmtK(kpiCur.tax),'kpiTaxDelta',kpiCur.tax,kpiPrev.tax);

  /* ── Comparison Cards ── */
  document.getElementById('cmpCostCur').textContent = fmtK(kpiCur.gross + kpiCur.fnpf_er);
  document.getElementById('cmpCostPrev').textContent = fmtK(kpiPrev.gross + kpiPrev.fnpf_er);
  var otCur = kpiCur.ot15_hrs + kpiCur.ot2_hrs;
  var otPrev = kpiPrev.ot15_hrs + kpiPrev.ot2_hrs;
  document.getElementById('cmpOtCur').textContent = fmtHrs(otCur)+' hrs';
  document.getElementById('cmpOtPrev').textContent = fmtHrs(otPrev)+' hrs';
  document.getElementById('cmpAvgCur').textContent = kpiCur.employees>0 ? fmtK(kpiCur.gross/kpiCur.employees) : '$0';

  /* ── Recent Runs Table ── */
  var tbody = document.getElementById('gnRecentBody');
  if(tbody && recent.length){
    var html='';
    for(var i=0;i<recent.length;i++){
      var r=recent[i];
      var sc=(r.status||'').toLowerCase();
      var badge='<span class="gn-status-badge '+(sc==='approved'||sc==='completed'?'completed':sc==='pending'?'pending':'draft')+'">'+r.status+'</span>';
      html+='<tr>';
      html+='<td style="font-weight:600">'+r.period+'</td>';
      html+='<td style="font-size:12px">'+r.start_date+' – '+r.end_date+'</td>';
      html+='<td>'+badge+'</td>';
      html+='<td style="text-align:center">'+r.emp_count+'</td>';
      html+='<td style="text-align:right">'+fmtHrs(r.normal_hrs)+'</td>';
      html+='<td style="text-align:right">'+fmtHrs(r.ot_hrs)+'</td>';
      html+='<td style="font-weight:600">'+fmt(r.gross)+'</td>';
      html+='<td>'+fmt(r.net)+'</td>';
      html+='</tr>';
    }
    tbody.innerHTML=html;
  } else if(tbody){
    tbody.innerHTML='<tr><td colspan="8" style="text-align:center;color:#9CA3AF;padding:24px">No recent pay runs found</td></tr>';
  }

  /* ── Monthly Trend Chart (CY vs PY) ── */
  var cyGross=new Array(12).fill(0), cyNet=new Array(12).fill(0);
  var pyGross=new Array(12).fill(0), pyNet=new Array(12).fill(0);
  for(var i=0;i<monthly.length;i++){
    var m=monthly[i];
    var idx=parseInt(m.mn)-1;
    if(parseInt(m.yr)===CY){cyGross[idx]=parseFloat(m.gross)||0;cyNet[idx]=parseFloat(m.net)||0;}
    else if(parseInt(m.yr)===PY){pyGross[idx]=parseFloat(m.gross)||0;pyNet[idx]=parseFloat(m.net)||0;}
  }
  var trendCtx=document.getElementById('gnTrendChart');
  if(trendCtx){
    new Chart(trendCtx,{
      type:'bar',
      data:{
        labels:MONTHS.slice(1),
        datasets:[
          {label:'Gross '+CY,data:cyGross,backgroundColor:'rgba(42,171,179,0.8)',borderRadius:4,order:2},
          {label:'Net '+CY,data:cyNet,backgroundColor:'rgba(24,114,120,0.7)',borderRadius:4,order:3},
          {label:'Gross '+PY,data:pyGross,type:'line',borderColor:'rgba(250,140,22,0.7)',backgroundColor:'rgba(250,140,22,0.1)',borderWidth:2,pointRadius:3,fill:false,order:1},
          {label:'Net '+PY,data:pyNet,type:'line',borderColor:'rgba(114,46,209,0.5)',borderDash:[5,5],borderWidth:1.5,pointRadius:2,fill:false,order:0}
        ]
      },
      options:{
        responsive:true,maintainAspectRatio:false,
        interaction:{mode:'index',intersect:false},
        plugins:{legend:{position:'bottom',labels:{font:{family:'Poppins',size:11},usePointStyle:true,padding:16}},
          tooltip:{callbacks:{label:function(c){return c.dataset.label+': $'+Number(c.raw).toLocaleString();}}}
        },
        scales:{
          x:{grid:{display:false},ticks:{font:{family:'Poppins',size:11}}},
          y:{grid:{color:'#F3F4F6'},ticks:{font:{family:'Poppins',size:11},callback:function(v){return v>=1000000?'$'+(v/1000000).toFixed(1)+'M':v>=1000?'$'+(v/1000).toFixed(0)+'K':'$'+v;}}}
        }
      }
    });
  }

  /* ── Monthly Hours Breakdown Chart (Stacked) ── */
  var hNormal=new Array(12).fill(0),h15=new Array(12).fill(0),h2x=new Array(12).fill(0),hPH=new Array(12).fill(0);
  for(var i=0;i<hoursData.length;i++){
    var h=hoursData[i];
    var idx=parseInt(h.mn)-1;
    hNormal[idx]=parseFloat(h.normal_hrs)||0;
    h15[idx]=parseFloat(h.ot15_hrs)||0;
    h2x[idx]=parseFloat(h.ot2_hrs)||0;
    hPH[idx]=parseFloat(h.ph_hrs)||0;
  }
  var hrsCtx=document.getElementById('gnHoursChart');
  if(hrsCtx){
    new Chart(hrsCtx,{
      type:'bar',
      data:{
        labels:MONTHS.slice(1),
        datasets:[
          {label:'Normal Hours',data:hNormal,backgroundColor:'rgba(42,171,179,0.75)',borderRadius:2},
          {label:'Time & Half (1.5x)',data:h15,backgroundColor:'rgba(250,140,22,0.75)',borderRadius:2},
          {label:'Double Time (2x)',data:h2x,backgroundColor:'rgba(114,46,209,0.75)',borderRadius:2},
          {label:'Public Holiday',data:hPH,backgroundColor:'rgba(250,77,79,0.7)',borderRadius:2}
        ]
      },
      options:{
        responsive:true,maintainAspectRatio:false,
        plugins:{legend:{position:'bottom',labels:{font:{family:'Poppins',size:11},usePointStyle:true,padding:16}},
          tooltip:{callbacks:{label:function(c){return c.dataset.label+': '+Number(c.raw).toLocaleString()+' hrs';}}}
        },
        scales:{
          x:{stacked:true,grid:{display:false},ticks:{font:{family:'Poppins',size:11}}},
          y:{stacked:true,grid:{color:'#F3F4F6'},ticks:{font:{family:'Poppins',size:11},callback:function(v){return v>=1000?(v/1000).toFixed(0)+'K':v;}}}
        }
      }
    });
  }

  /* ── Department Doughnut ── */
  var deptLabels=[],deptValues=[],deptColors=['#2AABB3','#1890FF','#722ED1','#FA8C16','#52C41A','#FF4D4F','#13C2C2','#FAAD14','#EB2F96','#1E8F96'];
  for(var i=0;i<depts.length;i++){
    deptLabels.push(depts[i].dept||'Unknown');
    deptValues.push(parseFloat(depts[i].gross)||0);
  }
  var deptCtx=document.getElementById('gnDeptChart');
  if(deptCtx && deptLabels.length){
    new Chart(deptCtx,{
      type:'doughnut',
      data:{labels:deptLabels,datasets:[{data:deptValues,backgroundColor:deptColors.slice(0,deptLabels.length),borderWidth:2,borderColor:'#fff'}]},
      options:{
        responsive:true,maintainAspectRatio:false,cutout:'55%',
        plugins:{
          legend:{position:'bottom',labels:{font:{family:'Poppins',size:11},usePointStyle:true,padding:12}},
          tooltip:{callbacks:{label:function(c){var total=c.dataset.data.reduce(function(a,b){return a+b;},0);var pct=(c.raw/total*100).toFixed(1);return c.label+': $'+Number(c.raw).toLocaleString()+' ('+pct+'%)';}}}
        }
      }
    });
  }

  /* ── Dashboard Toggle (localStorage) ── */
  window.gnToggleDash = function(){
    var d=document.getElementById('gnDashboard');
    var b=document.getElementById('gnToggleBtn');
    if(d.classList.contains('collapsed')){
      d.classList.remove('collapsed');
      d.style.maxHeight=d.scrollHeight+'px';
      b.classList.remove('collapsed');
      localStorage.setItem('gn_dash_state','open');
    } else {
      d.classList.add('collapsed');
      b.classList.add('collapsed');
      localStorage.setItem('gn_dash_state','closed');
    }
  };
  var saved = localStorage.getItem('gn_dash_state');
  if(saved==='closed'){
    document.getElementById('gnDashboard').classList.add('collapsed');
    document.getElementById('gnToggleBtn').classList.add('collapsed');
  } else {
    var d=document.getElementById('gnDashboard');
    d.style.maxHeight=d.scrollHeight+'px';
  }

  /* ── Hide loading modal ── */
  if(typeof window._gnHideLoader==='function') window._gnHideLoader();

})();
</script>

<script src="includes/vendors/owl.carousel/dist/owl.carousel.js" type="text/javascript"></script>
</body>
</html>

<?php
include('includes/MainMenuLinksArray.php');

if (isset($SupplierLogin) AND $SupplierLogin==1){
    echo '<table class="table_index">
            <tr><td class="menu_group_item"><p>&bull; <a href="' . $RootPath . '/SupplierTenders.php?TenderType=1">' . _('View or Amend outstanding offers') . '</a></p></td></tr>
            <tr><td class="menu_group_item"><p>&bull; <a href="' . $RootPath . '/SupplierTenders.php?TenderType=2">' . _('Create a new offer') . '</a></p></td></tr>
            <tr><td class="menu_group_item"><p>&bull; <a href="' . $RootPath . '/SupplierTenders.php?TenderType=3">' . _('View any open tenders without an offer') . '</a></p></td></tr>
          </table>';
    include('includes/footer.inc');
    exit;
} elseif (isset($CustomerLogin) AND $CustomerLogin==1){
    echo '<table class="table_index">
            <tr><td class="menu_group_item"><p>&bull; <a href="' . $RootPath . '/CustomerInquiry.php?CustomerID=' . $_SESSION['CustomerID'] . '">' . _('Account Status') . '</a></p></td></tr>
            <tr><td class="menu_group_item"><p>&bull; <a href="' . $RootPath . '/SelectOrderItems.php?NewOrder=Yes">' . _('Place An Order') . '</a></p></td></tr>
            <tr><td class="menu_group_item"><p>&bull; <a href="' . $RootPath . '/SelectCompletedOrder.php?SelectedCustomer=' . $_SESSION['CustomerID'] . '">' . _('Order Status') . '</a></p></td></tr>
          </table>';
    include('includes/footer.inc');
    exit;
}

if (isset($_GET['Application'])){
    $_SESSION['Module'] = $_GET['Application'];
}

function GetRptLinks($GroupID) {
    global $db, $RootPath, $ReportList;
    require_once('reportwriter/languages/en_US/reports.php');
    require_once('reportwriter/admin/defaults.php');
    $GroupID=$ReportList[$GroupID];
    $Title= array(_('Custom Reports'), _('Standard Reports and Forms'));
    $sql= "SELECT id, reporttype, defaultreport, groupname, reportname FROM reports ORDER BY groupname, reportname";
    $Result=DB_query($sql,'','',false,true);
    $ReportList = '';
    while ($Temp = DB_fetch_array($Result)) $ReportList[] = $Temp;
    $RptLinks = '';
    for ($Def=1; $Def>=0; $Def--) {
        $RptLinks .= '<li class="menu_group_headers"><b>' .  $Title[$Def] . '</b></li>';
        $NoEntries = true;
        if ($ReportList) {
            foreach ($ReportList as $Report) {
                if ($Report['groupname']==$GroupID AND $Report['defaultreport']==$Def) {
                    $RptLinks .= '<li class="menu_group_item"><p>&bull; <a href="' . $RootPath . '/reportwriter/ReportMaker.php?action=go&amp;reportid=' . $Report['id'] . '">' . _($Report['reportname']) . '</a></p></li>';
                    $NoEntries = false;
                }
            }
            $NoForms = true;
            foreach ($ReportList as $Report) {
                $Group=explode(':',$Report['groupname']);
                if ($NoForms AND $Group[0]==$GroupID AND $Report['reporttype']=='frm' AND $Report['defaultreport']==$Def) {
                    $RptLinks .= '<li class="menu_group_item"><img src="' . $RootPath . '/css/' . $_SESSION['Theme'] . '/images/folders.gif" width="16" height="13" alt="" />&nbsp;<p>&bull; <a href="' . $RootPath . '/reportwriter/FormMaker.php?id=' . $Report['groupname'] . '"></p>' . $FormGroups[$Report['groupname']] . '</a></li>';
                    $NoForms = false;
                    $NoEntries = false;
                }
            }
        }
        if ($NoEntries) $RptLinks .= '<li class="menu_group_item">' . _('There are no reports to show!') . '</li>';
    }
    return $RptLinks;
}
?>

<script type="text/javascript">
jQuery(document).on("ready xcrudafterrequest",function(){});
</script>