<?php
error_reporting(E_ALL & ~E_NOTICE);
$PageSecurity = 0;
include('includes/session.inc');
$Title = _('Guard Force Rostering');
include('includes/newheader.php');
$userid = isset($_SESSION['UserID']) ? $_SESSION['UserID'] : '';
$isAdmin = in_array($userid, array('admin','mosheed','sharukh','ravneet','sachin','ravinesh','pchand','rajnal'));
?>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box}
.R{font-family:'Poppins',sans-serif;color:#1F2937;padding:0 15px;max-width:100%}
.R a{text-decoration:none;color:#2AABB3}

/* Banner */
.R-ban{background:linear-gradient(135deg,#187278,#2AABB3 50%,#34C8D1);border-radius:12px;padding:20px 24px;color:#fff;margin-bottom:14px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;box-shadow:0 4px 15px rgba(42,171,179,.3)}
.R-ban h2{font-size:20px;font-weight:600;margin:0}.R-ban .sub{font-size:12px;opacity:.85}.R-ban .bc{font-size:11px;opacity:.7;margin-bottom:2px}
.R-ban .bc a{color:#fff}
.R-psel{padding:7px 12px;border-radius:8px;border:1px solid rgba(255,255,255,.3);background:rgba(255,255,255,.15);color:#fff;font-family:inherit;font-size:12px;cursor:pointer;backdrop-filter:blur(8px)}
.R-psel option{color:#1F2937;background:#fff}
.R-pbadge{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:6px;font-size:11px;font-weight:500;background:rgba(255,255,255,.2)}
.R-dot{width:8px;height:8px;border-radius:50%;display:inline-block}

/* KPIs */
.R-kpis{display:grid;grid-template-columns:repeat(5,1fr);gap:12px;margin-bottom:14px}
.R-kpi{background:#fff;border-radius:10px;padding:14px 16px;box-shadow:0 1px 3px rgba(0,0,0,.08);border:1px solid #E5E7EB;display:flex;align-items:center;gap:12px;transition:.2s}
.R-kpi:hover{box-shadow:0 4px 12px rgba(0,0,0,.1);transform:translateY(-1px)}
.R-ki{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:18px}
.R-kl{font-size:10px;color:#6B7280;font-weight:600;text-transform:uppercase;letter-spacing:.5px}
.R-kv{font-size:22px;font-weight:700;line-height:1.1}
.R-ks{font-size:10px;color:#9CA3AF}

/* Tabs */
.R-tabs{display:flex;gap:2px;border-bottom:1px solid #E5E7EB;margin-bottom:14px}
.R-tab{padding:8px 16px;font-size:12px;font-weight:500;color:#6B7280;border:none;background:none;cursor:pointer;position:relative;font-family:inherit;transition:.2s}
.R-tab:hover{color:#1F2937}.R-tab.on{color:#1E8F96}
.R-tab.on::after{content:'';position:absolute;bottom:-1px;left:0;right:0;height:2px;background:#2AABB3;border-radius:1px 1px 0 0}

/* Filters */
.R-fl{display:flex;align-items:center;gap:8px;margin-bottom:12px;flex-wrap:wrap}
.R-fs{padding:6px 10px;border:1px solid #E5E7EB;border-radius:6px;font-size:11px;font-family:inherit;background:#fff;min-width:130px}
.R-fs:focus{outline:none;border-color:#2AABB3;box-shadow:0 0 0 2px rgba(42,171,179,.15)}
.R-fla{font-size:10px;font-weight:600;color:#6B7280;text-transform:uppercase;letter-spacing:.5px}

/* Buttons */
.R-btn{padding:6px 12px;border-radius:6px;font-size:11px;font-weight:500;border:1px solid #E5E7EB;background:#fff;cursor:pointer;display:inline-flex;align-items:center;gap:4px;font-family:inherit;transition:.15s;color:#1F2937}
.R-btn:hover{background:#F9FAFB;border-color:#D1D5DB}
.R-bp{background:#2AABB3;color:#fff;border-color:#2AABB3}.R-bp:hover{background:#1E8F96}
.R-bd{background:#FEF2F2;color:#DC2626;border-color:#FECACA}.R-bd:hover{background:#FEE2E2}
.R-bs{padding:3px 8px;font-size:10px}

/* Badge */
.R-bg{font-size:10px;padding:2px 7px;border-radius:4px;font-weight:500;white-space:nowrap;display:inline-block}
.bg-ok{background:#F0FDF4;color:#15803D}.bg-warn{background:#FFFBEB;color:#B45309}.bg-err{background:#FEF2F2;color:#DC2626}.bg-info{background:#E6F7F8;color:#1E8F96}

/* Location Cards */
.R-loc{background:#fff;border-radius:10px;box-shadow:0 1px 3px rgba(0,0,0,.08);border:1px solid #E5E7EB;margin-bottom:8px;overflow:hidden;transition:.2s}
.R-loc:hover{box-shadow:0 3px 10px rgba(0,0,0,.1)}
.R-lh{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;cursor:pointer;user-select:none;transition:.2s;border-bottom:1px solid transparent}
.R-lh.open{border-bottom-color:#E5E7EB;background:#FAFBFC}
.R-li{display:flex;align-items:center;gap:10px;flex:1;min-width:0}
.R-lic{width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:14px}
.R-ln{font-size:12px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.R-ls{font-size:10px;color:#6B7280}
.R-lm{display:flex;gap:6px;align-items:center;flex-shrink:0;flex-wrap:wrap}
.R-chv{transition:transform .2s;font-size:10px;color:#9CA3AF}.R-chv.open{transform:rotate(180deg)}

/* Pool Bar */
.R-pool{padding:6px 12px;background:#F0F9FF;border-bottom:1px solid #E0F2FE;font-size:10px;display:flex;flex-wrap:wrap;gap:4px;align-items:center}
.R-pc{display:inline-flex;align-items:center;gap:3px;padding:2px 7px;background:#fff;border-radius:12px;font-size:10px;border:1px solid #E0F2FE}
.R-pc.busy{opacity:.4;text-decoration:line-through}

/* Schedule Grid */
.R-grid{overflow-x:auto;padding:4px 0}
.R-grid table{width:100%;border-collapse:collapse;font-size:11px;min-width:1000px}
.R-grid th{background:#F8FAFB;padding:6px;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:.3px;color:#6B7280;border-bottom:1px solid #E5E7EB;text-align:center;position:sticky;top:0;z-index:2}
.R-grid th:first-child{text-align:left;min-width:180px}
.R-grid td{padding:3px 4px;border-bottom:1px solid #F3F4F6;text-align:center;vertical-align:middle}
.R-grid tr:hover td{background:#FAFBFC}
.R-grid .th-dt{font-weight:400;font-size:9px;display:block;color:#9CA3AF}

/* Guard name */
.R-gn{display:flex;align-items:center;gap:7px;text-align:left;padding:4px 8px !important}
.R-ga{width:26px;height:26px;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:9px;font-weight:700;color:#fff;flex-shrink:0}
.R-gname{font-weight:500;font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:110px}
.R-gid{font-size:9px;color:#9CA3AF}
.R-ptag{font-size:7px;background:#E0F2FE;color:#0369A1;padding:1px 4px;border-radius:3px;font-weight:700;margin-left:2px}

/* Shift Cell */
.R-sc{min-width:70px;cursor:pointer;position:relative}
.R-sc:hover{background:#F0F9FF !important}
.R-sh{padding:3px 6px;border-radius:4px;font-size:10px;font-weight:500;display:inline-flex;flex-direction:column;align-items:center;line-height:1.2;min-width:58px;position:relative}
.R-sh .hrs{font-weight:700;font-size:11px}
.R-sh .tm{font-size:8px;opacity:.75}
.R-sh-off{background:#F1F5F9;color:#64748B;font-size:9px}
.R-sh-abs{background:#FEF3C7;color:#92400E;font-size:9px;padding:4px 6px;border-radius:4px}
.R-empty{color:#D1D5DB;font-size:16px;cursor:pointer}.R-empty:hover{color:#2AABB3}
.R-clash{position:absolute;top:-3px;right:-3px;width:12px;height:12px;border-radius:6px;background:#EF4444;color:#fff;font-size:7px;display:flex;align-items:center;justify-content:center;font-weight:700;border:1px solid #fff}

/* Totals */
.R-tot{font-weight:700;font-size:12px}
.R-tot.over{color:#DC2626}.R-tot.ok{color:#15803D}.R-tot.low{color:#6B7280}

/* Actions col */
.R-act{white-space:nowrap}

/* Modal */
.R-modal{display:none;position:fixed;inset:0;z-index:9999;align-items:center;justify-content:center;background:rgba(0,0,0,.4);backdrop-filter:blur(2px)}
.R-modal.show{display:flex}
.R-mc{background:#fff;border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,.2);max-width:560px;width:95%;max-height:85vh;overflow-y:auto;animation:Rslide .2s}
@keyframes Rslide{from{transform:translateY(20px);opacity:0}to{transform:translateY(0);opacity:1}}
.R-mh{padding:14px 18px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;justify-content:space-between}
.R-mh h3{font-size:15px;font-weight:600;margin:0}
.R-mx{width:28px;height:28px;border-radius:6px;border:none;background:#F3F4F6;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;color:#6B7280}
.R-mx:hover{background:#E5E7EB}
.R-mb{padding:16px 18px}
.R-mf{padding:12px 18px;border-top:1px solid #E5E7EB;display:flex;justify-content:flex-end;gap:8px}

/* Form */
.R-fg{margin-bottom:12px}
.R-fg label{display:block;font-size:11px;font-weight:600;color:#374151;margin-bottom:4px}
.R-fi{width:100%;padding:8px 10px;border:1px solid #E5E7EB;border-radius:6px;font-size:12px;font-family:inherit}
.R-fi:focus{outline:none;border-color:#2AABB3;box-shadow:0 0 0 2px rgba(42,171,179,.15)}

/* Preset Shifts */
.R-presets{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:12px}
.R-preset{padding:10px 8px;border:2px solid #E5E7EB;border-radius:8px;text-align:center;cursor:pointer;transition:.15s;font-size:11px;font-weight:500}
.R-preset:hover{border-color:#2AABB3;background:#F0FDFA}
.R-preset.sel{border-color:#2AABB3;background:#E6F7F8}
.R-preset .pt{font-weight:700;font-size:12px}.R-preset .pp{font-size:9px;color:#6B7280;margin-top:2px}

/* Employee Search Results */
.R-elist{max-height:250px;overflow-y:auto;border:1px solid #E5E7EB;border-radius:8px}
.R-ei{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;border-bottom:1px solid #F5F5F5;cursor:pointer;transition:.1s}
.R-ei:hover{background:#F0FDFA}
.R-ei.disabled{opacity:.4;cursor:not-allowed}
.R-ei .name{font-weight:500;font-size:12px}.R-ei .meta{font-size:10px;color:#6B7280}

/* Report table */
.R-rtbl{width:100%;border-collapse:collapse;font-size:11px}
.R-rtbl th{background:#F8FAFB;padding:8px;text-align:left;font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:.3px;color:#6B7280;border-bottom:2px solid #E5E7EB}
.R-rtbl td{padding:6px 8px;border-bottom:1px solid #F5F5F5}
.R-rtbl tr:hover td{background:#FAFBFC}
.R-hbar{height:5px;border-radius:3px;background:#E5E7EB;width:60px;display:inline-block;overflow:hidden;vertical-align:middle;margin-left:4px}
.R-hfill{height:100%;border-radius:3px}

/* Toast */
.R-toast{position:fixed;top:20px;right:20px;z-index:10000;padding:12px 18px;border-radius:8px;font-size:12px;font-weight:500;color:#fff;display:none;animation:Rslide .3s;font-family:'Poppins',sans-serif;box-shadow:0 4px 15px rgba(0,0,0,.2)}
.R-toast.ok{background:#10B981}.R-toast.err{background:#EF4444}.R-toast.warn{background:#F59E0B;color:#1F2937}

/* Loading */
.R-loading{text-align:center;padding:40px;color:#9CA3AF;font-size:13px}
.R-spin{display:inline-block;width:24px;height:24px;border:2px solid #E5E7EB;border-top:2px solid #2AABB3;border-radius:50%;animation:rspin .7s linear infinite;vertical-align:middle;margin-right:8px}
@keyframes rspin{to{transform:rotate(360deg)}}

/* Responsive */
@media(max-width:1100px){.R-kpis{grid-template-columns:repeat(3,1fr)}}
@media(max-width:768px){.R-kpis{grid-template-columns:repeat(2,1fr)}}
</style>

<div class="R" id="app">

<!-- Banner -->
<div class="R-ban">
    <div>
        <div class="bc"><a href="index.php">Home</a> / HRMS / Rostering</div>
        <h2>🛡️ Guard Force Rostering</h2>
        <div class="sub">Schedule & manage guard assignments across all locations</div>
    </div>
    <div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
        <select class="R-psel" id="selPeriod"></select>
        <span class="R-pbadge" id="periodBadge"></span>
        <?php if ($isAdmin): ?>
        <button class="R-btn R-bs" onclick="showDuplicateModal()" title="Duplicate roster from another period">📋 Duplicate</button>
        <?php endif; ?>
    </div>
</div>

<!-- KPIs -->
<div class="R-kpis" id="kpiBox"></div>

<!-- Tabs -->
<div class="R-tabs">
    <button class="R-tab on" onclick="switchTab('sched',this)">📋 Schedule Board</button>
    <button class="R-tab" onclick="switchTab('rptEmp',this)">👤 Employee Report</button>
    <button class="R-tab" onclick="switchTab('rptLoc',this)">📍 Location Report</button>
</div>

<!-- Schedule Tab -->
<div id="tab-sched">
    <div class="R-fl">
        <span class="R-fla">Dept:</span>
        <select class="R-fs" id="fDept" onchange="loadLocations()"><option value="">All Departments</option></select>
        <span class="R-fla">Sector:</span>
        <select class="R-fs" id="fSector" onchange="loadLocations()"><option value="">All Sectors</option></select>
        <input type="text" class="R-fs" id="fSearch" placeholder="Search locations..." style="min-width:180px" oninput="debounceSearch()">
        <div style="flex:1"></div>
        <button class="R-btn" onclick="expandAll()">Expand All</button>
        <button class="R-btn" onclick="collapseAll()">Collapse All</button>
    </div>
    <div id="locList"><div class="R-loading"><span class="R-spin"></span> Loading locations...</div></div>
</div>

<!-- Employee Report Tab -->
<div id="tab-rptEmp" style="display:none">
    <div id="empReportBox"><div class="R-loading"><span class="R-spin"></span> Loading report...</div></div>
</div>

<!-- Location Report Tab -->
<div id="tab-rptLoc" style="display:none">
    <div id="locReportBox"><div class="R-loading"><span class="R-spin"></span> Loading report...</div></div>
</div>

</div><!-- /app -->

<!-- ═══ SHIFT EDITOR MODAL ═══ -->
<div class="R-modal" id="shiftModal">
<div class="R-mc" style="max-width:440px">
    <div class="R-mh"><h3 id="smTitle">Edit Shift</h3><button class="R-mx" onclick="closeModal('shiftModal')">✕</button></div>
    <div class="R-mb">
        <div class="R-presets" id="smPresets"></div>
        <div class="R-fg"><label>Time In</label><input type="datetime-local" class="R-fi" id="smTimeIn"></div>
        <div class="R-fg"><label>Time Out</label><input type="datetime-local" class="R-fi" id="smTimeOut"></div>
        <div class="R-fg"><label>Absence Type</label>
            <select class="R-fi" id="smAbsent"><option value="">Working</option><option>Dayoff</option><option>AWOL</option><option>Public Holiday</option><option>Paid Public Holiday</option><option>SickLeave</option><option>BereavementLeave</option><option>AnnualLeave</option><option>MaternityLeave</option></select>
        </div>
        <div id="smClashWarn" style="display:none;padding:8px 12px;background:#FEF2F2;border:1px solid #FECACA;border-radius:6px;font-size:11px;color:#DC2626;margin-top:8px">⚠️ <span id="smClashText"></span></div>
    </div>
    <div class="R-mf">
        <button class="R-btn R-bd" onclick="clearShift()">Clear Shift</button>
        <button class="R-btn" onclick="closeModal('shiftModal')">Cancel</button>
        <button class="R-btn R-bp" onclick="saveShift()">Save Shift</button>
    </div>
</div>
</div>

<!-- ═══ ADD GUARD MODAL ═══ -->
<div class="R-modal" id="guardModal">
<div class="R-mc" style="max-width:500px">
    <div class="R-mh"><h3 id="gmTitle">Add Guard</h3><button class="R-mx" onclick="closeModal('guardModal')">✕</button></div>
    <div class="R-mb">
        <div class="R-fg"><label>Search Employee</label><input type="text" class="R-fi" id="gmSearch" placeholder="Type name or ID..." oninput="searchEmployees()"></div>
        <div id="gmPoolSection" style="margin-bottom:10px"></div>
        <div class="R-elist" id="gmResults"><div style="padding:20px;text-align:center;color:#9CA3AF;font-size:12px">Type to search employees</div></div>
    </div>
</div>
</div>

<!-- ═══ DUPLICATE MODAL ═══ -->
<div class="R-modal" id="dupModal">
<div class="R-mc" style="max-width:400px">
    <div class="R-mh"><h3>Duplicate Roster</h3><button class="R-mx" onclick="closeModal('dupModal')">✕</button></div>
    <div class="R-mb">
        <div class="R-fg"><label>Copy FROM Period</label><select class="R-fi" id="dupFrom"></select></div>
        <div class="R-fg"><label>Copy TO Period (current)</label><select class="R-fi" id="dupTo"></select></div>
        <p style="font-size:11px;color:#6B7280;margin-top:8px">This will copy all location rosters and guard assignments (without shift times) from the source period to the target.</p>
    </div>
    <div class="R-mf">
        <button class="R-btn" onclick="closeModal('dupModal')">Cancel</button>
        <button class="R-btn R-bp" onclick="doDuplicate()">Duplicate</button>
    </div>
</div>
</div>

<!-- Toast -->
<div class="R-toast" id="toast"></div>

<script>
// ═══ STATE ═══
var API = 'RosteringAPI.php';
var STATE = {
    periodId: 0,
    periods: [],
    locations: [],
    rosterData: {},  // clientid => [assignments]
    filters: {departments:[], sectors:[]},
    currentShift: null, // {rstimeid, day, rosterid, employeeid, clientid}
    currentAddGuard: null, // {clientid, rosterid}
    searchTimer: null,
    periodDates: [] // dates for current period
};

// ═══ INIT ═══
document.addEventListener('DOMContentLoaded', function() {
    api('get_periods', {}, function(d) {
        STATE.periods = d.data;
        var sel = document.getElementById('selPeriod');
        d.data.forEach(function(p) {
            var o = document.createElement('option');
            o.value = p.id;
            o.textContent = p.period + ' (' + p.start_date + ' → ' + p.end_date + ')';
            sel.appendChild(o);
        });
        if (d.data.length > 0) {
            STATE.periodId = parseInt(d.data[0].id);
            updatePeriodBadge(d.data[0]);
            computePeriodDates(d.data[0]);
        }
        loadFilters();
        loadAll();
    });
});

function computePeriodDates(p) {
    STATE.periodDates = [];
    if (!p || !p.start_date) return;
    var d = new Date(p.start_date + 'T00:00:00');
    for (var i = 0; i < 8; i++) {
        var dd = new Date(d);
        dd.setDate(dd.getDate() + i);
        STATE.periodDates.push(dd);
    }
}

function updatePeriodBadge(p) {
    var b = document.getElementById('periodBadge');
    var dotColor = p.status === 'approved' ? '#52C41A' : (p.status === 'locked' ? '#FAAD14' : '#1890FF');
    b.innerHTML = '<span class="R-dot" style="background:'+dotColor+'"></span> ' + (p.status||'pending').charAt(0).toUpperCase() + (p.status||'pending').slice(1);
}

document.getElementById('selPeriod').onchange = function() {
    STATE.periodId = parseInt(this.value);
    var p = STATE.periods.find(function(x){ return x.id == STATE.periodId; });
    if (p) { updatePeriodBadge(p); computePeriodDates(p); }
    loadAll();
};

function loadAll() {
    loadKPIs();
    loadLocations();
}

// ═══ API HELPER ═══
function api(action, params, cb, method) {
    method = method || 'GET';
    var url = API + '?action=' + action;
    var body = null;
    if (method === 'GET') {
        Object.keys(params).forEach(function(k) { url += '&' + k + '=' + encodeURIComponent(params[k]); });
    } else {
        body = new FormData();
        body.append('action', action);
        Object.keys(params).forEach(function(k) { body.append(k, params[k]); });
    }
    var xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function() {
        try { var d = JSON.parse(xhr.responseText); cb(d); }
        catch(e) { console.error('API Error:', e, xhr.responseText); cb({error:'Parse error'}); }
    };
    xhr.onerror = function() { cb({error:'Network error'}); };
    xhr.send(body);
}

// ═══ TOAST ═══
function toast(msg, type) {
    var t = document.getElementById('toast');
    t.textContent = msg;
    t.className = 'R-toast ' + (type||'ok');
    t.style.display = 'block';
    setTimeout(function(){ t.style.display = 'none'; }, 3000);
}

// ═══ MODAL ═══
function openModal(id) { document.getElementById(id).classList.add('show'); }
function closeModal(id) { document.getElementById(id).classList.remove('show'); }

// ═══ TAB SWITCHING ═══
function switchTab(id, btn) {
    document.querySelectorAll('.R-tab').forEach(function(t){ t.classList.remove('on'); });
    btn.classList.add('on');
    ['sched','rptEmp','rptLoc'].forEach(function(t){ document.getElementById('tab-'+t).style.display = t===id?'block':'none'; });
    if (id === 'rptEmp') loadEmpReport();
    if (id === 'rptLoc') loadLocReport();
}

// ═══ LOAD FILTERS ═══
function loadFilters() {
    api('get_filters', {}, function(d) {
        if (!d.ok) return;
        STATE.filters = d;
        var ds = document.getElementById('fDept');
        d.departments.forEach(function(x) { var o=document.createElement('option');o.value=x.departmentid;o.textContent=x.departmentname;ds.appendChild(o); });
        var ss = document.getElementById('fSector');
        d.sectors.forEach(function(x) { var o=document.createElement('option');o.value=x.id;o.textContent=x.name;ss.appendChild(o); });
    });
}

// ═══ LOAD KPIs ═══
function loadKPIs() {
    api('get_kpis', {period_id:STATE.periodId}, function(d) {
        if (!d.ok) return;
        var k = d.data;
        var cov = k.required > 0 ? Math.round((k.assigned/k.required)*100) : 0;
        document.getElementById('kpiBox').innerHTML =
            kpiCard('📍',k.locations,'Locations',k.required+' guards req','#E0F2FE','#0369A1') +
            kpiCard('✅',k.assigned,'Assigned',cov+'% coverage','#DCFCE7','#15803D') +
            kpiCard('⚠️',k.unfilled,'Unfilled','positions vacant','#FEF3C7','#B45309') +
            kpiCard('⏱️',numberFmt(k.total_hrs),'Hours','this period','#F3E8FF','#7C3AED') +
            kpiCard('🔴',k.overtime,'Overtime','guards >48hrs','#FEE2E2','#DC2626');
    });
}
function kpiCard(icon,val,label,sub,bg,color) {
    return '<div class="R-kpi"><div class="R-ki" style="background:'+bg+';color:'+color+'">'+icon+'</div><div><div class="R-kl">'+label+'</div><div class="R-kv" style="color:'+color+'">'+val+'</div><div class="R-ks">'+sub+'</div></div></div>';
}
function numberFmt(n) { return n >= 1000 ? (n/1000).toFixed(1)+'k' : n; }

// ═══ LOAD LOCATIONS ═══
function loadLocations() {
    var p = {period_id:STATE.periodId, dept:document.getElementById('fDept').value, sector:document.getElementById('fSector').value, search:document.getElementById('fSearch').value};
    document.getElementById('locList').innerHTML = '<div class="R-loading"><span class="R-spin"></span> Loading...</div>';
    api('get_locations', p, function(d) {
        if (!d.ok) { document.getElementById('locList').innerHTML = '<div class="R-loading">Error loading locations</div>'; return; }
        STATE.locations = d.data;
        // Now load all roster data in bulk
        api('get_roster_data', {period_id:STATE.periodId}, function(rd) {
            STATE.rosterData = rd.ok ? rd.data : {};
            renderLocations();
        });
    });
}
function debounceSearch() { clearTimeout(STATE.searchTimer); STATE.searchTimer = setTimeout(loadLocations, 300); }

var LOC_COLORS = ['#3B82F6','#10B981','#F59E0B','#EF4444','#8B5CF6','#EC4899','#06B6D4','#F97316'];
var DAYS = ['mon','tue','wed','thu','fri','sat','sun','mon2'];
var DAY_LABELS = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun','Mon2'];
var DAY_IN  = ['montime_in','tuestime_in','wedtime_in','thurstime_in','fritime_in','sattime_in','sunttime_in','mon2ttime_in'];
var DAY_OUT = ['montime_out','tuestime_out','wedtime_out','thurstime_out','fritime_out','sattime_out','sunttime_out','mon2time_out'];
var DAY_TOT = ['mon_total','tues_total','wed_total','thurs_total','fri_total','sat_total','sun_total','mon2_total'];
var DAY_ABS = ['mon_absent','tues_absent','wed_absent','thurs_absent','fri_absent','sat_absent','sun_absent',null];

function renderLocations() {
    var html = '';
    STATE.locations.forEach(function(loc, li) {
        var cid = loc.clientid;
        var guards = STATE.rosterData[cid] || [];
        var assigned = guards.length;
        var req = parseInt(loc.req_guards) || 0;
        var pct = req > 0 ? Math.round((assigned/req)*100) : 0;
        var bgCls = pct >= 100 ? 'bg-ok' : (assigned > 0 ? 'bg-warn' : 'bg-err');
        var bgTxt = pct >= 100 ? 'FULL' : (assigned > 0 ? assigned+'/'+req : 'EMPTY');
        var col = LOC_COLORS[cid % LOC_COLORS.length];
        var hasRoster = loc.rosterid ? true : false;
        var rstatus = loc.roster_status || 'none';

        html += '<div class="R-loc" id="loc-'+cid+'">';
        html += '<div class="R-lh" onclick="toggleLoc('+cid+')">';
        html += '<div class="R-li"><div class="R-lic" style="background:'+col+'15;color:'+col+'">📍</div>';
        html += '<div style="min-width:0"><div class="R-ln">'+esc(loc.patrollocation)+'</div>';
        html += '<div class="R-ls">'+esc(loc.customername||'')+' · '+esc(loc.sector_name||'')+' · '+esc(loc.departmentname||'')+'</div></div></div>';
        html += '<div class="R-lm">';
        html += '<span class="R-bg '+bgCls+'">'+bgTxt+' guards</span>';
        html += '<span class="R-bg bg-info">'+(loc.weekly_hours_required||0)+'h/wk</span>';
        if (loc.base_wage) html += '<span class="R-bg" style="background:#F8F8F8;color:#666">$'+parseFloat(loc.base_wage).toFixed(2)+'/hr</span>';
        if (hasRoster) html += '<span class="R-bg" style="background:#F0F0F0;color:#666">'+rstatus+'</span>';
        html += '<span class="R-chv" id="chv-'+cid+'">▼</span>';
        html += '</div></div>';

        // Body
        html += '<div id="body-'+cid+'" style="display:none">';

        // Action bar
        html += '<div style="padding:8px 12px;display:flex;gap:6px;align-items:center;border-bottom:1px solid #F3F4F6;background:#FAFBFC">';
        if (!hasRoster) {
            html += '<button class="R-btn R-bp R-bs" onclick="createRoster('+cid+')">+ Create Roster</button>';
            html += '<span style="font-size:11px;color:#9CA3AF">No roster created for this period yet</span>';
        } else {
            html += '<button class="R-btn R-bp R-bs" onclick="openAddGuard('+cid+','+loc.rosterid+')">+ Add Guard</button>';
            html += '<button class="R-btn R-bs" onclick="changeStatus('+loc.rosterid+',\'approved\')">✅ Approve</button>';
            html += '<button class="R-btn R-bs" onclick="changeStatus('+loc.rosterid+',\'locked\')">🔒 Lock</button>';
            html += '<a href="PDFPrintRoster-GFS.php?rosterid='+loc.rosterid+'" class="R-btn R-bs" target="_blank">📄 PDF</a>';
            html += '<a href="PrintRosterExcel-GFS.php?rosterid='+loc.rosterid+'" class="R-btn R-bs" target="_blank">📊 Excel</a>';
        }
        html += '</div>';

        // Schedule grid
        if (hasRoster && guards.length > 0) {
            html += '<div class="R-grid"><table><thead><tr><th>Guard</th>';
            for (var di=0; di<8; di++) {
                var dtStr = STATE.periodDates[di] ? (STATE.periodDates[di].getDate()+'/'+(STATE.periodDates[di].getMonth()+1)) : '';
                html += '<th>'+DAY_LABELS[di]+'<span class="th-dt">'+dtStr+'</span></th>';
            }
            html += '<th>Total</th><th style="min-width:60px">Actions</th></tr></thead><tbody>';

            guards.forEach(function(g) {
                var tot = parseFloat(g.total_hrs) || 0;
                var totCls = tot > 48 ? 'over' : (tot >= 40 ? 'ok' : 'low');
                html += '<tr>';
                // Name
                html += '<td class="R-gn"><div class="R-ga" style="background:'+col+'">'+(g.first_name||'?')[0]+(g.last_name||'?')[0]+'</div>';
                html += '<div><div class="R-gname">'+esc(g.first_name+' '+g.last_name)+'</div>';
                html += '<div class="R-gid">#'+g.employeeid+' · '+(g.contract||8)+'hr</div></div></td>';

                // Day cells
                for (var di=0; di<8; di++) {
                    var hrs = parseFloat(g[DAY_TOT[di]]) || 0;
                    var tIn = g[DAY_IN[di]] || '';
                    var tOut = g[DAY_OUT[di]] || '';
                    var absent = DAY_ABS[di] ? (g[DAY_ABS[di]] || '') : '';
                    html += '<td class="R-sc" onclick="openShiftEditor('+g.rstimeid+',\''+DAYS[di]+'\','+g.rosterid+','+g.employeeid+','+cid+')">';
                    if (absent && absent !== 'None' && absent !== '') {
                        html += '<div class="R-sh-abs">'+esc(absent)+'</div>';
                    } else if (hrs > 0) {
                        var sCol = getShiftColor(tIn);
                        var timeStr = formatTime(tIn) + '-' + formatTime(tOut);
                        html += '<div class="R-sh" style="background:'+sCol+'15;color:'+sCol+'"><span class="hrs">'+hrs+'h</span><span class="tm">'+timeStr+'</span></div>';
                    } else {
                        html += '<span class="R-empty">+</span>';
                    }
                    html += '</td>';
                }

                // Total
                html += '<td><span class="R-tot '+totCls+'">'+tot+'h</span>';
                if (tot > 48) html += ' <span style="color:#DC2626;font-size:10px" title="Overtime">⚠️</span>';
                html += '</td>';

                // Actions
                html += '<td class="R-act"><button class="R-btn R-bd R-bs" onclick="removeGuard('+g.rstimeid+',\''+esc(g.first_name)+'\')">✕</button></td>';
                html += '</tr>';
            });

            html += '</tbody></table></div>';
        } else if (hasRoster) {
            html += '<div style="padding:20px;text-align:center;color:#9CA3AF;font-size:12px">No guards assigned. Click "+ Add Guard" to start.</div>';
        }

        html += '</div>'; // body
        html += '</div>'; // loc
    });

    if (STATE.locations.length === 0) html = '<div class="R-loading">No locations found matching your filters.</div>';
    document.getElementById('locList').innerHTML = html;
}

function getShiftColor(tIn) {
    if (!tIn || tIn === '0000-00-00 00:00:00') return '#94A3B8';
    var h = parseInt(tIn.substr(11,2)) || 0;
    if (h >= 15) return '#F59E0B';
    if (h >= 12) return '#10B981';
    if (h >= 7) return '#3B82F6';
    return '#8B5CF6';
}
function formatTime(t) {
    if (!t || t.length < 16 || t === '0000-00-00 00:00:00') return '';
    return t.substr(11,5);
}
function esc(s) { if (!s) return ''; var d=document.createElement('div');d.textContent=s;return d.innerHTML; }

// ═══ TOGGLE LOCATION ═══
function toggleLoc(cid) {
    var body = document.getElementById('body-'+cid);
    var chev = document.getElementById('chv-'+cid);
    var hdr = body ? body.previousElementSibling : null;
    if (!body) return;
    var show = body.style.display === 'none';
    body.style.display = show ? 'block' : 'none';
    if (chev) chev.classList.toggle('open', show);
    if (hdr) hdr.classList.toggle('open', show);
}
function expandAll() { STATE.locations.forEach(function(l){ var b=document.getElementById('body-'+l.clientid);if(b){b.style.display='block';var c=document.getElementById('chv-'+l.clientid);if(c)c.classList.add('open');b.previousElementSibling.classList.add('open');}}); }
function collapseAll() { STATE.locations.forEach(function(l){ var b=document.getElementById('body-'+l.clientid);if(b){b.style.display='none';var c=document.getElementById('chv-'+l.clientid);if(c)c.classList.remove('open');b.previousElementSibling.classList.remove('open');}}); }

// ═══ CREATE ROSTER ═══
function createRoster(clientid) {
    api('create_roster', {clientid:clientid, period_id:STATE.periodId}, function(d) {
        if (d.ok) { toast('Roster created'); loadLocations(); } else toast(d.error||'Failed','err');
    }, 'POST');
}

// ═══ CHANGE STATUS ═══
function changeStatus(rosterid, status) {
    api('update_status', {rosterid:rosterid, status:status}, function(d) {
        if (d.ok) { toast('Status → '+status); loadLocations(); } else toast(d.error||'Failed','err');
    }, 'POST');
}

// ═══ SHIFT EDITOR ═══
function openShiftEditor(rstimeid, day, rosterid, employeeid, clientid) {
    STATE.currentShift = {rstimeid:rstimeid, day:day, rosterid:rosterid, employeeid:employeeid, clientid:clientid};
    document.getElementById('smTitle').textContent = 'Edit Shift — ' + day.charAt(0).toUpperCase()+day.slice(1);
    document.getElementById('smTimeIn').value = '';
    document.getElementById('smTimeOut').value = '';
    document.getElementById('smAbsent').value = '';
    document.getElementById('smClashWarn').style.display = 'none';

    // Find current values
    var guards = STATE.rosterData[clientid] || [];
    var g = guards.find(function(x){ return x.rstimeid == rstimeid; });
    if (g) {
        var di = DAYS.indexOf(day);
        if (di >= 0) {
            var tIn = g[DAY_IN[di]] || '';
            var tOut = g[DAY_OUT[di]] || '';
            var abs = DAY_ABS[di] ? (g[DAY_ABS[di]] || '') : '';
            if (tIn && tIn.length >= 16 && tIn !== '0000-00-00 00:00:00') document.getElementById('smTimeIn').value = tIn.substr(0,16);
            if (tOut && tOut.length >= 16 && tOut !== '0000-00-00 00:00:00') document.getElementById('smTimeOut').value = tOut.substr(0,16);
            if (abs && abs !== 'None') document.getElementById('smAbsent').value = abs;
        }
    }

    // Build presets using period dates
    var di = DAYS.indexOf(day);
    var dateStr = '';
    if (di >= 0 && STATE.periodDates[di]) {
        var pd = STATE.periodDates[di];
        dateStr = pd.getFullYear()+'-'+pad(pd.getMonth()+1)+'-'+pad(pd.getDate());
    }
    var presets = [
        {name:'Day (8h)',in:'07:00',out:'15:00',color:'#3B82F6'},
        {name:'Day (9h)',in:'06:00',out:'15:00',color:'#0EA5E9'},
        {name:'Swing',in:'15:00',out:'23:00',color:'#10B981'},
        {name:'Night',in:'23:00',out:'07:00',color:'#8B5CF6'},
        {name:'Long Day',in:'06:00',out:'18:00',color:'#F59E0B'},
        {name:'Custom',in:'',out:'',color:'#6B7280'}
    ];
    var ph = '';
    presets.forEach(function(p,i) {
        ph += '<div class="R-preset" onclick="applyPreset(\''+dateStr+'\',\''+p.in+'\',\''+p.out+'\')" style="border-left:3px solid '+p.color+'">';
        ph += '<div class="pt">'+p.name+'</div>';
        if (p.in) ph += '<div class="pp">'+p.in+' → '+p.out+'</div>';
        else ph += '<div class="pp">Set manually</div>';
        ph += '</div>';
    });
    document.getElementById('smPresets').innerHTML = ph;

    openModal('shiftModal');
}

function pad(n) { return n < 10 ? '0'+n : ''+n; }

function applyPreset(dateStr, tIn, tOut) {
    if (!dateStr || !tIn) return;
    document.getElementById('smAbsent').value = '';
    document.getElementById('smTimeIn').value = dateStr + 'T' + tIn;
    // For overnight shifts
    if (tOut < tIn) {
        var d = new Date(dateStr+'T00:00:00');
        d.setDate(d.getDate()+1);
        var nextDate = d.getFullYear()+'-'+pad(d.getMonth()+1)+'-'+pad(d.getDate());
        document.getElementById('smTimeOut').value = nextDate + 'T' + tOut;
    } else {
        document.getElementById('smTimeOut').value = dateStr + 'T' + tOut;
    }
    // Highlight selected
    document.querySelectorAll('.R-preset').forEach(function(el){ el.classList.remove('sel'); });
    event.currentTarget.classList.add('sel');
}

function saveShift() {
    var s = STATE.currentShift;
    if (!s) return;
    var absent = document.getElementById('smAbsent').value;
    var tIn = document.getElementById('smTimeIn').value;
    var tOut = document.getElementById('smTimeOut').value;

    if (!absent && (!tIn || !tOut)) { toast('Set times or select absence type','warn'); return; }

    var params = {rstimeid:s.rstimeid, day:s.day};
    if (absent) {
        params.absent = absent;
    } else {
        params.time_in = tIn.replace('T',' ');
        params.time_out = tOut.replace('T',' ');
    }

    api('update_shift', params, function(d) {
        if (d.ok) {
            toast('Shift saved ('+d.hours+'h)');
            closeModal('shiftModal');
            loadLocations();
        } else toast(d.error||'Failed','err');
    }, 'POST');
}

function clearShift() {
    var s = STATE.currentShift;
    if (!s) return;
    if (!confirm('Clear this shift?')) return;
    api('clear_shift', {rstimeid:s.rstimeid, day:s.day}, function(d) {
        if (d.ok) { toast('Shift cleared'); closeModal('shiftModal'); loadLocations(); }
        else toast(d.error||'Failed','err');
    }, 'POST');
}

// ═══ ADD GUARD ═══
function openAddGuard(clientid, rosterid) {
    STATE.currentAddGuard = {clientid:clientid, rosterid:rosterid};
    document.getElementById('gmTitle').textContent = 'Add Guard to Roster';
    document.getElementById('gmSearch').value = '';
    document.getElementById('gmResults').innerHTML = '<div style="padding:20px;text-align:center;color:#9CA3AF;font-size:12px">Type to search</div>';

    // Load pool guards
    api('get_pool_guards', {clientid:clientid, period_id:STATE.periodId}, function(d) {
        if (d.ok && d.data.length > 0) {
            var ph = '<div style="margin-bottom:6px"><span style="font-size:11px;font-weight:600;color:#0369A1">🛡️ Approved Pool Guards ('+d.data.length+')</span></div>';
            d.data.forEach(function(g) {
                var busy = g.period_hours >= 48;
                // Check if already at this location
                var atLoc = (STATE.rosterData[clientid]||[]).some(function(a){ return a.employeeid == g.employeeid; });
                var cls = (busy || atLoc) ? 'disabled' : '';
                var statusTxt = atLoc ? '✓ Already here' : (busy ? '⛔ '+g.period_hours+'h (max)' : g.period_hours+'h this period');
                ph += '<div class="R-ei '+cls+'" onclick="'+(cls?'':'addGuardToRoster('+g.employeeid+')')+'">';
                ph += '<div><div class="name">'+esc(g.first_name+' '+g.last_name)+' <span class="R-ptag">POOL</span></div>';
                ph += '<div class="meta">#'+g.employeeid+' · '+esc(g.job_role||'')+' · '+(g.contract||8)+'hr</div></div>';
                ph += '<div style="font-size:10px;color:'+(busy?'#DC2626':atLoc?'#15803D':'#6B7280')+'">'+statusTxt+'</div></div>';
            });
            document.getElementById('gmPoolSection').innerHTML = ph;
        } else {
            document.getElementById('gmPoolSection').innerHTML = '';
        }
    });

    openModal('guardModal');
}

function searchEmployees() {
    var q = document.getElementById('gmSearch').value;
    if (q.length < 2) { document.getElementById('gmResults').innerHTML = '<div style="padding:20px;text-align:center;color:#9CA3AF;font-size:12px">Type at least 2 characters</div>'; return; }
    var cag = STATE.currentAddGuard;
    if (!cag) return;

    api('get_employees', {search:q, period_id:STATE.periodId, clientid:cag.clientid}, function(d) {
        if (!d.ok) return;
        var h = '';
        d.data.forEach(function(g) {
            var cls = g.at_location ? 'disabled' : '';
            var status = g.at_location ? '✓ Already here' : (g.period_hours > 0 ? g.period_hours+'h' : 'Available');
            var statusCol = g.at_location ? '#15803D' : (g.period_hours >= 48 ? '#DC2626' : '#6B7280');
            h += '<div class="R-ei '+cls+'" onclick="'+(g.at_location?'':'addGuardToRoster('+g.employeeid+')')+'">';
            h += '<div><div class="name">'+esc(g.first_name+' '+g.last_name);
            if (g.is_pool) h += ' <span class="R-ptag">POOL</span>';
            h += '</div><div class="meta">#'+g.employeeid+' · '+esc(g.departmentname||'')+' · '+(g.contract||8)+'hr</div></div>';
            h += '<div style="font-size:10px;color:'+statusCol+'">'+status+'</div></div>';
        });
        if (d.data.length === 0) h = '<div style="padding:20px;text-align:center;color:#9CA3AF;font-size:12px">No employees found</div>';
        document.getElementById('gmResults').innerHTML = h;
    });
}

function addGuardToRoster(employeeid) {
    var cag = STATE.currentAddGuard;
    if (!cag) return;
    api('add_guard', {rosterid:cag.rosterid, employeeid:employeeid}, function(d) {
        if (d.ok) { toast('Guard added'); closeModal('guardModal'); loadLocations(); }
        else toast(d.error||'Failed','err');
    }, 'POST');
}

// ═══ REMOVE GUARD ═══
function removeGuard(rstimeid, name) {
    if (!confirm('Remove '+name+' from this roster? This will delete all their shift data.')) return;
    api('remove_guard', {rstimeid:rstimeid}, function(d) {
        if (d.ok) { toast('Guard removed'); loadLocations(); } else toast(d.error||'Failed','err');
    }, 'POST');
}

// ═══ DUPLICATE ROSTER ═══
function showDuplicateModal() {
    var sel1 = document.getElementById('dupFrom');
    var sel2 = document.getElementById('dupTo');
    sel1.innerHTML = ''; sel2.innerHTML = '';
    STATE.periods.forEach(function(p) {
        var o1 = document.createElement('option'); o1.value=p.id; o1.textContent=p.period;
        var o2 = document.createElement('option'); o2.value=p.id; o2.textContent=p.period;
        sel1.appendChild(o1); sel2.appendChild(o2);
    });
    sel2.value = STATE.periodId;
    openModal('dupModal');
}
function doDuplicate() {
    var fp = document.getElementById('dupFrom').value;
    var tp = document.getElementById('dupTo').value;
    if (fp === tp) { toast('Cannot duplicate to same period','warn'); return; }
    api('duplicate_roster', {from_period:fp, to_period:tp}, function(d) {
        if (d.ok) { toast(d.count+' rosters duplicated'); closeModal('dupModal'); loadLocations(); }
        else toast(d.error||'Failed','err');
    }, 'POST');
}

// ═══ EMPLOYEE REPORT ═══
function loadEmpReport() {
    document.getElementById('empReportBox').innerHTML = '<div class="R-loading"><span class="R-spin"></span> Loading...</div>';
    api('get_employee_report', {period_id:STATE.periodId}, function(d) {
        if (!d.ok) { document.getElementById('empReportBox').innerHTML = '<div class="R-loading">Error</div>'; return; }
        var h = '<div style="overflow-x:auto"><table class="R-rtbl"><thead><tr><th>ID</th><th>Name</th><th>Dept</th><th>Role</th><th>Locs</th><th>Mon</th><th>Tue</th><th>Wed</th><th>Thu</th><th>Fri</th><th>Sat</th><th>Sun</th><th>Total</th><th>Normal</th><th>1.5×</th><th>2×</th><th>Status</th></tr></thead><tbody>';
        var gtotal=0, gnorm=0, ghalf=0, gdbl=0;
        d.data.forEach(function(r) {
            var tot = parseFloat(r.total)||0;
            var isOT = tot > 48;
            var cls = isOT ? 'style="background:#FFF5F5"' : (tot>=40?'style="background:#F0FFF4"':'');
            var barW = Math.min(100, (tot/56)*100);
            var barC = isOT ? '#EF4444' : (tot>=40?'#10B981':'#3B82F6');
            h += '<tr '+cls+'>';
            h += '<td style="font-weight:600">#'+r.employeeid+'</td>';
            h += '<td>'+esc(r.first_name+' '+r.last_name)+'</td>';
            h += '<td style="font-size:10px">'+esc(r.departmentname||'')+'</td>';
            h += '<td style="font-size:10px">'+esc(r.job_role||'')+'</td>';
            h += '<td style="text-align:center">'+r.loc_count+'</td>';
            ['mon','tue','wed','thu','fri','sat','sun'].forEach(function(dk) {
                var v = parseFloat(r[dk])||0;
                var ct = parseInt(r.contract)||8;
                h += '<td style="text-align:center;font-weight:'+(v>0?'600':'400')+';color:'+(v>ct?'#DC2626':(v>0?'#1F2937':'#D1D5DB'))+'">'+(v>0?v:'-')+'</td>';
            });
            h += '<td style="font-weight:700">'+tot+'h <span class="R-hbar"><span class="R-hfill" style="width:'+barW+'%;background:'+barC+'"></span></span></td>';
            h += '<td>'+r.normal_hrs+'h</td>';
            h += '<td style="color:'+(r.time_half_hrs>0?'#B45309':'#D1D5DB')+'">'+(r.time_half_hrs>0?r.time_half_hrs+'h':'-')+'</td>';
            h += '<td style="color:'+(r.double_hrs>0?'#DC2626':'#D1D5DB')+'">'+(r.double_hrs>0?r.double_hrs+'h':'-')+'</td>';
            h += '<td><span class="R-bg '+(isOT?'bg-err':(tot>=40?'bg-ok':'bg-warn'))+'">'+(isOT?'OT':tot>=40?'OK':'UNDER')+'</span></td>';
            h += '</tr>';
            gtotal+=tot; gnorm+=parseFloat(r.normal_hrs)||0; ghalf+=parseFloat(r.time_half_hrs)||0; gdbl+=parseFloat(r.double_hrs)||0;
        });
        h += '<tr style="font-weight:700;background:#F8FAFB"><td colspan="12" style="text-align:right">TOTALS</td><td>'+gtotal.toFixed(1)+'h</td><td>'+gnorm.toFixed(1)+'h</td><td>'+ghalf.toFixed(1)+'h</td><td>'+gdbl.toFixed(1)+'h</td><td></td></tr>';
        h += '</tbody></table></div>';
        h += '<div style="margin-top:8px;font-size:11px;color:#6B7280">'+d.data.length+' employees · OT calc: 8hr contract (≤8 normal, 8-12 ×1.5, >12 ×2) | 9hr contract (≤9 normal, 9-13 ×1.5, >13 ×2)</div>';
        document.getElementById('empReportBox').innerHTML = h;
    });
}

// ═══ LOCATION REPORT ═══
function loadLocReport() {
    document.getElementById('locReportBox').innerHTML = '<div class="R-loading"><span class="R-spin"></span> Loading...</div>';
    api('get_location_report', {period_id:STATE.periodId}, function(d) {
        if (!d.ok) return;
        var h = '<div style="overflow-x:auto"><table class="R-rtbl"><thead><tr><th>Location</th><th>Customer</th><th>Dept</th><th>Sector</th><th>Req</th><th>Assigned</th><th>Coverage</th><th>Hrs Req</th><th>Hrs Sched</th><th>Est. Cost</th><th>Status</th></tr></thead><tbody>';
        d.data.forEach(function(r) {
            var pct = parseInt(r.req_guards)>0 ? Math.round((parseInt(r.assigned)/parseInt(r.req_guards))*100) : 0;
            var cost = parseFloat(r.sched_hrs) * parseFloat(r.base_wage||0);
            var barC = pct>=100?'#10B981':(pct>=50?'#F59E0B':'#EF4444');
            h += '<tr>';
            h += '<td style="font-weight:600">'+esc(r.patrollocation)+'</td>';
            h += '<td>'+esc(r.customername||'')+'</td>';
            h += '<td style="font-size:10px">'+esc(r.departmentname||'')+'</td>';
            h += '<td style="font-size:10px">'+esc(r.sector_name||'')+'</td>';
            h += '<td style="text-align:center">'+(r.req_guards||0)+'</td>';
            h += '<td style="text-align:center;font-weight:600">'+(r.assigned||0)+'</td>';
            h += '<td>'+pct+'% <span class="R-hbar"><span class="R-hfill" style="width:'+Math.min(100,pct)+'%;background:'+barC+'"></span></span></td>';
            h += '<td>'+(r.weekly_hours_required||0)+'h</td>';
            h += '<td style="font-weight:600">'+Math.round(parseFloat(r.sched_hrs)||0)+'h</td>';
            h += '<td>$'+cost.toFixed(2)+'</td>';
            h += '<td><span class="R-bg '+(pct>=100?'bg-ok':(pct>0?'bg-warn':'bg-err'))+'">'+(pct>=100?'FULL':(pct>0?'PARTIAL':'EMPTY'))+'</span></td>';
            h += '</tr>';
        });
        h += '</tbody></table></div>';
        document.getElementById('locReportBox').innerHTML = h;
    });
}
</script>
