/**
 * css/styles.css — Vee Industrial Complete Stylesheet
 * ════════════════════════════════════════════════════════════════
 * Extracted from demo.html <style> block.
 * All CSS is here — no inline styles in index.html.
 *
 * Architecture notes:
 * - CSS variables defined in :root and body.stage-* blocks
 * - Later rules override earlier (injection-layer pattern)
 * - Critical rules use !important to win cascade fights:
 *   → .ni, .sp-item pointer-events (never remove)
 *   → .md overflow-y:auto (scroll fix)
 *   → min-height:0 on flex scroll chain
 *
 * Stages: stage-day | stage-dusk | stage-dusk-dark | stage-night
 * ════════════════════════════════════════════════════════════════
 */



/* ══════════════════════════════════════════════════════════════
   VEE INDUSTRIAL — REDESIGN V2
   Four-stage luminance. SaaS structure. Vee soul.
   Stages: Day → Dusk → Dusk Dark → Night
══════════════════════════════════════════════════════════════ */

/* ── STAGE VARIABLES ── */
:root {
  /* Brand constants — never change */
  --y:    #FFCD11;
  --yd:   #E6B800;
  --gr:   #4CAF50;
  --r:    #F44336;
  --o:    #FF9800;
  --pu:   #a78bfa;
  --trans: 0.18s cubic-bezier(0.4,0,0.2,1);
  --trans-spring: 0.22s cubic-bezier(0.34,1.15,0.64,1);
  --radius-card: 12px;
  --radius-btn:  8px;
  --radius-input: 8px;
  --sidebar-w: 220px;
  --topbar-h: 56px;
}

/* ── DAY (lightest) ── */
body.stage-day {
  --bg:   #F7F7F5;
  --surf: #FFFFFF;
  --surf2:#F0EFE9;
  --ow:   #111110;
  --g:    #7A7A74;
  --bd:   #E2E2DE;
  --shadow: 0 1px 3px rgba(0,0,0,.06), 0 2px 8px rgba(0,0,0,.04);
  --shadow-md: 0 4px 16px rgba(0,0,0,.08);
  --shadow-lg: 0 12px 40px rgba(0,0,0,.12);
}

/* ── DUSK (warm mid-light) ── */
body.stage-dusk {
  --bg:   #EEEDE7;
  --surf: #F5F4EF;
  --surf2:#E6E5DF;
  --ow:   #1A1A18;
  --g:    #6B6A65;
  --bd:   #D4D3CC;
  --shadow: 0 1px 3px rgba(0,0,0,.08), 0 2px 8px rgba(0,0,0,.06);
  --shadow-md: 0 4px 16px rgba(0,0,0,.10);
  --shadow-lg: 0 12px 40px rgba(0,0,0,.14);
}

/* ── DUSK DARK (cool mid-dark) ── */
body.stage-dusk-dark {
  --bg:   #1E1E1C;
  --surf: #272725;
  --surf2:#2E2E2C;
  --ow:   #E8E8E4;
  --g:    #888884;
  --bd:   #383836;
  --shadow: 0 1px 3px rgba(0,0,0,.25), 0 2px 8px rgba(0,0,0,.18);
  --shadow-md: 0 4px 16px rgba(0,0,0,.3);
  --shadow-lg: 0 12px 40px rgba(0,0,0,.45);
}

/* ── NIGHT (darkest) ── */
body.stage-night {
  --bg:   #0A0A0A;
  --surf: #141414;
  --surf2:#1C1C1C;
  --ow:   #F5F5F0;
  --g:    #888880;
  --bd:   #2A2A2A;
  --shadow: 0 1px 3px rgba(0,0,0,.4), 0 2px 8px rgba(0,0,0,.3);
  --shadow-md: 0 4px 16px rgba(0,0,0,.5);
  --shadow-lg: 0 12px 40px rgba(0,0,0,.65);
}

/* ── FONT & RESET ── */
*,*::before,*::after { box-sizing:border-box; margin:0; padding:0; }
html,body { height:100%; }
body {
  background: var(--bg);
  color: var(--ow);
  font-family: 'Barlow', sans-serif;
  font-size: 14px;
  line-height: 1.55;
  letter-spacing: 0.01em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transition: background var(--trans), color var(--trans);
}
body::before {
  content:'';
  position:fixed;inset:0;
  background-image: repeating-linear-gradient(-45deg,transparent,transparent 40px,rgba(255,205,17,.012) 40px,rgba(255,205,17,.012) 41px);
  pointer-events:none;z-index:0;
}
body.stage-day::before, body.stage-dusk::before {
  background-image: repeating-linear-gradient(-45deg,transparent,transparent 40px,rgba(0,0,0,.012) 40px,rgba(0,0,0,.012) 41px);
}

/* ══ APP SHELL ══════════════════════════════════════════════════ */
#app {
  display: none;
  height: 100vh;
  flex-direction: column;
  position: relative;
  z-index: 1;
  background: var(--bg);
}

/* ── TOP BAR ── */
#topbar {
  height: var(--topbar-h);
  background: var(--surf);
  border-bottom: 1px solid var(--bd);
  display: flex;
  align-items: center;
  padding: 0 20px 0 0;
  flex-shrink: 0;
  gap: 0;
  box-shadow: var(--shadow);
  z-index: 10;
  position: relative;
}
#topbar-brand {
  width: var(--sidebar-w);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 10px;
  border-right: 1px solid var(--bd);
  height: 100%;
}
#topbar-brand .tb-mark {
  width: 30px; height: 30px;
  background: var(--y);
  display: flex; align-items: center; justify-content: center;
  border-radius: 8px;
  font-family: 'Barlow Condensed',sans-serif;
  font-weight: 900; font-size: 16px;
  color: #0A0A0A;
  flex-shrink: 0;
}
#topbar-brand .tb-name {
  font-family: 'Barlow Condensed', sans-serif;
  font-weight: 900; font-size: 17px;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--ow); line-height: 1;
}
#topbar-brand .tb-sub {
  font-family: 'Barlow Semi Condensed', sans-serif;
  font-size: 9px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--g); line-height: 1;
  margin-top: 2px;
}
#topbar-search {
  flex: 1;
  display: flex; align-items: center;
  padding: 0 20px;
}
#topbar-search-inner {
  display: flex; align-items: center; gap: 8px;
  background: var(--surf2);
  border: 1px solid var(--bd);
  border-radius: 8px;
  padding: 7px 14px;
  width: 280px;
  max-width: 100%;
  cursor: text;
  transition: border-color var(--trans), box-shadow var(--trans);
}
#topbar-search-inner:hover { border-color: var(--g); }
#topbar-search-inner span {
  font-size: 13px; color: var(--g);
  font-family: 'Barlow Semi Condensed', sans-serif;
  font-weight: 500; letter-spacing: .02em;
  user-select: none;
}
#topbar-search-inner kbd {
  margin-left: auto;
  font-size: 10px; color: var(--g);
  background: var(--surf); border: 1px solid var(--bd);
  border-radius: 4px; padding: 1px 5px;
  font-family: 'Barlow Semi Condensed', sans-serif;
}
#topbar-right {
  display: flex; align-items: center; gap: 6px;
  flex-shrink: 0;
}
.topbar-icon-btn {
  width: 36px; height: 36px;
  border-radius: 8px;
  border: 1px solid var(--bd);
  background: var(--surf2);
  color: var(--g);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px;
  transition: border-color var(--trans), color var(--trans), background var(--trans), transform var(--trans-spring);
}
.topbar-icon-btn:hover { border-color: var(--y); color: var(--ow); transform: translateY(-1px); }
#topbar-stage-btn {
  display: flex; align-items: center; gap: 8px;
  padding: 0 12px;
  height: 36px;
  border-radius: 8px;
  border: 1px solid var(--bd);
  background: var(--surf2);
  color: var(--g);
  cursor: pointer;
  font-family: 'Barlow Semi Condensed', sans-serif;
  font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  transition: all var(--trans);
  white-space: nowrap;
}
#topbar-stage-btn:hover { border-color: var(--y); color: var(--ow); }
#topbar-user {
  display: flex; align-items: center; gap: 10px;
  padding: 0 4px 0 10px;
  cursor: pointer;
  border-radius: 10px;
  border: 1px solid transparent;
  transition: border-color var(--trans), background var(--trans);
  margin-left: 4px;
  height: 40px;
}
#topbar-user:hover { border-color: var(--bd); background: var(--surf2); }
#topbar-user .tu-avatar {
  width: 30px; height: 30px; border-radius: 50%;
  background: linear-gradient(135deg, var(--y) 0%, var(--yd) 100%);
  display: flex; align-items: center; justify-content: center;
  font-family: 'Barlow Condensed',sans-serif;
  font-weight: 900; font-size: 13px; color: #0A0A0A;
  flex-shrink: 0;
}
#topbar-user .tu-name {
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 12px; font-weight: 600; color: var(--ow);
}
#topbar-user .tu-role {
  font-size: 10px; color: var(--g);
  font-family: 'Barlow Semi Condensed',sans-serif;
}

/* ── DEMO BANNER (slim strip) ── */
.dbanner {
  background: transparent;
  border-bottom: 1px solid rgba(255,205,17,.1);
  padding: 4px 20px 4px calc(var(--sidebar-w) + 20px);
  display: flex; align-items: center; justify-content: space-between;
  flex-shrink: 0; flex-wrap: wrap; gap: 8px;
}
.dbanner-l {
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 10px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--y); opacity: .6;
}
.dbanner-r { font-size: 10px; color: var(--g); font-family: 'Barlow Semi Condensed',sans-serif; opacity: .7; }

/* ── DEMO TIME BANNER ── */
#demo-time-banner {
  background: rgba(167,139,250,.08);
  border-bottom: 1px solid rgba(167,139,250,.2);
  padding: 5px 20px 5px calc(var(--sidebar-w) + 20px);
  flex-shrink: 0;
}

/* ── PORTAL INFO BAR (separator) ── */
#portal-sep-bar {
  background: rgba(255,205,17,.03);
  border-bottom: 1px solid rgba(255,205,17,.07);
  padding: 4px 20px 4px calc(var(--sidebar-w) + 20px);
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 10px; color: var(--g); opacity: .6;
  flex-shrink: 0;
}

/* ══ MAIN LAYOUT ════════════════════════════════════════════════ */
#app-body {
  display: flex;
  flex: 1;
  overflow: hidden; /* intentional - children scroll */
  min-height: 0;
}

/* ══ SIDEBAR ════════════════════════════════════════════════════ */
#sidebar {
  width: var(--sidebar-w);
  background: var(--surf);
  border-right: 1px solid var(--bd);
  display: flex; flex-direction: column;
  flex-shrink: 0; overflow-y: auto;
  transition: background var(--trans);
}

/* Portal switcher at top of sidebar */
#sidebar-portals {
  padding: 12px 12px 8px;
  border-bottom: 1px solid var(--bd);
}
.sp-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px;
  border-radius: 8px;
  cursor: pointer;
  margin-bottom: 2px;
  transition: background var(--trans), color var(--trans);
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 12px; font-weight: 600;
  color: var(--g);
  border: 1px solid transparent;
}
.sp-item:hover { background: var(--surf2); color: var(--ow); }
.sp-item.active {
  background: rgba(255,205,17,.08);
  border-color: rgba(255,205,17,.2);
  color: var(--y);
}
.sp-item .sp-icon { font-size: 15px; width: 20px; text-align: center; flex-shrink: 0; }
.sp-item .sp-label { font-weight: 700; font-size: 12px; line-height: 1; }
.sp-item .sp-sub {
  font-size: 9px; font-weight: 500; color: var(--g);
  letter-spacing: .04em; margin-top: 1px; line-height: 1;
}
.sp-item.active .sp-sub { color: rgba(255,205,17,.6); }

/* Sidebar nav */
#sidebar-nav { flex: 1; padding: 10px 12px; }
.ns {
  padding: 12px 8px 4px;
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 9px; font-weight: 700; letter-spacing: .2em;
  text-transform: uppercase; color: var(--g); opacity: .5;
}
.ni {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 12px;
  cursor: pointer;
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 12px; font-weight: 500;
  color: var(--g);
  border-radius: 8px;
  border: 1px solid transparent;
  margin-bottom: 1px;
  transition: background var(--trans), color var(--trans), border-color var(--trans);
}
.ni:hover { background: var(--surf2); color: var(--ow); }
.ni.active {
  background: rgba(255,205,17,.09);
  border-color: rgba(255,205,17,.18);
  color: var(--y);
  font-weight: 700;
}
.nic { font-size: 14px; width: 18px; text-align: center; flex-shrink: 0; }

/* Sidebar bottom user strip */
#sidebar-footer {
  border-top: 1px solid var(--bd);
  padding: 12px;
}
.sf-user {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  transition: background var(--trans);
}
.sf-user:hover { background: var(--surf2); }
.sf-avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: linear-gradient(135deg, var(--y) 0%, var(--yd) 100%);
  display: flex; align-items: center; justify-content: center;
  font-family: 'Barlow Condensed',sans-serif;
  font-weight: 900; font-size: 14px; color: #0A0A0A;
  flex-shrink: 0;
}
.sf-name {
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 12px; font-weight: 600; color: var(--ow); line-height: 1;
}
.sf-email { font-size: 10px; color: var(--g); margin-top: 2px; line-height: 1; }
.sf-chevron { margin-left: auto; color: var(--g); font-size: 11px; }

/* ══ PVIEWS (content areas) ════════════════════════════════════ */
#content-area {
  flex: 1; overflow: hidden;
  display: flex; flex-direction: column;
  min-height: 0;
}
.pview { display: none; flex: 1; overflow: hidden; min-height: 0; }
.pview.active { display: flex; }
#pv-employer { flex-direction: column; overflow-y: auto; min-height: 0; flex: 1; }

main {
  flex: 1; overflow-y: auto;
  padding: 24px 28px;
  display: flex; flex-direction: column; gap: 16px;
}
.pg { display: none; flex-direction: column; gap: 16px; animation: none; }
.pg.active { display: flex; animation: pg-in .18s ease both; }
@keyframes pg-in { from { opacity:0; transform:translateY(6px); } to { opacity:1; transform:translateY(0); } }

/* ── Page header ── */
.pg-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  margin-bottom: 4px; gap: 16px; flex-wrap: wrap;
}
.pg-title {
  font-family: 'Barlow Condensed',sans-serif;
  font-weight: 900; font-size: 28px; letter-spacing: -.01em;
  text-transform: uppercase; color: var(--ow); line-height: 1;
}
.pg-sub {
  font-size: 13px; color: var(--g); margin-top: 4px;
  font-family: 'Barlow Semi Condensed',sans-serif; line-height: 1.4;
}

/* ══ CARDS / PANELS ═════════════════════════════════════════════ */
.panel {
  background: var(--surf);
  border: 1px solid var(--bd);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow);
  transition: box-shadow var(--trans), border-color var(--trans);
}
.ph {
  padding: 14px 18px;
  border-bottom: 1px solid var(--bd);
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 10px;
}
.pt {
  font-family: 'Barlow Condensed',sans-serif;
  font-weight: 900; font-size: 14px;
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--ow);
}

/* ══ STAT CARDS ═════════════════════════════════════════════════ */
.sr { display: grid; grid-template-columns: repeat(4,1fr); gap: 12px; }
.sc {
  background: var(--surf);
  border: 1px solid var(--bd);
  border-radius: var(--radius-card);
  border-top: 3px solid var(--y);
  padding: 18px 20px;
  box-shadow: var(--shadow);
  transition: transform var(--trans-spring), box-shadow var(--trans);
  cursor: default;
}
.sc:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.scl {
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 9px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--g); margin-bottom: 6px;
}
.scv {
  font-family: 'Barlow Condensed',sans-serif;
  font-weight: 900; font-size: 30px; color: var(--y);
  line-height: 1;
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
}
.scs { font-size: 10px; color: var(--g); margin-top: 4px; letter-spacing: .02em; }

/* ══ HEALTH SCORE ═══════════════════════════════════════════════ */
.hsc {
  background: var(--surf);
  border: 1px solid var(--bd);
  border-radius: var(--radius-card);
  padding: 22px 24px;
  display: grid; grid-template-columns: auto 1fr;
  gap: 22px; align-items: center;
  box-shadow: var(--shadow);
  position: relative; overflow: hidden;
}
.hsc::before {
  content:'';position:absolute;top:-30px;right:-30px;
  width:120px;height:120px;
  background:radial-gradient(circle,rgba(255,205,17,.07) 0%,transparent 70%);
  pointer-events:none;
}
.hcircle { position:relative; width:96px; height:96px; flex-shrink:0; }
.hcircle svg { transform:rotate(-90deg); }
.hnum { position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center; }
.hn { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:28px;line-height:1;font-variant-numeric:tabular-nums; }
.hl2 { font-family:'Barlow Semi Condensed',sans-serif;font-size:9px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--g);margin-top:1px; }
.hbr { display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:10px; }
.hbi { background:var(--surf2);border:1px solid var(--bd);padding:8px 10px;border-radius:8px; transition:background var(--trans); }
.hbi:hover { background:var(--bd); }
.hbv { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;line-height:1;font-variant-numeric:tabular-nums; }
.hbl { font-family:'Barlow Semi Condensed',sans-serif;font-size:9px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--g);margin-top:2px; }

/* ══ BUTTONS ════════════════════════════════════════════════════ */
.btn {
  font-family: 'Barlow Condensed',sans-serif;
  font-weight: 900; font-size: 12px; letter-spacing: .07em;
  text-transform: uppercase; border: none;
  padding: 8px 18px; cursor: pointer;
  border-radius: var(--radius-btn);
  transition: all var(--trans);
  display: inline-flex; align-items: center; gap: 6px;
  white-space: nowrap; position: relative; overflow: hidden;
}
.btn:hover { transform: translateY(-1px); filter: brightness(1.08); }
.btn:active { transform: translateY(0) scale(.97); filter: brightness(.95); }
.btn:focus-visible { outline: 2px solid var(--y); outline-offset: 3px; }
.by  { background:var(--y);  color:#0A0A0A; }
.by:hover { background:var(--yd); box-shadow:0 4px 14px rgba(255,205,17,.3); }
.bo  { background:var(--o);  color:#0A0A0A; }
.bpu { background:var(--pu); color:#0A0A0A; }
.bpu:hover { background:#8b5cf6; box-shadow:0 4px 14px rgba(167,139,250,.3); }
.bout {
  background: transparent;
  border: 1px solid var(--bd); color: var(--g);
  border-radius: var(--radius-btn);
  transition: border-color var(--trans), color var(--trans), background var(--trans), transform var(--trans-spring);
}
.bout:hover { border-color:var(--y); color:var(--y); background:rgba(255,205,17,.04); transform:translateY(-1px); }
.bsm  { font-size: 10px; padding: 6px 12px; }
.bred { background:var(--r); color:#fff; }
.bred:hover { box-shadow:0 4px 14px rgba(244,67,54,.3); }

/* ══ INPUTS ═════════════════════════════════════════════════════ */
.fl {
  display: block;
  font-family: 'Barlow Semi Condensed',sans-serif;
  font-size: 10px; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--g); margin-bottom: 7px;
}
.fi {
  width: 100%;
  background: var(--surf2);
  border: 1px solid var(--bd);
  color: var(--ow);
  font-family: 'Barlow',sans-serif;
  font-size: 14px; padding: 11px 14px; outline: none;
  margin-bottom: 14px;
  border-radius: var(--radius-input);
  transition: border-color var(--trans), box-shadow var(--trans), background var(--trans);
}
.fi:focus { border-color:var(--y); box-shadow:0 0 0 3px rgba(255,205,17,.1); background:var(--surf); }
.fi:hover:not(:focus) { border-color:var(--g); }
.fi:-webkit-autofill,.fi:-webkit-autofill:hover,.fi:-webkit-autofill:focus {
  -webkit-box-shadow:0 0 0 1000px var(--surf2) inset!important;
  -webkit-text-fill-color:var(--ow)!important;
  border-color:var(--y)!important;
}
.fi::placeholder { color:var(--g); opacity:.6; }
.fi[type=number]::-webkit-inner-spin-button,.fi[type=number]::-webkit-outer-spin-button { opacity:.4; }
select.fi { appearance:none; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23888880' stroke-width='1.5' fill='none'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right 14px center; }

/* ══ MODAL ══════════════════════════════════════════════════════ */
.mo { position:fixed;inset:0;background:rgba(0,0,0,.75);z-index:1000;display:none;align-items:flex-start;justify-content:center;padding:24px;overflow-y:auto;backdrop-filter:blur(4px); }
.mo.open { display:flex; animation:backdrop-in .2s ease both; }
@keyframes backdrop-in { from{opacity:0} to{opacity:1} }
.mo.open .md { animation:modal-up .22s cubic-bezier(0.34,1.15,0.64,1) both; }
@keyframes modal-up { from{opacity:0;transform:translateY(16px) scale(.97)} to{opacity:1;transform:translateY(0) scale(1)} }
.md {
  background:var(--surf);border:1px solid var(--bd);
  border-top:2px solid var(--y);
  border-radius:14px;
  width:100%;max-width:520px;padding:28px 30px;margin:auto;
  max-height:90vh;overflow-y:auto;
  box-shadow:var(--shadow-lg),0 0 0 1px rgba(255,255,255,.03);
}
.mdt { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;letter-spacing:.02em;margin-bottom:5px; }
.mds { font-size:12px;color:var(--g);margin-bottom:20px;line-height:1.65; }
.mr { display:grid;grid-template-columns:1fr 1fr;gap:12px; }
.ma { display:flex;gap:10px;margin-top:22px;justify-content:flex-end; }
.fg { margin-top:12px; }
.fg .fi { margin-bottom:0; }

/* ══ WORKER GRID ════════════════════════════════════════════════ */
.wg { display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:12px;padding:16px; }
.wt {
  background:var(--surf);
  border:1px solid var(--bd);
  border-radius: 10px;
  padding:14px;display:flex;align-items:flex-start;gap:12px;
  box-shadow:var(--shadow);
  transition:transform var(--trans-spring),border-color var(--trans),box-shadow var(--trans);
  cursor:default;
}
.wt.test { border-color:rgba(167,139,250,.35); border-style:dashed; }
.wt:hover { transform:translateY(-2px);border-color:rgba(255,205,17,.25);box-shadow:var(--shadow-md); }
.av {
  width:36px;height:36px;
  background:rgba(255,205,17,.1);border:1px solid rgba(255,205,17,.2);
  display:flex;align-items:center;justify-content:center;
  font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;color:var(--y);
  border-radius:8px;flex-shrink:0;
  transition:transform var(--trans-spring),background var(--trans);
}
.wt:hover .av { transform:scale(1.08);background:rgba(255,205,17,.16); }
.ptag { font-family:'Barlow Semi Condensed',sans-serif;font-size:9px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;background:rgba(255,205,17,.08);border:1px solid rgba(255,205,17,.18);color:var(--y);padding:2px 7px;display:inline-block;border-radius:4px; }
.rd { display:inline-block;width:7px;height:7px;border-radius:50%; }
.rdg { background:var(--gr); }
.rdy { background:var(--y); }
.rdr { background:var(--r); }

/* ══ TABLE ══════════════════════════════════════════════════════ */
.tw { overflow-x:auto; }
table { width:100%;border-collapse:collapse; }
th {
  font-family:'Barlow Semi Condensed',sans-serif;
  font-size:9px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--g);padding:10px 14px;text-align:left;
  border-bottom:1px solid var(--bd);background:var(--surf2);
  position:sticky;top:0;z-index:1;
}
td { padding:10px 14px;border-bottom:1px solid rgba(42,42,42,.35);font-size:12px;vertical-align:middle; }
body.stage-day td, body.stage-dusk td { border-bottom-color:rgba(0,0,0,.06); }
tr:last-child td { border-bottom:none; }
tbody tr { transition:background var(--trans); }
tbody tr:hover { background:rgba(255,255,255,.03); }
body.stage-day tbody tr:hover, body.stage-dusk tbody tr:hover { background:rgba(0,0,0,.025); }
.wn { font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;font-size:13px; }
.hv { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:17px;color:var(--y);font-variant-numeric:tabular-nums; }
.badge { font-family:'Barlow Semi Condensed',sans-serif;font-size:9px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;padding:3px 8px;display:inline-block;border-radius:4px; }
.bgr { background:rgba(76,175,80,.12);color:var(--gr); }
.brd { background:rgba(244,67,54,.12);color:var(--r); }
.bpu { background:rgba(167,139,250,.12);color:var(--pu); }

/* ══ INFO BOX ═══════════════════════════════════════════════════ */
.ib {
  background:rgba(255,205,17,.04);
  border:1px solid rgba(255,205,17,.12);
  border-left:3px solid var(--y);
  border-radius: 8px;
  padding:12px 16px;font-size:12px;color:var(--g);line-height:1.65;
}
.ib strong { color:var(--ow); }

/* ══ CLERK PORTAL ═══════════════════════════════════════════════ */
#pv-clerk { flex-direction:column;overflow-y:auto; }
.clerk-wrap { padding:24px;display:flex;flex-direction:column;gap:16px;max-width:700px;width:100%;margin:0 auto; }
.code-input { width:100%;background:var(--surf2);border:2px solid var(--bd);color:var(--ow);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:48px;letter-spacing:.2em;padding:16px;outline:none;text-align:center;transition:border-color var(--trans);border-radius:10px; }
.code-input:focus { border-color:var(--o); }
.cresult { display:none;padding:20px;text-align:center;border:2px solid transparent;margin-top:4px;border-radius:10px; }
.crname { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:28px;margin-bottom:4px; }
.crtag { font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:5px 14px;display:inline-block;border-radius:4px; }
.npg { display:grid;grid-template-columns:repeat(3,1fr);gap:8px; }
.npb {
  background:var(--surf2);border:1px solid var(--bd);
  color:var(--ow);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;
  padding:13px;cursor:pointer;
  border-radius:10px;
  transition:background var(--trans),border-color var(--trans),transform var(--trans-spring);
  user-select:none;
}
.npb:hover { border-color:var(--o);background:rgba(255,152,0,.06); }
.npb:active { transform:scale(.93); }

/* ══ MANAGER PORTAL ═════════════════════════════════════════════ */
#pv-manager { flex-direction:column;overflow-y:auto; }
.mgr-worker-row { display:flex;align-items:center;gap:12px;padding:11px 16px;border-bottom:1px solid var(--bd);flex-wrap:wrap;transition:background var(--trans); }
.mgr-worker-row:hover { background:rgba(255,255,255,.025); }
body.stage-day .mgr-worker-row:hover, body.stage-dusk .mgr-worker-row:hover { background:rgba(0,0,0,.02); }
.susp-dismissed { opacity:.4;pointer-events:none; }
.susp-dismissed .dismiss-overlay { pointer-events:auto; }
.dismiss-badge { font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;padding:2px 8px;background:rgba(136,136,128,.15);color:var(--g);margin-left:6px;cursor:pointer;position:relative;border-radius:3px; }
.dismiss-tooltip { display:none;position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);background:var(--surf);border:1px solid var(--bd);padding:8px 12px;font-size:11px;color:var(--ow);z-index:9999;box-shadow:var(--shadow-lg);font-family:'Barlow Semi Condensed',sans-serif;font-weight:400;line-height:1.5;max-width:280px;white-space:normal;text-align:left;border-radius:8px; }
.dismiss-badge:hover .dismiss-tooltip { display:block; }

/* ══ EMPLOYEE PORTAL ════════════════════════════════════════════ */
.emp-wrap { padding:24px;display:flex;flex-direction:column;gap:16px;max-width:500px;width:100%;margin:0 auto; }
.emp-sel { display:grid;grid-template-columns:repeat(4,1fr);gap:8px; }
.hbtn { background:var(--surf2);border:1px solid var(--bd);color:var(--ow);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;padding:14px;cursor:pointer;transition:all var(--trans);text-align:center;border-radius:8px; }
.hbtn:hover { border-color:var(--y);color:var(--y); }
.hbtn.sel { background:var(--y);color:#0A0A0A;border-color:var(--y); }
.emp-history { display:flex;flex-direction:column;gap:8px; }
.eh { background:var(--surf2);border:1px solid var(--bd);border-left:3px solid var(--y);border-radius:8px;padding:12px 16px;display:flex;justify-content:space-between;align-items:center; }

/* ══ SITE BARS ══════════════════════════════════════════════════ */
.srow { display:flex;align-items:center;gap:12px;padding:11px 16px;border-bottom:1px solid var(--bd);transition:background var(--trans); }
.srow:last-child { border-bottom:none; }
.srow:hover { background:rgba(255,255,255,.02); }
body.stage-day .srow:hover, body.stage-dusk .srow:hover { background:rgba(0,0,0,.02); }
.sbw { flex:1;background:var(--surf2);height:6px;border-radius:3px; }
.sbar { background:var(--y);height:100%;transition:width .6s ease;border-radius:3px; }

/* ══ CI SPLIT ═══════════════════════════════════════════════════ */
.ci-split { display:grid;grid-template-columns:1fr 1fr;gap:16px; }

/* ══ TOAST ══════════════════════════════════════════════════════ */
.toast {
  position:fixed;bottom:24px;right:24px;
  background:var(--surf);border:1px solid var(--bd);
  border-left:3px solid var(--pu);
  color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;
  font-size:12px;font-weight:500;padding:12px 18px;
  z-index:9999;opacity:0;transform:translateY(10px);
  transition:all .3s;pointer-events:none;
  border-radius:10px;
  box-shadow:var(--shadow-lg);
}
.toast.show { opacity:1;transform:none;animation:toast-in .25s cubic-bezier(0.34,1.15,0.64,1) both; }
@keyframes toast-in { from{opacity:0;transform:translateY(10px) scale(.95)} to{opacity:1;transform:translateY(0) scale(1)} }

/* ══ TOOLTIP ════════════════════════════════════════════════════ */
#vee-tip { position:fixed;z-index:99999;max-width:200px;background:var(--surf);border:1px solid var(--bd);border-left:3px solid var(--y);padding:9px 13px;pointer-events:none;opacity:0;transition:opacity var(--trans);box-shadow:var(--shadow-md);border-radius:8px; }
#vee-tip.show { opacity:1; }
#vee-tip-title { font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--y);margin-bottom:3px; }
#vee-tip-body  { font-size:11px;color:var(--ow);line-height:1.5; }

/* ══ HELP BUTTON & PANEL ════════════════════════════════════════ */
#vee-help { position:fixed;bottom:20px;right:20px;width:38px;height:38px;background:var(--surf);border:1px solid var(--bd);color:var(--g);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:17px;cursor:pointer;z-index:9998;display:flex;align-items:center;justify-content:center;transition:all var(--trans);border-radius:10px; }
#vee-help:hover { border-color:var(--y);color:var(--y);transform:translateY(-1px); }
#vee-help-panel { position:fixed;bottom:66px;right:20px;width:300px;max-height:70vh;overflow-y:auto;background:var(--surf);border:1px solid var(--bd);border-top:2px solid var(--y);z-index:9997;display:none;box-shadow:var(--shadow-lg);border-radius:12px; }
#vee-help-panel.open { display:block;animation:panel-in .2s cubic-bezier(0.34,1.15,0.64,1) both; }
@keyframes panel-in { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
.help-ph { padding:12px 16px;border-bottom:1px solid var(--bd);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--y); }
.help-item { padding:9px 14px;border-bottom:1px solid rgba(42,42,42,.3);display:flex;gap:10px; }
.help-item:last-child { border-bottom:none; }
.help-icon { font-size:15px;flex-shrink:0;width:20px;text-align:center;margin-top:1px; }
.help-text { flex:1; }
.help-label { font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--ow);margin-bottom:2px; }
.help-desc { font-size:10px;color:var(--g);line-height:1.5; }

/* ══ SETTINGS / DARK BTN (hidden — replaced by topbar) ═════════ */
#vee-settings-btn,#vee-dark-btn { display:none!important; }

/* ══ PASSWORD GATE ══════════════════════════════════════════════ */
#gate { position:fixed;inset:0;background:var(--bg);z-index:9999;display:flex;align-items:center;justify-content:center;padding:20px; }
#gate::after { content:'';position:fixed;inset:0;background-image:repeating-linear-gradient(90deg,transparent,transparent 39px,rgba(255,205,17,.025) 39px,rgba(255,205,17,.025) 40px),repeating-linear-gradient(0deg,transparent,transparent 39px,rgba(255,205,17,.015) 39px,rgba(255,205,17,.015) 40px);pointer-events:none;z-index:0; }
.gbox { position:relative;z-index:1;background:var(--surf);border:1px solid var(--bd);border-top:2px solid var(--y);width:100%;max-width:400px;padding:44px 40px;border-radius:16px;box-shadow:var(--shadow-lg);animation:gate-rise .4s cubic-bezier(0.34,1.1,0.64,1) both; }
@keyframes gate-rise { from{opacity:0;transform:translateY(16px) scale(.98)} to{opacity:1;transform:translateY(0) scale(1)} }
.glogo { display:flex;align-items:center;margin-bottom:20px; }
.glv { background:var(--surf2);color:var(--ow);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:28px;padding:4px 16px 4px 10px;clip-path:polygon(0 0,85% 0,100% 100%,0 100%);border:1px solid var(--bd);border-right:none; }
.glt { background:var(--pu);color:#fff;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;letter-spacing:.15em;padding:4px 14px 4px 16px;clip-path:polygon(8% 0,100% 0,100% 100%,0 100%);margin-left:-1px; }
.gbadge { font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--pu);background:rgba(167,139,250,.08);border:1px solid rgba(167,139,250,.18);padding:4px 10px;margin-bottom:26px;display:inline-block;border-radius:4px; }
.gtit { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:26px;text-transform:uppercase;margin-bottom:5px; }
.gsub { font-size:13px;color:var(--g);margin-bottom:24px;line-height:1.65; }
.gbl { width:100%;background:var(--pu);color:#fff;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;letter-spacing:.1em;text-transform:uppercase;border:none;padding:15px;cursor:pointer;border-radius:10px;transition:background var(--trans),transform var(--trans-spring),box-shadow var(--trans); }
.gbl:hover { background:#7c3aed;transform:translateY(-1px);box-shadow:0 4px 16px rgba(167,139,250,.35); }
.gbl:active { transform:translateY(0) scale(.98); }
.gerr { color:var(--r);font-size:12px;margin-top:10px;display:none;font-family:'Barlow Semi Condensed',sans-serif; }

/* ══ VIEW SELECTOR ══════════════════════════════════════════════ */
#view-sel { position:fixed;inset:0;background:rgba(0,0,0,.92);z-index:99998;display:flex;align-items:center;justify-content:center;padding:20px;backdrop-filter:blur(6px); }
#view-sel.hidden { display:none; }
.vs-box { width:100%;max-width:520px; }
.vs-logo { display:flex;align-items:center;margin-bottom:10px; }
.vs-lv { background:var(--surf2);color:var(--ow);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:32px;padding:4px 18px 4px 12px;clip-path:polygon(0 0,85% 0,100% 100%,0 100%);border:1px solid rgba(255,255,255,.1);border-right:none; }
.vs-lt { background:var(--y);color:#0A0A0A;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:22px;letter-spacing:.15em;padding:4px 16px 4px 18px;clip-path:polygon(8% 0,100% 0,100% 100%,0 100%);margin-left:-1px; }
.vs-badge { font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:var(--y);margin-bottom:26px;display:block;opacity:.7; }
.vs-title { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:22px;text-transform:uppercase;letter-spacing:.04em;color:var(--ow);margin-bottom:5px; }
.vs-sub { font-size:12px;color:var(--g);margin-bottom:24px;line-height:1.65; }

/* 4-stage selector grid */
.vs-stages { display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:20px; }
.vs-stage {
  border:1px solid rgba(255,255,255,.1);
  border-radius:10px;padding:16px 12px;
  cursor:pointer;transition:all var(--trans);text-align:center;
}
.vs-stage:hover { border-color:rgba(255,205,17,.4);transform:translateY(-2px); }
.vs-stage.sel { border-color:var(--y);background:rgba(255,205,17,.07);transform:translateY(-1px); }
.vs-stage-swatch { width:28px;height:28px;border-radius:50%;margin:0 auto 8px;border:2px solid rgba(255,255,255,.15); }
.vs-stage-name { font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--ow);margin-bottom:3px; }
.vs-stage-desc { font-size:10px;color:var(--g);line-height:1.4; }
.vs-stage.sel .vs-stage-name { color:var(--y); }

.vs-confirm { width:100%;background:var(--y);color:#0A0A0A;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;letter-spacing:.1em;text-transform:uppercase;border:none;padding:15px;cursor:pointer;border-radius:10px;transition:background var(--trans),transform var(--trans-spring),box-shadow var(--trans); }
.vs-confirm:hover { background:var(--yd);transform:translateY(-1px);box-shadow:0 4px 14px rgba(255,205,17,.25); }

/* ══ SCROLLBARS ════════════════════════════════════════════════ */
::-webkit-scrollbar { width:4px;height:4px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:transparent;border-radius:4px; }
*:hover::-webkit-scrollbar-thumb { background:var(--bd); }

/* ══ TUTORIAL ══════════════════════════════════════════════════ */
@keyframes tut-bounce{from{transform:translateY(0)}to{transform:translateY(-8px)}}
@keyframes tut-bounce-up{from{transform:translateY(0)}to{transform:translateY(8px)}}
@keyframes tut-bounce-h{from{transform:translateX(0)}to{transform:translateX(-8px)}}
@keyframes tut-bounce-h-rev{from{transform:translateX(0)}to{transform:translateX(8px)}}
@keyframes tut-pulse{0%,100%{box-shadow:0 0 0 3px rgba(255,205,17,.25),0 0 24px rgba(255,205,17,.12)}50%{box-shadow:0 0 0 5px rgba(255,205,17,.15),0 0 36px rgba(255,205,17,.2)}}
#tut-card { border-radius:12px;box-shadow:var(--shadow-lg),0 0 0 1px rgba(255,255,255,.04); }
#tut-card { background:var(--surf)!important;border-color:var(--bd)!important; }

/* ══ MOBILE NAV ════════════════════════════════════════════════ */
#mobile-nav { display:none;position:fixed;bottom:0;left:0;right:0;background:var(--surf);border-top:1px solid var(--bd);z-index:500;padding:0;height:56px;flex-shrink:0; }
#mobile-nav .mn-item { flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;cursor:pointer;padding:6px 4px;font-family:'Barlow Semi Condensed',sans-serif;font-size:9px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--g);transition:color var(--trans);border:none;background:transparent; }
#mobile-nav .mn-item.active { color:var(--y); }
#mobile-nav .mn-item .mn-icon { font-size:18px;line-height:1; }

/* ══ LIGHT STAGE ADJUSTMENTS ═══════════════════════════════════ */
body.stage-day .gbox, body.stage-dusk .gbox { box-shadow:0 8px 32px rgba(0,0,0,.1); }
body.stage-day #sidebar, body.stage-dusk #sidebar { box-shadow:1px 0 0 var(--bd); }
body.stage-day .wt:hover, body.stage-dusk .wt:hover { box-shadow:0 4px 16px rgba(0,0,0,.1); }

/* ══ RESPONSIVE ════════════════════════════════════════════════ */
@media(max-width:900px){
  main{padding:16px;gap:12px;}
  #sidebar{width:180px;}
  .ni{font-size:11px;padding:8px 10px;}
  .sr{gap:8px;}
  .sc{padding:12px 14px;}
  .wg{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));}
  .vs-stages{grid-template-columns:repeat(2,1fr);}
}
@media(max-width:700px){
  body{font-size:14px;}
  #topbar{flex-wrap:wrap;}
  #topbar-brand{display:none;}
  #sidebar{display:none;}
  #app-body{flex-direction:column;}
  main{padding:12px;gap:10px;}
  .gbox{padding:28px 20px;}
  .gtit{font-size:20px;}
  .gbl{padding:14px;}
  .ci-split{grid-template-columns:1fr;}
  .sr{grid-template-columns:1fr 1fr;}
  .sc{padding:10px 12px;}
  .mo{padding:0;align-items:flex-end;}
  .md{max-width:100%!important;width:100%;max-height:92vh;padding:20px 16px;border-radius:0;margin:0;border-top:2px solid var(--y);border-left:none;border-right:none;border-bottom:none;}
  .mdt{font-size:17px;}
  .ma{flex-direction:column;gap:8px;}
  .ma .btn{width:100%;justify-content:center;}
  .npg{gap:8px;}
  .npb{font-size:22px;padding:16px 10px;min-height:56px;}
  .tw{overflow-x:auto;-webkit-overflow-scrolling:touch;}
  .tw table{min-width:500px;}
  .vs-box{padding:0 4px;}
  .vs-stages{grid-template-columns:1fr 1fr;}
  .clerk-wrap{padding:12px;}
  .emp-wrap{padding:12px;}
  .fi{font-size:16px;padding:12px 14px;}
  .btn{font-size:12px;padding:8px 14px;}
  .bsm{font-size:11px;padding:6px 10px;}
  #portal-sep-bar{display:none;}
  .dbanner{padding:4px 12px;}
  #demo-time-banner{flex-direction:column;gap:4px;padding:6px 12px;}
  #vee-help{bottom:72px;right:16px;width:42px;height:42px;}
  #vee-help-panel{right:0;left:0;width:100%;bottom:76px;max-height:60vh;border-radius:0;}
  #vee-tip{display:none!important;}
  #mobile-nav{display:flex;}
  #app{padding-bottom:56px;}
}
@media(max-width:400px){
  .npb{font-size:20px;padding:14px 8px;}
  .md{padding:16px 12px;}
  .sc{padding:8px 10px;}
  main{padding:8px;gap:8px;}
}
@media(hover:none) and (pointer:coarse){
  .btn{min-height:44px;}
  .ni{min-height:44px;}
  .fi{min-height:48px;}
  .npb{min-height:56px;}
  .hbtn{min-height:52px;}
  .btn:hover{transform:none;filter:none;}
  .wt:hover{transform:none;box-shadow:var(--shadow);}
}
@media(min-width:701px) and (max-width:1024px){
  #sidebar{width:160px;}
  .ni{font-size:11px;padding:8px 10px;}
  .nic{display:none;}
  main{padding:16px;}
  .wg{grid-template-columns:repeat(auto-fill,minmax(180px,1fr));}
}


/* ════════════════════════════════════════════════════════════════
   VEE SIDEBAR FINAL — appended last, highest specificity wins.
   Expand 220px ↔ Collapse 60px. Uses body.sb-closed.
   ALL pointer-events guaranteed. Zero click blockers.
════════════════════════════════════════════════════════════════ */
:root { --sb-open:220px; --sb-shut:60px; --sb-t:0.22s cubic-bezier(0.4,0,0.2,1); }

/* Topbar brand */
#topbar-brand {
  width:var(--sb-open) !important; flex-shrink:0 !important;
  display:flex !important; align-items:center !important;
  padding:0 12px !important; gap:10px !important;
  border-right:1px solid var(--bd) !important; height:100% !important;
  overflow:hidden !important; box-sizing:border-box !important;
  transition:width var(--sb-t), padding var(--sb-t) !important;
}
body.sb-closed #topbar-brand {
  width:var(--sb-shut) !important; padding:0 !important;
  justify-content:center !important; gap:0 !important;
}
#sb-toggle {
  width:30px !important; height:30px !important; flex-shrink:0 !important;
  border:1px solid var(--bd) !important; background:var(--surf2) !important;
  color:var(--g) !important; border-radius:8px !important;
  cursor:pointer !important; display:flex !important;
  align-items:center !important; justify-content:center !important;
  pointer-events:auto !important;
  transition:background 0.15s, border-color 0.15s, color 0.15s !important;
}
#sb-toggle:hover { background:rgba(255,205,17,.1) !important; border-color:var(--y) !important; color:var(--y) !important; }
.tb-mark {
  width:32px !important; height:32px !important; flex-shrink:0 !important;
  background:var(--y) !important; border-radius:9px !important;
  display:flex !important; align-items:center !important; justify-content:center !important;
  font-family:'Barlow Condensed',sans-serif !important;
  font-weight:900 !important; font-size:16px !important; color:#0A0A0A !important;
  box-shadow:0 0 12px rgba(255,205,17,.25) !important;
}
.tb-wordmark {
  overflow:hidden !important; white-space:nowrap !important;
  transition:opacity var(--sb-t), max-width var(--sb-t) !important;
  max-width:150px !important; opacity:1 !important;
}
.tb-name {
  font-family:'Barlow Condensed',sans-serif !important; font-weight:900 !important;
  font-size:17px !important; text-transform:uppercase !important;
  letter-spacing:.06em !important; color:var(--ow) !important; line-height:1 !important;
}
.tb-sub {
  font-family:'Barlow Semi Condensed',sans-serif !important; font-size:9px !important;
  font-weight:600 !important; letter-spacing:.12em !important;
  text-transform:uppercase !important; color:var(--g) !important; margin-top:2px !important;
}
body.sb-closed .tb-wordmark { opacity:0 !important; max-width:0 !important; pointer-events:none !important; }

/* Sidebar container */
#sidebar {
  width:var(--sb-open) !important; min-width:var(--sb-open) !important;
  flex-shrink:0 !important; display:flex !important; flex-direction:column !important;
  background:var(--surf) !important; border-right:1px solid var(--bd) !important;
  overflow:hidden !important; z-index:5 !important;
  transition:width var(--sb-t), min-width var(--sb-t) !important;
}
body.sb-closed #sidebar { width:var(--sb-shut) !important; min-width:var(--sb-shut) !important; overflow:visible !important; }

/* Portal items */
#sidebar-portals { padding:10px 8px 8px !important; border-bottom:1px solid var(--bd) !important; flex-shrink:0 !important; }
body.sb-closed #sidebar-portals { padding:10px 5px 8px !important; overflow:visible !important; }
.sp-item {
  display:flex !important; align-items:center !important; gap:10px !important;
  padding:9px 10px !important; border-radius:10px !important; cursor:pointer !important;
  margin-bottom:2px !important; border:1px solid transparent !important;
  overflow:hidden !important; white-space:nowrap !important; position:relative !important;
  pointer-events:auto !important; color:var(--g) !important;
  font-family:'Inter','Barlow Semi Condensed',sans-serif !important;
  font-size:12px !important; font-weight:600 !important;
  transition:background 0.15s,color 0.15s,border-color 0.15s !important;
}
.sp-item:hover { background:var(--surf2) !important; color:var(--ow) !important; }
.sp-item.active { background:rgba(255,205,17,.09) !important; border-color:rgba(255,205,17,.2) !important; color:var(--y) !important; }
.sp-icon { font-size:16px !important; width:24px !important; text-align:center !important; flex-shrink:0 !important; pointer-events:none !important; }
.sp-label { font-weight:700 !important; font-size:12px !important; pointer-events:none !important; white-space:nowrap !important; overflow:hidden !important; transition:opacity var(--sb-t),max-width var(--sb-t) !important; max-width:150px !important; opacity:1 !important; }
.sp-sub { font-size:9px !important; color:var(--g) !important; pointer-events:none !important; white-space:nowrap !important; overflow:hidden !important; transition:opacity var(--sb-t),max-width var(--sb-t) !important; max-width:150px !important; opacity:1 !important; margin-top:2px !important; }
.sp-item.active .sp-sub { color:rgba(255,205,17,.55) !important; }
.sp-item>div { overflow:hidden !important; }
body.sb-closed .sp-item { padding:9px 5px !important; justify-content:center !important; gap:0 !important; }
body.sb-closed .sp-label, body.sb-closed .sp-sub, body.sb-closed .sp-item>div { opacity:0 !important; max-width:0 !important; pointer-events:none !important; }

/* Nav */
#sidebar-nav { flex:1 !important; padding:8px !important; overflow-y:auto !important; overflow-x:hidden !important; }
body.sb-closed #sidebar-nav { padding:8px 5px !important; overflow:visible !important; }
.ns {
  font-family:'Inter','Barlow Semi Condensed',sans-serif !important;
  font-size:9px !important; font-weight:700 !important; letter-spacing:.2em !important;
  text-transform:uppercase !important; color:var(--g) !important; opacity:.45 !important;
  padding:12px 10px 4px !important; white-space:nowrap !important; overflow:hidden !important;
  display:block !important; max-height:32px !important;
  transition:opacity var(--sb-t),max-height var(--sb-t),padding var(--sb-t) !important;
}
body.sb-closed .ns { opacity:0 !important; max-height:0 !important; padding:0 !important; }

/* ═══ THE .ni NAV ITEM — every rule here is intentional ═══ */
.ni {
  display:flex !important; align-items:center !important; gap:10px !important;
  padding:9px 10px !important; cursor:pointer !important;
  border-radius:10px !important; border:1px solid transparent !important;
  margin-bottom:1px !important; overflow:hidden !important;
  white-space:nowrap !important; position:relative !important;
  pointer-events:auto !important;   /* ← THE FIX. Never remove this. */
  color:var(--g) !important;
  font-family:'Inter','Barlow Semi Condensed',sans-serif !important;
  font-size:12px !important; font-weight:500 !important;
  transition:background 0.15s,color 0.15s,border-color 0.15s !important;
  user-select:none !important;
}
.ni:hover  { background:var(--surf2) !important; color:var(--ow) !important; }
.ni.active { background:rgba(255,205,17,.09) !important; border-color:rgba(255,205,17,.2) !important; color:var(--y) !important; font-weight:700 !important; }
.nic {
  font-size:16px !important; width:24px !important; text-align:center !important;
  flex-shrink:0 !important; pointer-events:none !important; line-height:1 !important;
}
.ni-label {
  pointer-events:none !important; overflow:hidden !important; white-space:nowrap !important;
  transition:opacity var(--sb-t),max-width var(--sb-t) !important;
  max-width:150px !important; opacity:1 !important;
}
/* Kill ALL old tooltip spans completely */
.ni-tooltip,.sp-tooltip { display:none !important; pointer-events:none !important; position:static !important; }

/* Collapsed nav */
body.sb-closed .ni { padding:9px 5px !important; justify-content:center !important; gap:0 !important; }
body.sb-closed .ni-label { opacity:0 !important; max-width:0 !important; }
body.sb-closed .nic { width:28px !important; font-size:17px !important; }

/* Hover tooltip in collapsed mode */
body.sb-closed .ni:hover::after,
body.sb-closed .sp-item:hover::after {
  content:attr(data-sb-label) !important;
  position:absolute !important; left:calc(100% + 8px) !important; top:50% !important;
  transform:translateY(-50%) !important;
  background:var(--surf) !important; border:1px solid var(--bd) !important;
  border-left:2px solid var(--y) !important; color:var(--ow) !important;
  font-family:'Inter',sans-serif !important; font-size:11px !important; font-weight:600 !important;
  padding:5px 10px !important; border-radius:8px !important;
  white-space:nowrap !important; pointer-events:none !important; z-index:99999 !important;
  box-shadow:0 4px 16px rgba(0,0,0,.3) !important;
}

/* Footer */
#sidebar-footer { border-top:1px solid var(--bd) !important; padding:10px 8px !important; flex-shrink:0 !important; }
body.sb-closed #sidebar-footer { padding:8px 5px !important; overflow:visible !important; }
.sf-user { display:flex !important; align-items:center !important; gap:10px !important; padding:8px 10px !important; border-radius:10px !important; cursor:pointer !important; overflow:hidden !important; position:relative !important; pointer-events:auto !important; transition:background 0.15s !important; }
.sf-user:hover { background:var(--surf2) !important; }
.sf-avatar { width:30px !important; height:30px !important; border-radius:50% !important; flex-shrink:0 !important; background:linear-gradient(135deg,var(--y),var(--yd)) !important; display:flex !important; align-items:center !important; justify-content:center !important; font-family:'Barlow Condensed',sans-serif !important; font-weight:900 !important; font-size:13px !important; color:#0A0A0A !important; }
.sf-name   { font-family:'Inter','Barlow Semi Condensed',sans-serif !important; font-size:12px !important; font-weight:600 !important; color:var(--ow) !important; line-height:1 !important; white-space:nowrap !important; pointer-events:none !important; transition:opacity var(--sb-t),max-width var(--sb-t) !important; max-width:140px !important; opacity:1 !important; }
.sf-email  { font-size:10px !important; color:var(--g) !important; margin-top:2px !important; white-space:nowrap !important; pointer-events:none !important; transition:opacity var(--sb-t),max-width var(--sb-t) !important; max-width:140px !important; opacity:1 !important; }
.sf-chevron { margin-left:auto !important; color:var(--g) !important; font-size:11px !important; flex-shrink:0 !important; }
body.sb-closed .sf-user { padding:8px 5px !important; justify-content:center !important; gap:0 !important; }
body.sb-closed .sf-name, body.sb-closed .sf-email, body.sb-closed .sf-chevron { opacity:0 !important; max-width:0 !important; pointer-events:none !important; }

@media(max-width:700px) { #sidebar { display:none !important; } #topbar-brand { display:none !important; } }


/* ══ SCROLL FIX ══════════════════════════════════════════════ */
html, body { height: 100%; overflow: hidden; }
#app { height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
#app-body { flex: 1; display: flex; overflow: hidden; min-height: 0; }
#sidebar { min-height: 0; overflow-y: auto; overflow-x: hidden; }
body.sb-closed #sidebar { overflow: visible; }
#content-area { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
.pview { display: none; flex: 1; overflow: hidden; min-height: 0; }
.pview.active { display: flex; flex: 1; overflow: hidden; min-height: 0; }
#pv-employer { flex-direction: column; flex: 1; overflow: hidden; min-height: 0; }
main { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 22px 24px; display: flex; flex-direction: column; gap: 16px; min-height: 0; }
#pv-manager { flex-direction: column; overflow-y: auto; flex: 1; min-height: 0; }
#pv-employee { flex-direction: column; overflow-y: auto; flex: 1; min-height: 0; }

/* ══ POINTER EVENTS FIX — no sticky buttons ══════════════════ */
.mo { pointer-events: none; }
.mo.open { pointer-events: auto; }
.panel::before, .sc::before, .wt::before, .hsc::before,
.btn::before, .btn::after, .gbox::before, .gbox::after,
.vs-stage::before { pointer-events: none !important; }
#tut-dim-top, #tut-dim-bottom, #tut-dim-left, #tut-dim-right { pointer-events: none; }
#tut-overlay.tut-active #tut-dim-top,
#tut-overlay.tut-active #tut-dim-bottom,
#tut-overlay.tut-active #tut-dim-left,
#tut-overlay.tut-active #tut-dim-right { pointer-events: auto; }
#topbar button, .topbar-icon-btn, #sb-toggle { pointer-events: auto !important; }
#vee-help, #vee-settings-btn, #vee-dark-btn { pointer-events: auto !important; }
#emp-corner-actions .emp-corner-btn { pointer-events: auto !important; }
.ni, .sp-item, .sf-user { pointer-events: auto !important; }
.nic, .ni-label, .ni-tooltip, .sp-tooltip { pointer-events: none !important; }

/* ══ WOW FACTOR — glow + glass ═══════════════════════════════ */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');
:root { --glow-y:rgba(255,205,17,.22); --glow-pu:rgba(167,139,250,.22); }
body { font-family: 'Inter','Barlow',sans-serif; -webkit-font-smoothing:antialiased; }
body.stage-night::before {
  background-image:
    radial-gradient(ellipse 60% 40% at 50% -5%,rgba(255,205,17,.06) 0%,transparent 60%),
    radial-gradient(ellipse 40% 30% at 100% 100%,rgba(167,139,250,.04) 0%,transparent 50%);
}
#topbar { backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px); }
body.stage-night #topbar { background:rgba(14,14,14,.96); border-bottom-color:rgba(255,255,255,.06); }
body.stage-dusk-dark #topbar { background:rgba(30,30,28,.96); }
body.stage-day #topbar, body.stage-dusk #topbar { background:rgba(255,255,255,.92); }
.tb-mark { box-shadow:0 0 14px rgba(255,205,17,.3),inset 0 1px 0 rgba(255,255,255,.25); }
.panel { border-radius:14px; position:relative; overflow:hidden; }
.panel::before { content:''; position:absolute; top:0; left:0; right:0; height:1px; background:linear-gradient(90deg,transparent,rgba(255,255,255,.1) 50%,transparent); pointer-events:none; }
body.stage-day .panel::before, body.stage-dusk .panel::before { background:linear-gradient(90deg,transparent,rgba(0,0,0,.04) 50%,transparent); }
.sc { border-radius:14px; position:relative; overflow:hidden; transition:transform .18s,box-shadow .18s; }
.sc::before { content:''; position:absolute; top:0; left:0; right:0; height:36px; background:linear-gradient(180deg,rgba(255,205,17,.06) 0%,transparent 100%); pointer-events:none; }
.sc:hover { transform:translateY(-2px); box-shadow:0 6px 20px rgba(0,0,0,.25),0 0 16px var(--glow-y); }
.wt { border-radius:14px; position:relative; overflow:hidden; }
.wt::before { content:''; position:absolute; top:0; left:0; right:0; height:1px; background:linear-gradient(90deg,transparent,rgba(255,255,255,.08) 50%,transparent); pointer-events:none; }
.wt:hover { transform:translateY(-2px); box-shadow:0 6px 20px rgba(0,0,0,.25),0 0 18px rgba(255,205,17,.08); }
.btn { border-radius:10px; font-family:'Inter','Barlow Condensed',sans-serif; font-size:11px; font-weight:700; letter-spacing:.04em; position:relative; overflow:hidden; }
.btn::before { content:''; position:absolute; top:0; left:0; right:0; height:1px; background:linear-gradient(90deg,transparent,rgba(255,255,255,.25) 50%,transparent); pointer-events:none; }
.by  { color:#0A0A0A !important; box-shadow:0 2px 8px rgba(255,205,17,.25); }
.by:hover  { box-shadow:0 4px 16px rgba(255,205,17,.4),0 0 24px rgba(255,205,17,.12); transform:translateY(-1px); }
.bpu:hover { box-shadow:0 4px 16px rgba(167,139,250,.4),0 0 20px rgba(167,139,250,.12); transform:translateY(-1px); }
.bred:hover { box-shadow:0 4px 14px rgba(244,67,54,.35); transform:translateY(-1px); }
.btn:active { transform:scale(.97) !important; filter:brightness(.95); }
.bout { border-radius:10px; }
.mo { backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px); }
.md { border-radius:18px; box-shadow:0 24px 60px rgba(0,0,0,.55),0 0 0 1px rgba(255,205,17,.08); position:relative; overflow:hidden; }
.md::before { content:''; position:absolute; top:0; left:0; right:0; height:1px; background:linear-gradient(90deg,transparent,rgba(255,255,255,.15) 50%,transparent); pointer-events:none; }
body.stage-night .md, body.stage-dusk-dark .md { background:rgba(18,18,16,.98); }
.gbox { border-radius:20px; position:relative; overflow:hidden; box-shadow:0 24px 60px rgba(0,0,0,.5),0 0 60px rgba(255,205,17,.04); }
.gbox::before { content:''; position:absolute; top:-60px; left:-60px; width:180px; height:180px; background:radial-gradient(circle,rgba(255,205,17,.08) 0%,transparent 65%); pointer-events:none; }
.gbox::after  { content:''; position:absolute; bottom:-60px; right:-60px; width:160px; height:160px; background:radial-gradient(circle,rgba(167,139,250,.06) 0%,transparent 65%); pointer-events:none; }
.hcircle { filter:drop-shadow(0 0 10px rgba(255,205,17,.28)); }
.hsc { border-radius:14px; position:relative; overflow:hidden; }
.hsc::before { content:''; position:absolute; top:-40px; right:-40px; width:160px; height:160px; background:radial-gradient(circle,rgba(255,205,17,.08) 0%,transparent 65%); pointer-events:none; }
.toast { border-radius:12px; backdrop-filter:blur(16px); box-shadow:0 8px 32px rgba(0,0,0,.4),0 0 0 1px rgba(255,255,255,.06); }
#vee-tip { border-radius:8px; border-left:2px solid var(--y); box-shadow:0 4px 16px rgba(0,0,0,.35),0 0 12px var(--glow-y); }
#vee-help { border-radius:10px; }
#vee-help:hover { transform:translateY(-2px); box-shadow:0 4px 16px rgba(0,0,0,.3),0 0 14px var(--glow-y); }
#vee-help-panel { border-radius:14px; box-shadow:0 12px 40px rgba(0,0,0,.5); }
.npb { border-radius:10px; box-shadow:inset 0 1px 0 rgba(255,255,255,.06),0 2px 4px rgba(0,0,0,.2); }
.npb:hover { box-shadow:0 0 0 1px var(--o),0 0 12px rgba(255,152,0,.2); transform:translateY(-1px); }
.npb:active { transform:scale(.93) !important; box-shadow:0 1px 2px rgba(0,0,0,.3) !important; }
::-webkit-scrollbar { width:4px; height:4px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:var(--bd); border-radius:4px; }
::-webkit-scrollbar-thumb:hover { background:rgba(255,205,17,.4); }
.pg.active { animation:pg-wow .18s ease both; }
@keyframes pg-wow { from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:translateY(0);} }
#susp-badge { animation:susp-pulse 2.2s ease-in-out infinite; }
@keyframes susp-pulse { 0%,100%{box-shadow:0 0 5px rgba(244,67,54,.4);}50%{box-shadow:0 0 10px rgba(244,67,54,.7);} }
.pg-title { font-family:'Inter',sans-serif; font-size:26px; font-weight:800; letter-spacing:-.02em; text-transform:none; }
.mdt { font-family:'Inter',sans-serif; font-weight:800; font-size:18px; }
.pt  { font-family:'Inter',sans-serif; font-weight:700; font-size:13px; letter-spacing:.04em; }
.scv { font-family:'Inter',sans-serif; font-weight:800; font-size:30px; letter-spacing:-.02em; }
.gtit { font-family:'Inter',sans-serif; font-weight:800; font-size:24px; text-transform:none; letter-spacing:-.01em; }
.gbl { border-radius:12px; font-family:'Inter',sans-serif; font-weight:700; font-size:14px; letter-spacing:.02em; text-transform:none; box-shadow:0 4px 16px var(--glow-pu); }
.gbl:hover { box-shadow:0 6px 24px rgba(167,139,250,.5),0 0 40px rgba(167,139,250,.12); }
body.stage-day .gbox, body.stage-dusk .gbox { background:rgba(255,255,255,.97); border:1px solid rgba(0,0,0,.08); border-top:1px solid rgba(255,205,17,.3); box-shadow:0 16px 50px rgba(0,0,0,.1); }
body.stage-day .panel, body.stage-dusk .panel { box-shadow:0 1px 3px rgba(0,0,0,.06),0 2px 8px rgba(0,0,0,.04); }
.fi { border-radius:10px; }
.fi:focus { border-color:var(--y) !important; box-shadow:0 0 0 3px rgba(255,205,17,.12),0 0 12px rgba(255,205,17,.06) !important; }
body.stage-day .fi, body.stage-dusk .fi { color-scheme:light; background:var(--surf2); }
.by:hover, .bpu:hover, .bred:hover, .bout:hover { filter:none; }


/* ══════════════════════════════════════════════════════════════
   MOBILE OPTIMISATION — iPhone 13 (390×844) + all touch
   Safe areas, bottom nav, modals, touch targets, typography
══════════════════════════════════════════════════════════════ */

/* ── Safe area support ── */
:root {
  --safe-top:    env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left:   env(safe-area-inset-left, 0px);
  --safe-right:  env(safe-area-inset-right, 0px);
  --mob-nav-h:   60px;
}

/* ── Mobile bottom nav ── */
#mobile-nav {
  display: none;
  position: fixed;
  bottom: 0; left: 0; right: 0;
  height: calc(var(--mob-nav-h) + var(--safe-bottom));
  padding-bottom: var(--safe-bottom);
  background: var(--surf);
  border-top: 1px solid var(--bd);
  z-index: 500;
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
body.stage-night #mobile-nav  { background: rgba(14,14,14,.97); }
body.stage-dusk-dark #mobile-nav { background: rgba(30,30,28,.97); }
body.stage-day #mobile-nav, body.stage-dusk #mobile-nav { background: rgba(255,255,255,.95); }

#mobile-nav .mn-item {
  flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 4px;
  cursor: pointer;
  padding: 8px 4px 4px;
  font-family: 'Inter','Barlow Semi Condensed',sans-serif;
  font-size: 9px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--g);
  transition: color 0.15s;
  border: none; background: transparent;
  position: relative;
  min-height: 44px;
  -webkit-tap-highlight-color: transparent;
}
#mobile-nav .mn-item::before {
  content: '';
  position: absolute;
  top: 0; left: 20%; right: 20%;
  height: 2px;
  background: var(--y);
  border-radius: 0 0 2px 2px;
  opacity: 0;
  transform: scaleX(0);
  transition: opacity 0.15s, transform 0.2s cubic-bezier(0.34,1.15,0.64,1);
}
#mobile-nav .mn-item.active { color: var(--y); }
#mobile-nav .mn-item.active::before { opacity: 1; transform: scaleX(1); }
#mobile-nav .mn-item .mn-icon {
  font-size: 20px; line-height: 1;
  transition: transform 0.15s cubic-bezier(0.34,1.15,0.64,1);
}
#mobile-nav .mn-item.active .mn-icon { transform: translateY(-1px) scale(1.1); }

/* ── Mobile more menu — full redesign ── */
#mobile-more-menu {
  display: none;
  position: fixed;
  bottom: calc(var(--mob-nav-h) + var(--safe-bottom));
  left: 0; right: 0;
  background: var(--surf) !important;
  border-top: 1px solid var(--bd);
  border-radius: 16px 16px 0 0;
  z-index: 499;
  padding: 8px 0 8px;
  box-shadow: 0 -8px 32px rgba(0,0,0,.3);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  max-height: 75vh;
  overflow-y: auto;
}
body.stage-night #mobile-more-menu { background: rgba(16,16,16,.98) !important; }
body.stage-dusk-dark #mobile-more-menu { background: rgba(28,28,26,.98) !important; }
body.stage-day #mobile-more-menu, body.stage-dusk #mobile-more-menu { background: rgba(255,255,255,.97) !important; }

/* Drag handle */
#mobile-more-menu::before {
  content: '';
  display: block;
  width: 36px; height: 4px;
  background: var(--bd);
  border-radius: 2px;
  margin: 0 auto 12px;
}

/* More menu section headers */
.mob-menu-section {
  font-family: 'Inter','Barlow Semi Condensed',sans-serif;
  font-size: 9px; font-weight: 700; letter-spacing: .18em;
  text-transform: uppercase; color: var(--g); opacity: .5;
  padding: 10px 20px 4px;
}

/* More menu rows */
#mobile-more-menu button {
  width: 100%; text-align: left;
  padding: 13px 20px !important;
  background: transparent !important;
  border: none !important;
  border-bottom: 1px solid rgba(255,255,255,.04) !important;
  color: var(--ow) !important;
  font-family: 'Inter','Barlow Semi Condensed',sans-serif !important;
  font-size: 14px !important; font-weight: 600 !important;
  cursor: pointer !important;
  display: flex !important; align-items: center !important; gap: 14px !important;
  transition: background 0.15s !important;
  min-height: 52px;
  -webkit-tap-highlight-color: transparent;
}
body.stage-day #mobile-more-menu button,
body.stage-dusk #mobile-more-menu button {
  border-bottom-color: rgba(0,0,0,.05) !important;
}
#mobile-more-menu button:hover,
#mobile-more-menu button:active { background: var(--surf2) !important; }
#mobile-more-menu button span { font-size: 20px; width: 28px; text-align: center; }

/* Portal switcher in more menu */
#mob-portal-row {
  display: flex; gap: 8px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--bd);
}
.mob-portal-btn {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 6px;
  background: var(--surf2);
  border: 1px solid var(--bd);
  border-radius: 10px;
  cursor: pointer;
  font-family: 'Inter',sans-serif;
  font-size: 10px; font-weight: 600; letter-spacing: .04em;
  color: var(--g);
  transition: all 0.15s;
  min-height: 52px;
  -webkit-tap-highlight-color: transparent;
}
.mob-portal-btn.active {
  background: rgba(255,205,17,.09);
  border-color: rgba(255,205,17,.25);
  color: var(--y);
}
.mob-portal-btn span { font-size: 22px; }

/* Stage row in more menu */
#mob-stage-row {
  display: flex; gap: 6px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--bd);
}
.mob-stage-btn {
  flex: 1;
  padding: 8px 4px;
  background: var(--surf2);
  border: 1px solid var(--bd);
  border-radius: 8px;
  cursor: pointer;
  font-family: 'Inter',sans-serif;
  font-size: 9px; font-weight: 700; letter-spacing: .06em;
  color: var(--g); text-align: center;
  transition: all 0.15s;
  -webkit-tap-highlight-color: transparent;
}
.mob-stage-btn.active {
  background: rgba(255,205,17,.09);
  border-color: rgba(255,205,17,.25);
  color: var(--y);
}

/* ══ MOBILE LAYOUT — iPhone 13 (≤700px) ══════════════════════ */
@media(max-width:700px){

  /* App padding for nav + safe area */
  #app { padding-bottom: calc(var(--mob-nav-h) + var(--safe-bottom)); }
  #mobile-nav { display: flex; }

  /* Topbar — account for notch */
  #topbar {
    padding-top: var(--safe-top);
    height: calc(56px + var(--safe-top));
  }

  /* Hide desktop sidebar completely */
  #sidebar { display: none !important; }
  #topbar-brand { display: none !important; }

  /* Gate/login — iPhone friendly */
  #gate { padding: 16px; align-items: flex-start; padding-top: calc(60px + var(--safe-top)); }
  .gbox { padding: 32px 24px 28px; border-radius: 16px; }
  .gtit { font-size: 22px; }
  .gsub { font-size: 13px; }
  .fl   { font-size: 10px; }
  .fi   { font-size: 16px !important; padding: 14px 16px; } /* 16px prevents iOS zoom */
  .gbl  { font-size: 15px; padding: 16px; min-height: 52px; }

  /* View selector */
  .vs-box { padding: 0; }
  .vs-stages { grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 16px; }
  .vs-stage { padding: 14px 10px; }
  .vs-confirm { font-size: 15px; padding: 16px; min-height: 52px; }

  /* Main content */
  main { padding: 12px 14px; gap: 10px; }

  /* Dashboard — full single column on mobile */
  #pg-dashboard {
    display: flex !important;
    flex-direction: column !important;
    grid-template-columns: unset !important;
  }

  /* Health score — compact */
  .hsc { padding: 16px 18px; gap: 16px; }
  .hcircle { width: 80px; height: 80px; }
  .hcircle svg { width: 80px; height: 80px; }

  /* Stat cards — 2×2 */
  .sr { grid-template-columns: 1fr 1fr; gap: 8px; }
  .sc { padding: 14px 14px; }
  .scv { font-size: 26px; }

  /* Panels */
  .panel { border-radius: 12px; }
  .ph { padding: 12px 14px; flex-wrap: wrap; gap: 6px; }
  .pt { font-size: 12px; }

  /* Worker grid — single column */
  .wg { grid-template-columns: 1fr; padding: 10px 12px; gap: 8px; }
  .wt { padding: 12px 14px; }

  /* Tables — horizontal scroll */
  .tw { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .tw table { min-width: 480px; }
  th { padding: 8px 10px; font-size: 9px; }
  td { padding: 8px 10px; font-size: 12px; }

  /* Page title */
  .pg-title { font-size: 20px; }
  .pg-sub   { font-size: 12px; }

  /* Modals — slide up from bottom */
  .mo { padding: 0; align-items: flex-end; }
  .md {
    max-width: 100% !important;
    width: 100%; margin: 0;
    max-height: 88vh;
    border-radius: 20px 20px 0 0 !important;
    padding: 24px 20px calc(20px + var(--safe-bottom));
    border-top: 2px solid var(--y) !important;
    border-left: none !important; border-right: none !important; border-bottom: none !important;
  }
  /* Modal drag handle */
  .md::after {
    content: '';
    position: absolute;
    top: 10px; left: 50%; transform: translateX(-50%);
    width: 36px; height: 4px;
    background: var(--bd);
    border-radius: 2px;
  }
  .mdt { font-size: 18px; }
  .ma  { flex-direction: column; gap: 8px; }
  .ma .btn { width: 100%; justify-content: center; min-height: 48px; }

  /* CI split — single col */
  .ci-split { grid-template-columns: 1fr; }

  /* Numpad — bigger tap targets */
  .npg { gap: 8px; }
  .npb { font-size: 22px; padding: 18px 10px; min-height: 60px; border-radius: 12px; }
  .code-input { font-size: 40px; letter-spacing: .2em; }

  /* Employee portal */
  #emp-form { grid-template-columns: 1fr !important; }
  #emp-code-wrap { grid-column: 1 !important; grid-row: auto !important; }
  #emp-code-val { font-size: 44px; }
  .emp-wrap { padding: 14px; max-width: 100%; }

  /* Scroll rows — bigger tap */
  .srow { padding: 14px 16px; }
  .mgr-worker-row { padding: 12px 14px; }

  /* Check-in tabs */
  #ci-tab-btn, #co-tab-btn { min-height: 48px; }

  /* Corner action buttons — shift above mobile nav */
  #emp-corner-actions { bottom: calc(var(--mob-nav-h) + var(--safe-bottom) + 12px); }

  /* Help button — above mobile nav */
  #vee-help { bottom: calc(var(--mob-nav-h) + var(--safe-bottom) + 12px); }
  #vee-help-panel { bottom: calc(var(--mob-nav-h) + var(--safe-bottom) + 56px); right: 0; left: 0; width: 100%; border-radius: 0; }

  /* Dismiss tooltip — reposition on mobile */
  .dismiss-tooltip { left: 0; transform: none; max-width: 100%; }

  /* Info box */
  .ib { font-size: 12px; padding: 10px 14px; }

  /* Page header */
  .pg-header { flex-direction: column; align-items: flex-start; gap: 8px; }
  #payroll-run-status { align-self: flex-start; }
}

/* ══ SMALL PHONE ≤390px (iPhone SE, older androids) ══════════ */
@media(max-width:390px){
  .npb   { font-size: 20px; padding: 16px 8px; }
  .md    { padding: 20px 16px calc(16px + var(--safe-bottom)); }
  .sc    { padding: 10px 12px; }
  main   { padding: 8px 10px; gap: 8px; }
  .scv   { font-size: 22px; }
  #emp-code-val { font-size: 38px; }
  .hcircle { width: 70px; height: 70px; }
  .hcircle svg { width: 70px; height: 70px; }
}

/* ══ TOUCH DEVICES (coarse pointer) ══════════════════════════ */
@media(hover:none) and (pointer:coarse){
  .btn { min-height: 44px; }
  .fi  { min-height: 48px; }
  .npb { min-height: 56px; }
  .hbtn { min-height: 52px; }
  .btn:hover { transform: none !important; filter: none !important; box-shadow: none !important; }
  .wt:hover  { transform: none !important; box-shadow: var(--shadow) !important; }
  .sc:hover  { transform: none !important; box-shadow: var(--shadow) !important; }
  .ni:hover  { transform: none !important; }
  -webkit-tap-highlight-color: transparent;
}

/* ══ TABLET 700–1024px ════════════════════════════════════════ */
@media(min-width:701px) and (max-width:1024px){
  main { padding: 16px; }
  .wg  { grid-template-columns: repeat(auto-fill,minmax(200px,1fr)); }
  .sr  { grid-template-columns: repeat(2,1fr); }
}


/* ══ TOPBAR — no search bar, right buttons fill space ════════ */
#topbar { justify-content: space-between; padding: 0 16px 0 0; }
#topbar-right {
  display: flex; align-items: center; gap: 8px;
  flex: 1;
  justify-content: flex-end;
  padding-right: 4px;
}
#topbar-search { display: none !important; }
#topbar-brand {
  flex-shrink: 0;
}
/* Stage button — slightly more breathing room */
#topbar-stage-btn {
  padding: 0 14px;
  font-size: 11px;
  letter-spacing: .07em;
}
/* User pill — clean */
#topbar-user {
  gap: 8px;
  padding: 6px 8px;
}


/* ══ MODAL SCROLL FIX — definitive, overrides all previous rules ══
   Root cause: overflow:hidden on .md was killing scroll inside modals.
   The wow shimmer ::before only needs position:relative, not overflow:hidden.
   The dismiss/close on backdrop-click still works via .mo click handler.
═══════════════════════════════════════════════════════════════════ */

/* Modal overlay — always scrollable, always covers screen */
.mo {
  position: fixed !important;
  inset: 0 !important;
  z-index: 1000 !important;
  display: none !important;
  align-items: flex-start !important;
  justify-content: center !important;
  padding: 24px !important;
  overflow-y: auto !important;          /* overlay scrolls if modal taller than screen */
  -webkit-overflow-scrolling: touch !important;
  background: rgba(0,0,0,.78) !important;
  backdrop-filter: blur(8px) !important;
  -webkit-backdrop-filter: blur(8px) !important;
  pointer-events: none !important;
}
.mo.open {
  display: flex !important;
  pointer-events: auto !important;
}

/* Modal card — scrolls its OWN content, never clips it */
.md {
  background: var(--surf) !important;
  border: 1px solid var(--bd) !important;
  border-top: 2px solid var(--y) !important;
  border-radius: 16px !important;
  width: 100% !important;
  max-width: 540px !important;
  padding: 28px 30px !important;
  margin: auto !important;
  /* CRITICAL: overflow-y auto, NOT hidden */
  overflow-y: auto !important;
  overflow-x: hidden !important;
  -webkit-overflow-scrolling: touch !important;
  /* No max-height here — let the overlay handle the viewport constraint */
  max-height: calc(100vh - 48px) !important;
  box-shadow: 0 24px 60px rgba(0,0,0,.55), 0 0 0 1px rgba(255,205,17,.08) !important;
  position: relative !important;       /* for ::before shimmer — but NO overflow:hidden */
  flex-shrink: 0 !important;
}

/* Shimmer top edge — still works without overflow:hidden on parent */
.md::before {
  content: '' !important;
  position: absolute !important;
  top: 0 !important; left: 0 !important; right: 0 !important;
  height: 1px !important;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.15) 50%, transparent) !important;
  pointer-events: none !important;
  z-index: 1 !important;
}

/* Night/dusk-dark modal background */
body.stage-night .md,
body.stage-dusk-dark .md { background: rgba(18,18,16,.99) !important; }

/* Light stage modal */
body.stage-day .md,
body.stage-dusk .md { background: var(--surf) !important; }

/* Mobile — bottom sheet with proper scroll */
@media(max-width:700px){
  .mo {
    padding: 0 !important;
    align-items: flex-end !important;
    overflow-y: hidden !important;      /* overlay doesn't scroll on mobile */
  }
  .md {
    max-width: 100% !important;
    width: 100% !important;
    margin: 0 !important;
    max-height: 88vh !important;
    border-radius: 20px 20px 0 0 !important;
    padding: 28px 20px calc(24px + var(--safe-bottom)) !important;
    border-top: 2px solid var(--y) !important;
    border-left: none !important;
    border-right: none !important;
    border-bottom: none !important;
    overflow-y: auto !important;         /* card itself scrolls on mobile */
    -webkit-overflow-scrolling: touch !important;
    flex-shrink: 0 !important;
  }
  /* Drag handle */
  .md::after {
    content: '' !important;
    position: absolute !important;
    top: 10px !important; left: 50% !important;
    transform: translateX(-50%) !important;
    width: 36px !important; height: 4px !important;
    background: var(--bd) !important;
    border-radius: 2px !important;
    pointer-events: none !important;
  }
  .mdt { margin-top: 8px !important; }
  .ma { flex-direction: column !important; gap: 8px !important; }
  .ma .btn { width: 100% !important; justify-content: center !important; min-height: 48px !important; }
}


/* ══ CLERK / MANAGER / SK PORTAL SCROLL FIX ══════════════════ */
#pv-clerk, #pv-manager, #pv-storekeeper {
  flex-direction: column;
  overflow-y: auto !important;
  overflow-x: hidden;
  min-height: 0 !important;
  flex: 1;
}
#pv-clerk .emp-wrap,
#pv-manager .emp-wrap,
#pv-storekeeper .emp-wrap {
  min-height: 0;
  padding-bottom: 32px;
}


/* ══ ALERTS HUB TABS ══════════════════════════════════════════ */
.alerts-tab { outline: none; }
.alerts-tab:hover { color: var(--ow) !important; }
.alerts-panel { border-radius: 0 0 14px 14px !important; }
@media(max-width:700px){
  .alerts-tab { padding: 10px 10px !important; font-size: 10px !important; }
}

</style>
</head>
<body>

<!-- VIEW SELECTOR — first visit only -->
<div id="view-sel" class="hidden">
  <div class="vs-box">
    <div class="vs-logo"><div class="vs-lv">VEE</div><div class="vs-lt">INDUSTRIAL</div></div>
    <span class="vs-badge">🏗 Built for earthmoving · construction · mining · trades</span>
    <div class="vs-title">Choose your brightness</div>
    <div class="vs-sub">Pick how bright or dark the interface feels. Switch anytime from the top bar.</div>
    <div class="vs-stages">
      <div class="vs-stage" onclick="selStage('day',this)" data-stage="day" data-vee-tip="Day|Full brightness. Clean white surfaces. Perfect for bright environments.">
        <div class="vs-stage-swatch" style="background:#F7F7F5;border-color:rgba(0,0,0,.15);"></div>
        <div class="vs-stage-name">Day</div>
        <div class="vs-stage-desc">Full brightness</div>
      </div>
      <div class="vs-stage" onclick="selStage('dusk',this)" data-stage="dusk" data-vee-tip="Dusk|Warm mid-light. Easier on the eyes than full bright.">
        <div class="vs-stage-swatch" style="background:#EEEDE7;border-color:rgba(0,0,0,.12);"></div>
        <div class="vs-stage-name">Dusk</div>
        <div class="vs-stage-desc">Warm mid-light</div>
      </div>
      <div class="vs-stage" onclick="selStage('dusk-dark',this)" data-stage="dusk-dark" data-vee-tip="Dusk Dark|Comfortable dark. Not too light, not too dark.">
        <div class="vs-stage-swatch" style="background:#1E1E1C;border-color:rgba(255,255,255,.1);"></div>
        <div class="vs-stage-name">Dusk Dark</div>
        <div class="vs-stage-desc">Cool mid-dark</div>
      </div>
      <div class="vs-stage sel" onclick="selStage('night',this)" data-stage="night" data-vee-tip="Night|Deep dark. High contrast. Built for the site.">
        <div class="vs-stage-swatch" style="background:#0A0A0A;border-color:rgba(255,255,255,.08);"></div>
        <div class="vs-stage-name">Night</div>
        <div class="vs-stage-desc">Deep dark</div>
      </div>
    </div>
    <button class="vs-confirm" onclick="confirmView()">Enter Vee Industrial →</button>
  </div>
</div>
<!-- TOOLTIP -->
<div id="vee-tip"><div id="vee-tip-title"></div><div id="vee-tip-body"></div></div>

<!-- HELP PANEL -->
<div id="vee-help-panel">
  <div class="help-ph" id="help-title">Help</div>
  <div style="padding:10px 14px;border-bottom:1px solid var(--bd);">
    <button onclick="startTutorial();toggleHelp()" id="vee-tutorial-btn" style="width:100%;background:rgba(255,205,17,.08);border:1px solid rgba(255,205,17,.25);color:var(--y);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;letter-spacing:.08em;text-transform:uppercase;padding:10px 16px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;transition:all .2s;" onmouseover="this.style.background='rgba(255,205,17,.15)'" onmouseout="this.style.background='rgba(255,205,17,.08)'">🎓 Start Guided Tutorial</button>
  </div>
  <div id="help-body"></div>
</div>

<!-- FIXED BUTTONS -->
<button id="vee-help" onclick="toggleHelp()" data-vee-tip="Help &amp; Tutorial|Quick-reference cheat sheet plus guided tour.">?</button>
<button id="vee-settings-btn" onclick="openViewSel()" data-vee-tip="Appearance|Change your view mode (Base/Modern/Prof) and light/dark mode.">⚙</button>
<button id="vee-dark-btn" onclick="toggleDark()" data-vee-tip="Light / Dark|Switch between dark and light colour mode.">🌑</button>

<!-- MOBILE BOTTOM NAV -->
<div id="mobile-nav">
  <button class="mn-item active" onclick="mobileNav('dashboard',this)"><span class="mn-icon">📊</span>Dash</button>
  <button class="mn-item" onclick="mobileNav('checkin',this)"><span class="mn-icon">⚡</span>Check-In</button>
  <button class="mn-item" onclick="mobileNav('workers',this)"><span class="mn-icon">👷</span>Workers</button>
  <button class="mn-item" onclick="mobileNav('export',this)"><span class="mn-icon">📥</span>Export</button>
  <button class="mn-item" id="mn-more" onclick="toggleMobileMore()"><span class="mn-icon">☰</span>More</button>
</div>

<!-- MOBILE MORE MENU -->
<div id="mobile-more-menu">
  <!-- Portal switcher -->
  <div class="mob-menu-section">Switch Portal</div>
  <div id="mob-portal-row">
    <button class="mob-portal-btn active" id="mob-p-employer" onclick="switchPortal('employer',document.querySelector('.sp-item[data-sb-label=\'Office\']'));closeMobileMore();"><span>🏢</span>Office</button>
    <button class="mob-portal-btn" id="mob-p-manager"  onclick="switchPortal('manager',document.querySelector('.sp-item[data-sb-label=\'Manager\']'));closeMobileMore();"><span>🔧</span>Manager</button>
    <button class="mob-portal-btn" id="mob-p-storekeeper" onclick="switchPortal('storekeeper',document.querySelector('.sp-item[data-sb-label=\'StoreKeeper\']'));closeMobileMore();"><span>📦</span>Store</button>
    <button class="mob-portal-btn" id="mob-p-clerk" onclick="switchPortal('clerk',document.querySelector('.sp-item[data-sb-label=\'Clerk\']'));closeMobileMore();"><span>🔐</span>Clerk</button>
    <button class="mob-portal-btn" id="mob-p-employee" onclick="switchPortal('employee',document.querySelector('.sp-item[data-sb-label=\'Worker\']'));closeMobileMore();"><span>👷</span>Worker</button>
  </div>
  <!-- Stage switcher -->
  <div class="mob-menu-section">Brightness</div>
  <div id="mob-stage-row">
    <button class="mob-stage-btn" onclick="applyStageAndSave('day');closeMobileMore()">☀️ Day</button>
    <button class="mob-stage-btn" onclick="applyStageAndSave('dusk');closeMobileMore()">🌤 Dusk</button>
    <button class="mob-stage-btn" onclick="applyStageAndSave('dusk-dark');closeMobileMore()">🌙 Dusk Dark</button>
    <button class="mob-stage-btn" onclick="applyStageAndSave('night');closeMobileMore()">🌑 Night</button>
  </div>
  <!-- More pages -->
  <div class="mob-menu-section">Pages</div>
  <button onclick="mobileNav('inventory',null);closeMobileMore()"><span>📦</span>Inventory</button>
  <button onclick="mobileNav('sites',null);closeMobileMore()"><span>📍</span>Sites</button>
  <button onclick="mobileNav('calendar',null);closeMobileMore()"><span>📅</span>Leave Calendar</button>
  <button onclick="mobileNav('disputes',null);closeMobileMore()"><span>📝</span>Dispute Log</button>
  <button onclick="mobileNav('suspicious',null);closeMobileMore()"><span>🚨</span>Suspicious</button>
  <button onclick="mobileNav('demo',null);closeMobileMore()" style="color:var(--pu)!important;"><span>🎯</span>Demo Controls</button>
  <!-- Tutorial -->
  <div class="mob-menu-section">Help</div>
  <button onclick="startTutorial();closeMobileMore()" style="color:var(--y)!important;"><span>🎓</span>Start Tutorial</button>
  <button onclick="toggleHelp();closeMobileMore()"><span>❓</span>Help Panel</button>
</div>

<!-- TUTORIAL OVERLAY -->
<div id="tut-overlay" style="display:none;position:fixed;inset:0;z-index:99990;pointer-events:none;">
  <!-- Dim layer (4 rects around the highlight) -->
  <div id="tut-dim-top"    style="position:absolute;left:0;right:0;top:0;background:rgba(0,0,0,.82);pointer-events:auto;"></div>
  <div id="tut-dim-bottom" style="position:absolute;left:0;right:0;bottom:0;background:rgba(0,0,0,.82);pointer-events:auto;"></div>
  <div id="tut-dim-left"   style="position:absolute;top:0;bottom:0;left:0;background:rgba(0,0,0,.82);pointer-events:auto;"></div>
  <div id="tut-dim-right"  style="position:absolute;top:0;bottom:0;right:0;background:rgba(0,0,0,.82);pointer-events:auto;"></div>
  <div id="tut-ring" style="position:absolute;top:-9999px;left:-9999px;display:none;pointer-events:none;"></div>
  <div id="tut-arrow" style="position:absolute;top:-9999px;left:-9999px;display:none;font-size:24px;color:var(--y);line-height:1;pointer-events:none;"></div>
  <!-- Tooltip card -->
  <div id="tut-card" style="position:absolute;top:-9999px;left:-9999px;max-width:340px;min-width:260px;background:var(--surf);border:1px solid var(--bd);border-top:3px solid var(--y);padding:18px 20px;box-shadow:0 8px 40px rgba(0,0,0,.7);pointer-events:auto;z-index:99999;">
    <!-- Role segment banner -->
    <div id="tut-segment" style="display:none;font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;padding:4px 10px;margin-bottom:10px;border:1px solid;"></div>
    <div style="display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:10px;">
      <div>
        <div id="tut-category" style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--y);margin-bottom:3px;"></div>
        <div id="tut-title" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;letter-spacing:.04em;color:var(--ow);"></div>
      </div>
      <div id="tut-step-counter" style="font-family:'Barlow Condensed',sans-serif;font-size:12px;font-weight:700;color:var(--g);white-space:nowrap;flex-shrink:0;margin-top:3px;"></div>
    </div>
    <div id="tut-what" style="margin-bottom:8px;">
      <div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--g);margin-bottom:3px;">What it is</div>
      <div id="tut-what-text" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--ow);line-height:1.5;"></div>
    </div>
    <div id="tut-does" style="margin-bottom:8px;">
      <div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--g);margin-bottom:3px;">What it does</div>
      <div id="tut-does-text" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--ow);line-height:1.5;"></div>
    </div>
    <div id="tut-how" style="margin-bottom:8px;">
      <div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--g);margin-bottom:3px;">How to use it</div>
      <div id="tut-how-text" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--y);line-height:1.5;"></div>
    </div>
    <!-- See More -->
    <button id="tut-more-btn" style="display:none;width:100%;background:transparent;border:none;border-top:1px solid var(--bd);color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:8px 0 4px;cursor:pointer;text-align:left;">▼ See More</button>
    <div id="tut-more-content" style="display:none;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);line-height:1.5;padding-top:6px;margin-bottom:8px;"></div>
    <div style="display:flex;gap:8px;align-items:center;margin-top:10px;">
      <button onclick="tutSkip()" style="background:transparent;border:1px solid var(--bd);color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:7px 14px;cursor:pointer;flex-shrink:0;">Exit Tour</button>
      <div style="flex:1;"></div>
      <button id="tut-prev-btn" onclick="tutPrev()" style="background:transparent;border:1px solid var(--bd);color:var(--ow);font-family:'Barlow Condensed',sans-serif;font-size:13px;font-weight:900;letter-spacing:.06em;text-transform:uppercase;padding:8px 16px;cursor:pointer;">← Back</button>
      <button id="tut-next-btn" onclick="tutNext()" style="background:var(--y);border:none;color:var(--bg);font-family:'Barlow Condensed',sans-serif;font-size:13px;font-weight:900;letter-spacing:.06em;text-transform:uppercase;padding:8px 20px;cursor:pointer;min-width:90px;"></button>
    </div>
    <!-- Progress dots -->
    <div id="tut-dots" style="display:flex;gap:4px;justify-content:center;margin-top:12px;flex-wrap:wrap;"></div>
  </div>
</div>

<!-- PASSWORD GATE -->
<div id="gate">
  <div class="gbox">
    <div class="glogo"><div class="glv">VEE</div><div class="glt">INDUSTRIAL</div></div>
    <div class="gbadge">🏗 Industrial Demo — Earthmoving · Construction · Trades</div>
    <div class="gtit">Try Vee Live</div>
    <div class="gsub">Workforce management for earthmoving, construction &amp; mining. <strong style="color:var(--y)">V0.1 Demo</strong> — fully interactive, no data saved. Enter the password to begin.</div>
    <label class="fl">Demo Password</label>
    <input class="fi" type="password" id="gpw" placeholder="••••••••" autocomplete="off"/>
    <button class="gbl" onclick="unlock()">Enter Demo →</button>
    <div class="gerr" id="gerr">Incorrect password. The demo password is <strong>veedemo</strong>. If the button still doesn't respond, <a href="#" onclick="localStorage.clear();location.reload();return false;" style="color:var(--y);text-decoration:underline;">click here to reset the session</a>.</div>
    <a href="index.html" style="display:block;text-align:center;margin-top:16px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;text-decoration:none;">← Back to Vee</a>
  </div>
</div>

<!-- APP -->
<div id="app">

  <!-- TOP BAR -->
  <div id="topbar">
    <div id="topbar-brand">
      <button id="sb-toggle" onclick="toggleSidebar()" title="Toggle sidebar" aria-label="Toggle sidebar">
        <svg width="15" height="12" viewBox="0 0 15 12" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round">
          <line x1="0.5" y1="1" x2="14.5" y2="1"/>
          <line x1="0.5" y1="6" x2="14.5" y2="6"/>
          <line x1="0.5" y1="11" x2="14.5" y2="11"/>
        </svg>
      </button>
      <div class="tb-mark">V</div>
      <div class="tb-wordmark">
        <div class="tb-name">Vee</div>
        <div class="tb-sub">Industrial</div>
      </div>
    </div>
    <div id="topbar-right">
      <button id="topbar-stage-btn" onclick="cycleStage()" data-vee-tip="Brightness|Cycle between Day, Dusk, Dusk Dark, and Night modes.">
        <span id="topbar-stage-icon">🌙</span>
        <span id="topbar-stage-label">Night</span>
      </button>
      <button class="topbar-icon-btn" onclick="openViewSel()" data-vee-tip="Appearance|Change your display settings.">⚙</button>
      <div id="topbar-user" data-vee-tip="Demo Mode|All data is fake and in-memory only.">
        <div class="tu-avatar">V</div>
        <div>
          <div class="tu-name">Vee Demo</div>
          <div class="tu-role" id="worker-count-banner">0 workers</div>
        </div>
      </div>
    </div>
  </div>

  <!-- DEMO BANNER -->
  <div class="dbanner">
    <div class="dbanner-l">🏗 Demo — all data in-memory only</div>
    <div class="dbanner-r"><span id="entry-count-banner">0</span> entries today</div>
  </div>

  <!-- DEMO TIME BANNER -->
  <div id="demo-time-banner" style="display:none;align-items:center;justify-content:space-between;flex-shrink:0;">
    <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--pu);">🕐 Demo Time Override Active — <span id="demo-time-banner-val"></span></span>
    <button onclick="clearDemoTime()" style="background:transparent;border:1px solid rgba(167,139,250,.4);color:var(--pu);font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;padding:3px 10px;cursor:pointer;border-radius:6px;">Reset to Real Time</button>
  </div>

  <!-- PORTAL INFO BAR -->
  <div id="portal-sep-bar">
    🏢 <strong style="color:var(--y)">Office</strong> uses employer credentials &nbsp;·&nbsp; 🔧 <strong style="color:var(--pu)">Manager</strong> activates via PIN &nbsp;·&nbsp; 👷 <strong style="color:var(--ow)">Worker</strong> uses employee login &nbsp;·&nbsp; 🔐 <strong style="color:var(--o)">Clerk</strong> unlocks inside Worker tab
  </div>

  <!-- APP BODY: sidebar + content -->
  <div id="app-body">

    <!-- SIDEBAR -->
    <div id="sidebar">

      <!-- Portal switcher -->
      <div id="sidebar-portals">
        <div class="sp-item active" data-sb-label="Office" onclick="switchPortal('employer',this)" data-vee-tip="Office Portal|Full employer dashboard — workers, payroll, check-ins, reports, settings.">
          <span class="sp-icon">🏢</span>
          <div>
            <div class="sp-label">Office / Employer</div>
            <div class="sp-sub">Full dashboard access</div>
          </div>
        </div>
        <div class="sp-item" data-sb-label="Manager" onclick="switchPortal('manager',this)" data-vee-tip="Manager Portal|Site-scoped dashboard. Check in workers, excuse, dispute, dismiss flags for your site.">
          <span class="sp-icon">🔧</span>
          <div>
            <div class="sp-label">Manager</div>
            <div class="sp-sub">Site oversight · PIN required</div>
          </div>
        </div>
        <div class="sp-item" data-sb-label="StoreKeeper" onclick="switchPortal('storekeeper',this)" data-vee-tip="StoreKeeper Portal|Site inventory, tool checkout/return, stock tracking. PIN required.">
          <span class="sp-icon">📦</span>
          <div>
            <div class="sp-label">StoreKeeper</div>
            <div class="sp-sub">Inventory · PIN required</div>
          </div>
        </div>
        <div class="sp-item" data-sb-label="Clerk" onclick="switchPortal('clerk',this)" data-vee-tip="Clerk Portal|Site gate — check workers in and out. PIN required.">
          <span class="sp-icon">🔐</span>
          <div>
            <div class="sp-label">Site Clerk</div>
            <div class="sp-sub">Gate check-in · PIN required</div>
          </div>
        </div>
        <div class="sp-item" data-sb-label="Worker" onclick="switchPortal('employee',this)" data-vee-tip="Worker Portal|Daily check-in code, status, hours history. Clerk mode available.">
          <span class="sp-icon">👷</span>
          <div>
            <div class="sp-label">Worker / Employee</div>
            <div class="sp-sub">Log hours · clerk if permitted</div>
          </div>
        </div>
      </div>

      <!-- Employer nav (shown when employer portal active) -->
      <div id="sidebar-nav">
        <div class="ns">Overview</div>
        <div class="ni active" data-sb-label="Dashboard" onclick="showPg('dashboard',this)" data-vee-tip="Dashboard|Health score, today's entries, stats, and site breakdown. Your daily command centre."><span class="nic">📊</span><span class="ni-label"> Dashboard</span></div>
        <div class="ni" data-sb-label="Check-In" onclick="showPg('checkin',this)" data-vee-tip="Live Check-In|Generate worker codes and process check-ins in real time. Simulates the full gate flow."><span class="nic">⚡</span><span class="ni-label"> Live Check-In</span></div>
        <div class="ns">Workers</div>
        <div class="ni" data-sb-label="Workers" onclick="showPg('workers',this)" data-vee-tip="Workers|Manage your workforce. Set pay types, shift rules, geo-fence, and clerk access per worker."><span class="nic">👷</span><span class="ni-label"> Workers</span></div>
        <div class="ni" data-sb-label="Sites" onclick="showPg('sites',this)" data-vee-tip="Sites|Add job sites. Workers check in against a site so you can track hours per project."><span class="nic">📍</span><span class="ni-label"> Sites</span></div>
        <div class="ni" data-sb-label="Disputes" onclick="showPg('disputes',this)" data-vee-tip="Dispute Log|Timestamped record of payroll disputes, warnings, and incidents. Legally defensible evidence."><span class="nic">📝</span><span class="ni-label"> Dispute Log</span></div>
        <div class="ns">Payroll</div>
        <div class="ni" data-sb-label="Export" onclick="showPg('export',this)" data-vee-tip="Payroll Export|Download Excel or PDF payroll. Test workers are automatically excluded."><span class="nic">📥</span><span class="ni-label"> Export</span></div>
        <div class="ni" data-sb-label="Leave" onclick="showPg('calendar',this)" data-vee-tip="Leave Calendar|Visual timeline of all excused days across all workers for the current month."><span class="nic">📅</span><span class="ni-label"> Leave Calendar</span></div>
        <div class="ns">Inventory</div>
        <div class="ni" data-sb-label="Inventory" onclick="showPg('inventory',this)" data-vee-tip="Inventory|All tools, equipment and consumables. Manage stock across all sites."><span class="nic">📦</span><span class="ni-label"> Inventory</span></div>
        <div class="ns">Security</div>
        <div class="ni" onclick="showPg('suspicious',this)" data-vee-tip="Suspicious Activity|Flagged check-in events." data-sb-label="Suspicious" style="position:relative;"><span class="nic">🚨</span><span class="ni-label">Suspicious</span><span id="susp-badge" style="display:none;position:absolute;top:3px;right:3px;background:var(--r);color:#fff;font-size:8px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:700;padding:1px 5px;border-radius:20px;min-width:16px;text-align:center;"></span></div>
        <div class="ns">Inventory</div>
        <div class="ni" data-sb-label="Inventory" onclick="showPg('inventory',this)" data-vee-tip="Inventory|Manage all site inventory, tools and equipment."><span class="nic">📦</span><span class="ni-label"> Inventory</span></div>
        <div class="ns">Demo</div>
        <div class="ni" data-sb-label="Demo" style="color:var(--pu);" onclick="showPg('demo',this)"><span class="nic">🎯</span><span class="ni-label"> Demo Controls</span></div>
      </div>

      <!-- Footer user strip -->
      <div id="sidebar-footer">
        <div class="sf-user" data-vee-tip="Demo User|This is a demo instance. No data is saved.">
          <div class="sf-avatar">V</div>
          <div style="flex:1;min-width:0;">
            <div class="sf-name">Vee Demo</div>
            <div class="sf-email"><a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="1175747c7e516774743f787f756462656378707d">[email&#160;protected]</a></div>
          </div>
          <div class="sf-chevron">⌃</div>
        </div>
      </div>

    </div><!-- /sidebar -->

    <!-- CONTENT AREA -->
    <div id="content-area">

<div class="pview active" id="pv-employer">
    <main>

      <!-- DASHBOARD -->
      <div class="pg active" id="pg-dashboard">
        <div class="pg-header">
          <div>
            <div class="pg-title">Dashboard</div>
            <div class="pg-sub">Your daily workforce command centre.</div>
          </div>
          <button class="btn by bsm" onclick="openEOD()" style="flex-shrink:0;gap:6px;border-radius:8px;padding:9px 16px;" data-vee-tip="End of Day Report|Full snapshot of today — attendance, hours, flags.">
            📋 End of Day Report
          </button>
        </div>
        <div class="hsc">
          <div class="hcircle">
            <svg width="100" height="100" viewBox="0 0 100 100">
              <circle cx="50" cy="50" r="42" fill="none" stroke="#2A2A2A" stroke-width="7"/>
              <circle cx="50" cy="50" r="42" fill="none" stroke="#FFCD11" stroke-width="7" stroke-dasharray="264" stroke-dashoffset="264" id="harc" stroke-linecap="round" style="transition:stroke-dashoffset 1s ease,stroke 1s ease"/>
            </svg>
            <div class="hnum"><div class="hn" id="hscore" style="color:var(--y)">—</div><div class="hl2">/ 10</div></div>
          </div>
          <div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;margin-bottom:4px;">Payroll Health Score</div>
            <div style="font-size:12px;color:var(--g)" id="hsdesc">Add workers and log hours to see your score.</div>
            <div class="hbr" id="hbr"></div>
          </div>
        </div>
        <div class="sr">
          <div class="sc"><div class="scl">Workers</div><div class="scv" id="st0">0</div><div class="scs">on the books</div></div>
          <div class="sc"><div class="scl">Logged Today</div><div class="scv" id="st1">0</div><div class="scs">submitted</div></div>
          <div class="sc"><div class="scl">Not Logged</div><div class="scv" id="st2" style="color:var(--r)">0</div><div class="scs">no entry yet</div></div>
          <div class="sc" style="border-left-color:var(--pu)"><div class="scl">Check-Ins</div><div class="scv" id="st3" style="color:var(--pu)">0</div><div class="scs">via clerk today</div></div>
        </div>

        <!-- WORKER HEALTH ALERTS -->
        <div id="worker-alerts-panel" style="display:none;">
          <div style="background:rgba(244,67,54,.06);border:1px solid rgba(244,67,54,.25);border-left:3px solid var(--r);padding:0;">
            <div style="display:flex;align-items:center;justify-content:space-between;padding:10px 16px;cursor:pointer;" onclick="toggleAlertPanel()">
              <div style="display:flex;align-items:center;gap:10px;">
                <span style="font-size:16px;">⚠</span>
                <div>
                  <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;text-transform:uppercase;letter-spacing:.04em;color:var(--r);">Worker Reliability Alerts</div>
                  <div id="alert-sub" style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;"></div>
                </div>
              </div>
              <div style="display:flex;align-items:center;gap:8px;">
                <button class="btn bsm" onclick="event.stopPropagation();openWorkerAlertAction()" style="background:var(--r);border-color:var(--r);color:#fff;font-size:11px;">Take Action</button>
                <span id="alert-chevron" style="color:var(--r);font-size:12px;transition:transform .2s;">▼</span>
              </div>
            </div>
            <div id="alert-body" style="display:none;border-top:1px solid rgba(244,67,54,.2);">
              <div id="alert-list" style="padding:12px 16px;display:flex;flex-direction:column;gap:6px;"></div>
            </div>
          </div>
        </div>
        <div class="panel">
          <div class="ph"><div class="pt">Today's Entries</div></div>
          <div class="tw"><table>
            <thead><tr><th>Worker</th><th>Reliability</th><th>Pay Type</th><th>Hours</th><th>Est. Pay</th><th>Site</th><th>Status</th></tr></thead>
            <tbody id="etb"><tr><td colspan="7" style="padding:20px;text-align:center;color:var(--g);font-size:13px">No entries yet. Add workers and log hours.</td></tr></tbody>
          </table></div>
        </div>
        <div class="panel">
          <div class="ph"><div class="pt">Hours by Site</div></div>
          <div id="sitebd" style="padding:16px"><div style="color:var(--g);font-size:13px;text-align:center;padding:10px">No site data yet.</div></div>
        </div>
      </div>

      <!-- LIVE CHECK-IN -->
      <div class="pg" id="pg-checkin">
        <div class="ib"><strong>Live Check-In / Checkout</strong> — Select a worker to generate their codes. The gate clerk uses the check-in or checkout numpad on the right. Both flows support time-window bypassing with full suspicious activity logging.</div>

        <div class="ci-split">
          <!-- EMPLOYER CODE PANEL -->
          <div class="panel">
            <div class="ph">
              <div class="pt">👤 Code Generator</div>
              <div style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.08em;text-transform:uppercase;background:rgba(255,205,17,.1);border:1px solid rgba(255,205,17,.2);color:var(--y);padding:3px 10px;">Employer</div>
            </div>
            <div style="padding:18px;display:flex;flex-direction:column;gap:12px;">
              <div>
                <label class="fl">Select Worker</label>
                <select class="fi" id="ci-sel" onchange="genCode()" style="margin-bottom:0;">
                  <option value="">Choose a worker...</option>
                </select>
              </div>
              <div id="ci-display" style="display:none;">
                <!-- Check-in code -->
                <div style="background:var(--bg);border:2px solid rgba(76,175,80,.3);padding:14px;text-align:center;margin-bottom:8px;">
                  <div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--gr);margin-bottom:4px;">Check-In Code — <span id="ci-wname"></span></div>
                  <div id="ci-code" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:48px;letter-spacing:.2em;color:var(--gr);line-height:1;"></div>
                  <div style="font-size:10px;color:var(--g);margin-top:4px;">Show to clerk for entry</div>
                </div>
                <!-- Checkout code -->
                <div style="background:var(--bg);border:2px solid rgba(255,152,0,.3);padding:14px;text-align:center;margin-bottom:8px;">
                  <div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--o);margin-bottom:4px;">Checkout Code — <span id="co-wname"></span></div>
                  <div id="co-code" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:48px;letter-spacing:.2em;color:var(--o);line-height:1;"></div>
                  <div style="font-size:10px;color:var(--g);margin-top:4px;">Show to clerk when leaving</div>
                </div>
              </div>
              <div id="ci-winfo" style="display:none;background:rgba(255,205,17,.04);border:1px solid rgba(255,205,17,.1);padding:10px 14px;">
                <div style="display:flex;gap:16px;flex-wrap:wrap;">
                  <div><div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:2px;">Pay Type</div><div id="ci-pt" style="font-size:13px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;"></div></div>
                  <div><div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:2px;">Reliability</div><div id="ci-rel" style="font-size:13px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;"></div></div>
                  <div><div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:2px;">Check-In Window</div><div id="ci-window" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--ow);"></div></div>
                  <div><div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:2px;">Checkout Window</div><div id="co-window" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--ow);"></div></div>
                </div>
                <!-- Bypass checkbox -->
                <div style="margin-top:10px;display:flex;flex-direction:column;gap:6px;">
                  <label style="display:flex;align-items:center;gap:8px;cursor:pointer;padding:6px 8px;background:rgba(244,67,54,.05);border:1px solid rgba(244,67,54,.2);">
                    <input type="checkbox" id="ci-bypass" style="accent-color:var(--r);width:14px;height:14px;" onchange="updBypassState()"/>
                    <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:600;color:var(--ow);">⚠ Bypass check-in time window</span>
                    <span id="ci-bypass-label" style="font-size:10px;color:var(--g);margin-left:auto;font-family:'Barlow Semi Condensed',sans-serif;"></span>
                  </label>
                  <label style="display:flex;align-items:center;gap:8px;cursor:pointer;padding:6px 8px;background:rgba(255,152,0,.05);border:1px solid rgba(255,152,0,.2);">
                    <input type="checkbox" id="co-bypass" style="accent-color:var(--o);width:14px;height:14px;" onchange="updBypassState()"/>
                    <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:600;color:var(--ow);">⚠ Bypass checkout time window</span>
                    <span id="co-bypass-label" style="font-size:10px;color:var(--g);margin-left:auto;font-family:'Barlow Semi Condensed',sans-serif;"></span>
                  </label>
                </div>
              </div>
            </div>
          </div>

          <!-- CLERK ENTRY PANEL — tabbed check-in / checkout -->
          <div class="panel">
            <div class="ph" style="padding:0;">
              <div style="display:flex;width:100%;border-bottom:1px solid var(--bd);">
                <button id="ci-tab-btn" onclick="switchCITab('checkin')" style="flex:1;padding:12px;background:var(--gr);color:#fff;border:none;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;letter-spacing:.08em;text-transform:uppercase;cursor:pointer;transition:all .2s;">✓ CHECK IN</button>
                <button id="co-tab-btn" onclick="switchCITab('checkout')" style="flex:1;padding:12px;background:var(--surf2);color:var(--g);border:none;border-left:1px solid var(--bd);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;letter-spacing:.08em;text-transform:uppercase;cursor:pointer;transition:all .2s;">← CHECK OUT</button>
              </div>
            </div>

            <!-- CHECK IN TAB -->
            <div id="ci-tab" style="padding:18px;display:flex;flex-direction:column;gap:12px;">
              <div>
                <label class="fl">Enter check-in code</label>
                <div style="display:flex;gap:8px;">
                  <input type="text" class="fi" id="ci-inp" maxlength="6" placeholder="000000" inputmode="numeric" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:30px;letter-spacing:.2em;text-align:center;margin-bottom:0;flex:1;" oninput="this.value=this.value.replace(/\D/g,'')"/>
                  <button class="btn bo" onclick="ciCheck()" style="font-size:18px;padding:0 18px;background:var(--gr);border-color:var(--gr);">✓</button>
                </div>
              </div>
              <div id="ci-res" style="display:none;padding:16px;text-align:center;border:2px solid transparent;">
                <div id="ci-ric" style="font-size:40px;line-height:1;margin-bottom:6px;"></div>
                <div id="ci-rn" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:24px;margin-bottom:3px;"></div>
                <div id="ci-rm" style="font-size:12px;color:var(--g);margin-bottom:10px;"></div>
                <div id="ci-rt" class="crtag"></div>
                <button class="btn bout bsm" onclick="ciReset()" style="display:block;width:100%;justify-content:center;margin-top:12px;">→ Next Worker</button>
              </div>
              <div class="npg">
                <button class="npb" onclick="npd('1')">1</button><button class="npb" onclick="npd('2')">2</button><button class="npb" onclick="npd('3')">3</button>
                <button class="npb" onclick="npd('4')">4</button><button class="npb" onclick="npd('5')">5</button><button class="npb" onclick="npd('6')">6</button>
                <button class="npb" onclick="npd('7')">7</button><button class="npb" onclick="npd('8')">8</button><button class="npb" onclick="npd('9')">9</button>
                <button class="npb" style="opacity:0;cursor:default;"></button><button class="npb" onclick="npd('0')">0</button><button class="npb" style="color:var(--g);" onclick="npd('⌫')">⌫</button>
              </div>
            </div>

            <!-- CHECK OUT TAB -->
            <div id="co-tab" style="display:none;padding:18px;flex-direction:column;gap:12px;">
              <div>
                <label class="fl">Enter checkout code</label>
                <div style="display:flex;gap:8px;">
                  <input type="text" class="fi" id="co-inp" maxlength="6" placeholder="000000" inputmode="numeric" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:30px;letter-spacing:.2em;text-align:center;margin-bottom:0;flex:1;" oninput="this.value=this.value.replace(/\D/g,'')"/>
                  <button class="btn bout" onclick="coCheck()" style="font-size:18px;padding:0 18px;border-color:var(--o);color:var(--o);">←</button>
                </div>
              </div>
              <div id="co-res" style="display:none;padding:16px;text-align:center;border:2px solid transparent;">
                <div id="co-ric" style="font-size:40px;line-height:1;margin-bottom:6px;"></div>
                <div id="co-rn" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:24px;margin-bottom:3px;"></div>
                <div id="co-rm" style="font-size:12px;color:var(--g);margin-bottom:10px;"></div>
                <div id="co-rt" class="crtag"></div>
                <button class="btn bout bsm" onclick="coReset()" style="display:block;width:100%;justify-content:center;margin-top:12px;">→ Next Worker</button>
              </div>
              <div class="npg">
                <button class="npb" onclick="cod('1')">1</button><button class="npb" onclick="cod('2')">2</button><button class="npb" onclick="cod('3')">3</button>
                <button class="npb" onclick="cod('4')">4</button><button class="npb" onclick="cod('5')">5</button><button class="npb" onclick="cod('6')">6</button>
                <button class="npb" onclick="cod('7')">7</button><button class="npb" onclick="cod('8')">8</button><button class="npb" onclick="cod('9')">9</button>
                <button class="npb" style="opacity:0;cursor:default;"></button><button class="npb" onclick="cod('0')">0</button><button class="npb" style="color:var(--g);" onclick="cod('⌫')">⌫</button>
              </div>
            </div>
          </div>
        </div>

        <!-- MANDATORY BYPASS ACKNOWLEDGEMENT MODAL (inline) -->
        <div id="ci-mandatory-modal" style="display:none;background:rgba(244,67,54,.08);border:2px solid rgba(244,67,54,.4);padding:16px 18px;margin-top:8px;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:16px;color:var(--r);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px;">⚠ Mandatory Rule Active</div>
          <div id="ci-mandatory-msg" style="font-size:12px;color:var(--ow);margin-bottom:14px;line-height:1.6;font-family:'Barlow Semi Condensed',sans-serif;"></div>
          <div style="display:flex;gap:8px;">
            <button class="btn bout bsm" onclick="dismissMandatoryModal()" style="border-color:var(--g);color:var(--g);">Cancel</button>
            <button class="btn bsm" onclick="proceedMandatoryBypass()" style="background:var(--r);border-color:var(--r);color:#fff;">I Acknowledge — Proceed Anyway</button>
          </div>
        </div>

        <!-- GLOBAL TIME WINDOW SETTINGS -->
        <div class="panel">
          <div class="ph">
            <div class="pt">⏰ Site-Wide Time Window</div>
            <div id="tw-status" style="font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;"></div>
          </div>
          <div style="padding:14px 18px;display:flex;align-items:flex-end;gap:16px;flex-wrap:wrap;">
            <div style="font-size:12px;color:var(--g);flex-basis:100%;">Codes outside this window are flagged or blocked. Individual worker windows set in Edit Worker override this for that worker.</div>
            <div><label class="fl" style="margin-bottom:4px;">Check-In Opens</label><input type="time" class="fi" id="tw-start" value="05:00" style="width:130px;margin-bottom:0;" onchange="saveTimeWindow()"/></div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;color:var(--g);padding-bottom:6px;">→</div>
            <div><label class="fl" style="margin-bottom:4px;">Check-In Closes</label><input type="time" class="fi" id="tw-end" value="10:00" style="width:130px;margin-bottom:0;" onchange="saveTimeWindow()"/></div>
          </div>
        </div>

        <!-- LOGS -->
        <div class="panel">
          <div class="ph">
            <div class="pt">Today's Activity Log</div>
            <span id="ci-log-cnt" style="font-size:12px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;">0 entries</span>
          </div>
          <div class="tw"><table>
            <thead><tr><th>Worker</th><th>Type</th><th>Time</th><th>Code</th><th>By</th><th>Status</th></tr></thead>
            <tbody id="ci-log-tb"><tr><td colspan="6" style="padding:16px;text-align:center;color:var(--g);font-size:13px">No activity yet.</td></tr></tbody>
          </table></div>
        </div>
      </div>

      <!-- WORKERS -->
      <div class="pg" id="pg-workers">
        <div class="ib"><strong>Workers</strong> — add workers manually or use Demo Controls to generate test workers instantly. Reliability is based on logged entries.</div>
        <div class="panel">
          <div class="ph">
            <div class="pt">Official Workers</div>
            <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;position:relative;">
              <!-- ACTIONS DROPDOWN -->
              <div style="position:relative;" id="worker-actions-wrap">
                <button class="btn bout bsm" onclick="toggleWorkerActions()" id="worker-actions-btn" style="display:flex;align-items:center;gap:6px;">
                  ⚡ Actions <span id="worker-actions-chevron" style="font-size:10px;transition:transform .2s;">▼</span>
                </button>
                <div id="worker-actions-menu" style="display:none;position:absolute;top:calc(100% + 6px);right:0;min-width:210px;background:var(--surf);border:1px solid var(--bd);border-top:3px solid var(--y);z-index:800;box-shadow:0 8px 32px rgba(0,0,0,.5);">
                  <button onclick="openExcuseModal();closeWorkerActions()" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>📋</span>Excuse Workers</button>
                  <button onclick="openMakeupModal();closeWorkerActions()" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>🔄</span>Compensation Days</button>
                  <button onclick="openOvertimeBonusModal();closeWorkerActions()" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>💰</span>OT / Bonus Days</button>
                  <div style="padding:10px 16px;border-bottom:1px solid var(--bd);">
                    <div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--g);margin-bottom:6px;">Geo-Fence (Global)</div>
                    <div id="global-geo-btn" onclick="toggleGlobalGeo()" style="display:flex;align-items:center;gap:8px;cursor:pointer;background:rgba(244,67,54,.08);border:1px solid rgba(244,67,54,.3);padding:6px 10px;transition:all .2s;">
                      <span style="font-size:13px;">🛰</span>
                      <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;" id="global-geo-label">Geo-Fence: OFF</span>
                      <span style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;" id="global-geo-sub">default for all</span>
                    </div>
                  </div>
                  <button onclick="openAddWorker();closeWorkerActions()" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;color:var(--y);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,205,17,.05)'" onmouseout="this.style.background='transparent'"><span>+</span>Add Worker</button>
                </div>
              </div>
              <button class="btn by bsm" onclick="openAddWorker()">+ Add Worker</button>
            </div>
          </div>
          <div class="wg" id="wgrid"><div style="padding:30px;text-align:center;color:var(--g);font-size:13px">No workers yet. Add your first worker above.</div></div>
        </div>
      </div>

      <!-- SITES -->
      <div class="pg" id="pg-sites">
        <div class="ib"><strong>Job Sites</strong> — workers pick from this list when logging hours. Hours per site are tracked for job costing.</div>
        <div class="panel">
          <div class="ph"><div class="pt">Sites &amp; Jobs</div><button class="btn by bsm" onclick="openAddSite()">+ Add Site</button></div>
          <div id="slist" style="padding:16px;display:flex;flex-direction:column;gap:8px;"><div style="color:var(--g);font-size:13px;text-align:center;padding:16px">No sites yet.</div></div>
        </div>
      </div>

      <!-- DISPUTES -->
      <div class="pg" id="pg-disputes">
        <div class="ib"><strong>Dispute Log</strong> — timestamped record of any payroll issue, warning, or attendance problem. Legally defensible evidence.</div>
        <div class="panel">
          <div class="ph"><div class="pt">Dispute &amp; Incident Log</div><button class="btn by bsm" onclick="openAddDispute()">+ Add Entry</button></div>
          <div id="dlist" style="padding:16px;"><div style="color:var(--g);font-size:13px;text-align:center;padding:16px">No disputes logged.</div></div>
        </div>
      </div>

      <!-- EXPORT -->
      <div class="pg" id="pg-export">

        <!-- QUICK EXPORT — today only -->
        <div class="panel">
          <div class="ph">
            <div>
              <div class="pt">Payroll Summary</div>
              <div style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;margin-top:2px;">Today's hours · real workers only</div>
            </div>
            <div style="display:flex;gap:8px;flex-wrap:wrap;">
              <button class="btn by bsm" onclick="exportXl()" data-vee-tip="Download Excel|Exports today's payroll for all real workers as a formatted .xlsx file.">⬇ Excel</button>
              <button class="btn bout bsm" onclick="exportPdf()" data-vee-tip="Print PDF|Opens a print-ready payroll summary for today in a new tab.">⬇ PDF</button>
            </div>
          </div>
          <div id="exprev" style="padding:0 0 4px;"></div>
          <div style="padding:12px 18px;border-top:1px solid var(--bd);font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;">⚠ Test workers are excluded. Only workers with logged hours appear in the download.</div>
        </div>

        <!-- FULL PAYSHEET — filtered -->
        <div class="panel" style="border-top:3px solid var(--y);">
          <div class="ph">
            <div>
              <div class="pt" style="color:var(--y);">🖨 Full Paysheet Export</div>
              <div style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;margin-top:2px;">Filter by date range, site, pay type — include or exclude absent workers</div>
            </div>
            <button class="btn by bsm" onclick="openPaysheetFilter()" data-vee-tip="Paysheet Filter|Set date range, site, pay type, and whether to include workers with no hours.">Configure & Export →</button>
          </div>
          <div style="padding:16px 18px;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;">
            <div style="background:var(--surf2);padding:12px 14px;">
              <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:4px;">Date Range</div>
              <div id="ps-range-display" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;">This week</div>
            </div>
            <div style="background:var(--surf2);padding:12px 14px;">
              <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:4px;">Site Filter</div>
              <div id="ps-site-display" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;">All Sites</div>
            </div>
            <div style="background:var(--surf2);padding:12px 14px;">
              <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:4px;">Pay Type</div>
              <div id="ps-type-display" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;">All Types</div>
            </div>
            <div style="background:var(--surf2);padding:12px 14px;">
              <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;margin-bottom:4px;">Absent Workers</div>
              <div id="ps-absent-display" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;">Excluded</div>
            </div>
          </div>
        </div>

      </div>

      <!-- LEAVE CALENDAR -->
      <div class="pg" id="pg-calendar">
        <div class="ib"><strong>Leave Calendar</strong> — Visual overview of all excused absences across your workforce. Navigate months to see the full picture.</div>
        <div class="panel">
          <div class="ph">
            <div>
              <div class="pt">📅 Leave Calendar</div>
              <div style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;margin-top:2px;" id="cal-month-label"></div>
            </div>
            <div style="display:flex;gap:8px;align-items:center;">
              <button class="btn bout bsm" onclick="calNav(-1)">← Prev</button>
              <button class="btn bout bsm" onclick="calNav(0)">Today</button>
              <button class="btn bout bsm" onclick="calNav(1)">Next →</button>
            </div>
          </div>
          <!-- LEGEND -->
          <div style="padding:10px 18px;border-bottom:1px solid var(--bd);display:flex;gap:16px;flex-wrap:wrap;">
            <div style="display:flex;align-items:center;gap:6px;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);">
              <div style="width:12px;height:12px;background:rgba(244,67,54,.3);border:1px solid rgba(244,67,54,.5);"></div> Unpaid
            </div>
            <div style="display:flex;align-items:center;gap:6px;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);">
              <div style="width:12px;height:12px;background:rgba(76,175,80,.25);border:1px solid rgba(76,175,80,.4);"></div> Paid Leave
            </div>
            <div style="display:flex;align-items:center;gap:6px;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);">
              <div style="width:12px;height:12px;background:rgba(255,205,17,.2);border:1px solid rgba(255,205,17,.4);"></div> Half Day
            </div>
            <div style="display:flex;align-items:center;gap:6px;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);">
              <div style="width:12px;height:12px;background:rgba(244,67,54,.08);border:1px dashed var(--r);"></div> Reliability Affected
            </div>
            <div style="display:flex;align-items:center;gap:6px;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);">
              <div style="width:12px;height:12px;background:rgba(167,139,250,.15);border:1px solid rgba(167,139,250,.4);"></div> Pay Override Active
            </div>
          </div>
          <!-- CALENDAR GRID -->
          <div style="overflow-x:auto;">
            <div id="cal-grid" style="padding:16px;min-width:600px;"></div>
          </div>
        </div>
        <!-- ENTITLEMENT SUMMARY -->
        <div class="panel">
          <div class="ph"><div class="pt">Absence Entitlement Status</div></div>
          <div id="cal-entitlement-list" style="padding:16px;display:flex;flex-direction:column;gap:8px;"></div>
        </div>
      </div>

      <!-- SUSPICIOUS -->
      <div class="pg" id="pg-suspicious">
        <div class="pg-header">
          <div>
            <div class="pg-title">Alerts &amp; Activity</div>
            <div class="pg-sub">Suspicious flags · Disputes · Inventory alerts — all in one place.</div>
          </div>
        </div>

        <!-- Tab bar -->
        <div style="display:flex;gap:0;border-bottom:2px solid var(--bd);margin-bottom:0;">
          <button class="alerts-tab active" id="atab-susp"   onclick="switchAlertsTab('susp')"   style="padding:10px 18px;font-family:'Inter','Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:700;letter-spacing:.04em;background:transparent;border:none;cursor:pointer;color:var(--ow);border-bottom:2px solid var(--y);margin-bottom:-2px;transition:color .15s;">🚨 Suspicious <span id="atab-susp-cnt" style="background:var(--r);color:#fff;font-size:9px;padding:1px 6px;border-radius:20px;margin-left:4px;display:none;"></span></button>
          <button class="alerts-tab" id="atab-disputes" onclick="switchAlertsTab('disputes')" style="padding:10px 18px;font-family:'Inter','Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:700;letter-spacing:.04em;background:transparent;border:none;cursor:pointer;color:var(--g);border-bottom:2px solid transparent;margin-bottom:-2px;transition:color .15s;">📝 Disputes <span id="atab-disputes-cnt" style="background:var(--o);color:#fff;font-size:9px;padding:1px 6px;border-radius:20px;margin-left:4px;display:none;"></span></button>
          <button class="alerts-tab" id="atab-inv"      onclick="switchAlertsTab('inv')"      style="padding:10px 18px;font-family:'Inter','Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:700;letter-spacing:.04em;background:transparent;border:none;cursor:pointer;color:var(--g);border-bottom:2px solid transparent;margin-bottom:-2px;transition:color .15s;">📦 Inventory Alerts <span id="atab-inv-cnt" style="background:var(--o);color:#fff;font-size:9px;padding:1px 6px;border-radius:20px;margin-left:4px;display:none;"></span></button>
        </div>

        <!-- ── Suspicious panel ── -->
        <div id="alerts-panel-susp" class="alerts-panel panel" style="border-radius:0 0 14px 14px;">
          <div class="ph" style="justify-content:space-between;">
            <div class="pt">🚨 Suspicious Attempts</div>
            <div style="display:flex;gap:8px;align-items:center;">
              <span id="susp-archive-toggle-btn" onclick="toggleSuspArchive()" style="font-size:11px;color:var(--g);cursor:pointer;font-family:'Inter',sans-serif;padding:4px 10px;border:1px solid var(--bd);border-radius:6px;">Show Archived ▼</span>
              <button class="btn bred bsm" onclick="clearSusp()" style="border-radius:6px;">Clear All</button>
            </div>
          </div>
          <div id="susplist"><div style="padding:30px;text-align:center;color:var(--g);font-size:13px">No suspicious activity. System is clean.</div></div>
        </div>

        <!-- ── Disputes panel ── -->
        <div id="alerts-panel-disputes" class="alerts-panel panel" style="display:none;border-radius:0 0 14px 14px;">
          <div class="ph">
            <div class="pt">📝 Disputes &amp; Warnings</div>
            <button class="btn by bsm" onclick="cm('mdisp')" style="border-radius:6px;gap:6px;">+ Log Entry</button>
          </div>
          <div id="dlist-alerts" style=""></div>
        </div>

        <!-- ── Inventory Alerts panel ── -->
        <div id="alerts-panel-inv" class="alerts-panel panel" style="display:none;border-radius:0 0 14px 14px;">
          <div class="ph">
            <div class="pt">📦 Inventory Alerts</div>
            <span style="font-size:11px;color:var(--g);font-family:'Inter',sans-serif;">Low stock · Overdue returns · Damaged items</span>
          </div>
          <div id="inv-alerts-list" style="padding:0;"></div>
        </div>
      </div>


      <!-- INVENTORY MANAGEMENT PAGE -->
      <div class="pg" id="pg-inventory">
        <div class="pg-header">
          <div>
            <div class="pg-title">📦 Inventory</div>
            <div class="pg-sub">All tools, equipment and consumables across your sites.</div>
          </div>
          <div style="display:flex;gap:8px;">
            <button class="btn by bsm" onclick="openSkReceiveEmployer()" style="border-radius:8px;gap:6px;">+ Add Item</button>
          </div>
        </div>

        <!-- Inventory stats -->
        <div class="sr" style="grid-template-columns:repeat(4,1fr);">
          <div class="sc" style="border-top-color:var(--y);"><div class="scl">Total Items</div><div class="scv" id="emp-inv-st0" style="color:var(--y);">0</div><div class="scs">all sites</div></div>
          <div class="sc" style="border-top-color:var(--o);"><div class="scl">Checked Out</div><div class="scv" id="emp-inv-st1" style="color:var(--o);">0</div><div class="scs">currently issued</div></div>
          <div class="sc" style="border-top-color:var(--r);"><div class="scl">Low Stock</div><div class="scv" id="emp-inv-st2" style="color:var(--r);">0</div><div class="scs">below minimum</div></div>
          <div class="sc" style="border-top-color:var(--r);"><div class="scl">Overdue</div><div class="scv" id="emp-inv-st3" style="color:var(--r);">0</div><div class="scs">past due date</div></div>
        </div>

        <!-- Filter bar -->
        <div class="panel">
          <div style="padding:12px 16px;display:flex;gap:10px;align-items:center;flex-wrap:wrap;">
            <select class="fi" id="emp-inv-filter-site" onchange="renderEmpInventory()" style="margin:0;padding:6px 10px;font-size:12px;border-radius:8px;width:auto;">
              <option value="">All Sites</option>
            </select>
            <select class="fi" id="emp-inv-filter-type" onchange="renderEmpInventory()" style="margin:0;padding:6px 10px;font-size:12px;border-radius:8px;width:auto;">
              <option value="">All Types</option>
              <option value="tool">Tools</option>
              <option value="equipment">Equipment</option>
              <option value="consumable">Consumables</option>
            </select>
            <select class="fi" id="emp-inv-filter-status" onchange="renderEmpInventory()" style="margin:0;padding:6px 10px;font-size:12px;border-radius:8px;width:auto;">
              <option value="">All Status</option>
              <option value="available">Available</option>
              <option value="checked-out">Checked Out</option>
              <option value="low-stock">Low Stock</option>
              <option value="needs-repair">Needs Repair</option>
            </select>
          </div>
          <div class="tw">
            <table>
              <thead><tr>
                <th>Name</th><th>Type</th><th>Site</th><th>Qty</th><th>Status</th><th>Condition</th><th>Checked Out To</th><th></th>
              </tr></thead>
              <tbody id="emp-inv-list"></tbody>
            </table>
          </div>
          <div id="emp-inv-empty" style="padding:24px;text-align:center;color:var(--g);font-size:13px;">No inventory items yet. Add items using the + Add Item button above, or have a StoreKeeper receive stock.</div>
        </div>

        <!-- Recent transactions -->
        <div class="panel">
          <div class="ph"><div class="pt">📜 Recent Inventory Activity</div></div>
          <div id="emp-inv-txn" style="padding:0;"></div>
          <div id="emp-inv-txn-empty" style="padding:16px 20px;color:var(--g);font-size:12px;">No transactions yet.</div>
        </div>
      </div>

      <!-- DEMO CONTROLS -->
      <div class="pg" id="pg-demo">
        <div style="background:rgba(167,139,250,.08);border:1px solid rgba(167,139,250,.25);border-left:3px solid var(--pu);padding:18px 22px;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;text-transform:uppercase;color:var(--pu);margin-bottom:3px;">🎯 Demo Controls</div>
          <div style="font-size:13px;color:var(--g);">Generate test data instantly. Everything here stays in-memory — nothing goes to any real database.</div>
        </div>
        <div class="panel"><div class="ph"><div class="pt" style="color:var(--pu)">Step 1 — Test Workers</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:12px;">
            <div style="font-size:13px;color:var(--g);">Generates workers pre-filled with realistic pay types. You can customise names before saving.</div>
            <div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;">
              <select class="fi" id="dwc" style="width:80px;margin:0;"><option value="3">3</option><option value="5" selected>5</option><option value="8">8</option></select>
              <button class="btn bpu" onclick="demoWorkers()">⚡ Generate Test Workers</button>
            </div>
          </div>
        </div>
        <div class="panel"><div class="ph"><div class="pt" style="color:var(--pu)">Step 2 — Test Sites</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:10px;">
            <div style="font-size:13px;color:var(--g);">Adds 3 demo job sites.</div>
            <button class="btn bpu" style="width:fit-content;" onclick="demoSites()">⚡ Generate Test Sites</button>
          </div>
        </div>
        <div class="panel"><div class="ph"><div class="pt" style="color:var(--pu)">Step 3 — Log Hours</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:10px;">
            <div style="font-size:13px;color:var(--g);">Logs hours for all test workers so the dashboard and health score come alive.</div>
            <button class="btn bpu" style="width:fit-content;" onclick="demoHours()">⚡ Log Hours for All Test Workers</button>
          </div>
        </div>
        <div class="panel" style="border-top:2px solid var(--y);">
          <div class="ph"><div class="pt" style="color:var(--y)">Step 3B — Fill Rest of Month</div><span style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;">Mon–Fri only</span></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:10px;">
            <div style="font-size:13px;color:var(--g);">Generates realistic varied hours for all test workers for every remaining working day this month. Gives the paysheet export and charts real data to show.</div>
            <button class="btn by" style="width:fit-content;" onclick="demoFillMonth()">📅 Fill Rest of Month with Hours</button>
          </div>
        </div>
        <div class="panel" style="border-top:2px solid var(--y);">
          <div class="ph"><div class="pt" style="color:var(--y)">Step 3C — Make Test Workers Export-Ready</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:10px;">
            <div style="font-size:13px;color:var(--g);">Removes the test tag from generated workers so they appear in payroll exports, the PDF, and the Excel — letting you test the full export flow with real-looking data.</div>
            <div style="background:rgba(255,205,17,.06);border:1px solid rgba(255,205,17,.2);padding:10px 14px;font-size:12px;color:var(--y);font-family:'Barlow Semi Condensed',sans-serif;">⚠ These workers will show in real payroll exports until you reset the demo.</div>
            <button class="btn by" style="width:fit-content;" onclick="demoMakeExportReady()">✓ Enable for Export</button>
          </div>
        </div>
        <div class="panel"><div class="ph"><div class="pt" style="color:var(--pu)">Step 4 — Suspicious Activity</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:10px;">
            <div style="font-size:13px;color:var(--g);">Simulates an invalid code attempt and a geo-fence failure.</div>
            <button class="btn bpu" style="width:fit-content;" onclick="demoSusp()" >⚡ Simulate Suspicious Attempts</button>
          <button class="btn bsm" style="background:var(--o);color:#0A0A0A;border-radius:8px;" onclick="demoStorekeeper()">📦 Load StoreKeeper Demo (PIN: 1234)</button>
          </div>
        </div>
        <div class="panel"><div class="ph"><div class="pt" style="color:var(--pu)">Step 5 — Live Check-In Demo</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:10px;">
            <div style="font-size:13px;color:var(--g);">Opens Live Check-In with a test worker pre-selected and code ready.</div>
            <button class="btn bpu" style="width:fit-content;" onclick="demoGoCI()">→ Open Live Check-In</button>
          </div>
        </div>
        <div style="border:1px solid rgba(244,67,54,.25);background:rgba(244,67,54,.04);padding:18px 22px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;">
          <div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:16px;text-transform:uppercase;color:var(--r);">🗑 Reset Everything</div>
            <div style="font-size:12px;color:var(--g);margin-top:3px;">Wipes all in-memory data. Fresh start.</div>
          </div>
          <button class="btn bred" onclick="demoReset()">Reset Demo</button>
        </div>

        <!-- DEMO TIME OVERRIDE -->
        <div class="panel" style="border-color:rgba(167,139,250,.3);">
          <div class="ph" style="border-bottom-color:rgba(167,139,250,.2);"><div class="pt" style="color:var(--pu);">🕐 Demo Time Override</div><div id="demo-time-display" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;color:var(--pu);">Real time</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:12px;">
            <div style="font-size:13px;color:var(--g);">Override the clock so you can test time window enforcement, login rules, and logout rules at any hour — without waiting for that time to actually arrive.</div>
            <div style="display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;">
              <div><label class="fl" style="margin-bottom:6px;">Set demo time</label><input type="time" class="fi" id="demo-time-input" value="07:00" style="width:140px;margin-bottom:0;"/></div>
              <button class="btn bpu" onclick="setDemoTime()">Set Time</button>
              <button class="btn bout" onclick="clearDemoTime()">Use Real Time</button>
            </div>
            <div style="display:flex;gap:8px;flex-wrap:wrap;">
              <button class="btn bout bsm" onclick="quickTime('03:50')">3:50 AM</button>
              <button class="btn bout bsm" onclick="quickTime('04:00')">4:00 AM</button>
              <button class="btn bout bsm" onclick="quickTime('06:00')">6:00 AM</button>
              <button class="btn bout bsm" onclick="quickTime('09:30')">9:30 AM</button>
              <button class="btn bout bsm" onclick="quickTime('17:00')">5:00 PM</button>
              <button class="btn bout bsm" onclick="quickTime('18:00')">6:00 PM</button>
            </div>
          </div>
        </div>

        <!-- TIME WINDOW SETTINGS -->
        <div class="panel">
          <div class="ph"><div class="pt" style="color:var(--pu);">⏰ Check-In Time Window</div><div style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;">Codes only valid during this window</div></div>
          <div style="padding:18px;display:flex;flex-direction:column;gap:14px;">
            <div style="font-size:13px;color:var(--g);">Outside these hours, valid codes are blocked and logged as suspicious. Set to 00:00–23:59 to disable the window for testing.</div>
            <div style="display:flex;gap:16px;flex-wrap:wrap;align-items:center;">
              <div><label class="fl" style="margin-bottom:6px;">Window Opens</label><input type="time" class="fi" id="tw-start" value="05:00" style="width:140px;margin-bottom:0;" onchange="saveTimeWindow()"/></div>
              <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;color:var(--g);padding-top:20px;">→</div>
              <div><label class="fl" style="margin-bottom:6px;">Window Closes</label><input type="time" class="fi" id="tw-end" value="10:00" style="width:140px;margin-bottom:0;" onchange="saveTimeWindow()"/></div>
              <div id="tw-status" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;padding-top:20px;"></div>
            </div>
          </div>
        </div>
        <div class="panel">
          <div class="ph"><div class="pt">Current Demo State</div></div>
          <div style="padding:16px;display:grid;grid-template-columns:repeat(4,1fr);gap:10px;">
            <div class="sc"><div class="scl">Workers</div><div class="scv" id="ds-w" style="color:var(--pu)">0</div></div>
            <div class="sc"><div class="scl">Sites</div><div class="scv" id="ds-s" style="color:var(--pu)">0</div></div>
            <div class="sc"><div class="scl">Entries</div><div class="scv" id="ds-e" style="color:var(--pu)">0</div></div>
            <div class="sc"><div class="scl">Suspicious</div><div class="scv" id="ds-su" style="color:var(--r)">0</div></div>
          </div>
        </div>
      </div>

    </main>
  </div>



  <!-- ══ CLERK PORTAL ══ -->
  <div class="pview" id="pv-clerk" style="flex-direction:column;overflow-y:auto;min-height:0;">
    <div class="emp-wrap" style="max-width:860px;">

      <!-- PIN GATE -->
      <div id="clerk-gate" style="display:flex;flex-direction:column;gap:14px;">
        <div style="background:rgba(255,152,0,.08);border:1px solid rgba(255,152,0,.25);border-left:3px solid var(--o);padding:16px 18px;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--o);">🔐 Site Clerk Portal</div>
          <div style="font-size:12px;color:var(--g);margin-top:3px;">Select your name and enter your Clerk PIN to access the check-in gate.</div>
        </div>
        <div>
          <label class="fl">Who are you?</label>
          <select class="fi" id="clerk-gate-who" onchange="clerkGateWhoChange()" style="margin-bottom:0;"><option value="">Select your name...</option></select>
        </div>
        <div id="clerk-gate-pin-wrap" style="display:none;">
          <label class="fl">Clerk PIN</label>
          <div style="display:flex;gap:8px;">
            <input class="fi" type="password" id="clerk-gate-pin-input" maxlength="4" placeholder="••••" inputmode="numeric" style="margin-bottom:0;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:28px;letter-spacing:.3em;text-align:center;flex:1;" oninput="this.value=this.value.replace(/\D/g,'')"/>
            <button class="btn" style="background:var(--o);color:#0A0A0A;font-size:18px;padding:0 20px;border-radius:8px;" onclick="verifyClerkGatePIN()">→</button>
          </div>
          <div id="clerk-gate-pin-err" style="display:none;color:var(--r);font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;margin-top:6px;">Incorrect PIN. Try again.</div>
        </div>
      </div>

      <!-- CLERK DASHBOARD (shown after PIN) -->
      <div id="clerk-dashboard" style="display:none;flex-direction:column;gap:16px;">
      <!-- CLERK PIN ENTRY -->
      <div id="clerk-pin-entry" style="display:none;background:var(--surf);border:1px solid var(--bd);border-top:3px solid var(--o);padding:22px;">
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--o);margin-bottom:4px;">Enter Clerk PIN</div>
        <div style="font-size:12px;color:var(--g);margin-bottom:16px;">Enter the 4-digit PIN your employer assigned to you.</div>
        <div style="display:flex;gap:8px;margin-bottom:12px;">
          <input class="fi" type="password" id="clerk-pin-input" maxlength="4" placeholder="••••" inputmode="numeric" style="margin-bottom:0;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:28px;letter-spacing:.3em;text-align:center;flex:1;" oninput="this.value=this.value.replace(/\D/g,'')"/>
          <button class="btn bo" onclick="verifyClerkPIN()" style="font-size:18px;padding:0 18px;">→</button>
        </div>
        <div id="clerk-pin-err" style="display:none;color:var(--r);font-size:13px;font-family:'Barlow Semi Condensed',sans-serif;margin-bottom:8px;">Incorrect PIN. Try again.</div>
        <button class="btn bout bsm" onclick="cancelClerkPIN()">Cancel</button>
      </div>

      <!-- ACTIVE CLERK MODE — smart flow, no code shown -->
      <div id="clerk-active-mode" style="display:flex;flex-direction:column;gap:12px;">
        <div style="background:rgba(255,152,0,.08);border:2px solid rgba(255,152,0,.35);padding:14px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;">
          <div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--o);">🔐 Clerk Mode Active</div>
            <div style="font-size:12px;color:var(--g);margin-top:2px;" id="clerk-active-name"></div>
          </div>
          <button class="btn bout bsm" onclick="exitClerkPortal()">Exit Clerk Mode</button>
        </div>

        <!-- STEP 1: SELECT WORKER + DIRECTION -->
        <div class="panel">
          <div class="ph"><div class="pt" style="color:var(--o);">Step 1 — Select Worker</div></div>
          <div style="padding:16px;display:flex;flex-direction:column;gap:12px;">
            <select class="fi" id="clerk-worker-sel" onchange="clerkSelectWorker()" style="margin-bottom:0;"><option value="">Select worker...</option></select>

            <!-- Direction toggle: Check In or Check Out -->
            <div id="clerk-direction-wrap" style="display:none;">
              <label class="fl">Action</label>
              <div style="display:flex;gap:8px;">
                <button id="clerk-dir-in" onclick="clerkSetDir('in')" style="flex:1;padding:10px;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;letter-spacing:.06em;text-transform:uppercase;border:2px solid var(--gr);background:rgba(76,175,80,.1);color:var(--gr);cursor:pointer;transition:all .2s;">✓ Check In</button>
                <button id="clerk-dir-out" onclick="clerkSetDir('out')" style="flex:1;padding:10px;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;letter-spacing:.06em;text-transform:uppercase;border:2px solid var(--bd);background:transparent;color:var(--g);cursor:pointer;transition:all .2s;">← Check Out</button>
              </div>
            </div>

            <!-- Time window status indicator -->
            <div id="clerk-window-status" style="display:none;padding:10px 14px;border:1px solid var(--bd);background:var(--bg);">
              <div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
                <div id="clerk-window-icon" style="font-size:24px;line-height:1;flex-shrink:0;"></div>
                <div style="flex:1;">
                  <div id="clerk-window-label" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:14px;text-transform:uppercase;letter-spacing:.04em;"></div>
                  <div id="clerk-window-sub" style="font-size:11px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;"></div>
                </div>
                <div id="clerk-window-rule-badge" style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:3px 10px;"></div>
              </div>
              <!-- Bypass checkbox — only shown when outside window -->
              <div id="clerk-bypass-wrap" style="display:none;margin-top:10px;border-top:1px solid var(--bd);padding-top:10px;">
                <label style="display:flex;align-items:center;gap:8px;cursor:pointer;">
                  <input type="checkbox" id="clerk-bypass-chk" style="accent-color:var(--r);width:14px;height:14px;" onchange="clerkUpdBypass()"/>
                  <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:600;color:var(--ow);">⚠ Override time window — I acknowledge this is outside the allowed window</span>
                </label>
                <!-- Mandatory acknowledgement (only for mandatory workers) -->
                <div id="clerk-mandatory-ack" style="display:none;margin-top:10px;background:rgba(244,67,54,.08);border:1px solid rgba(244,67,54,.3);padding:10px 12px;">
                  <div style="font-size:12px;color:var(--r);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;margin-bottom:6px;" id="clerk-mandatory-msg"></div>
                  <label style="display:flex;align-items:center;gap:8px;cursor:pointer;">
                    <input type="checkbox" id="clerk-mandatory-confirm" style="accent-color:var(--r);width:14px;height:14px;"/>
                    <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;color:var(--ow);">I acknowledge — this will be logged to suspicious activity</span>
                  </label>
                </div>
              </div>
            </div>

            <!-- Generate & Submit button -->
            <button id="clerk-submit-btn" onclick="clerkSubmit()" style="display:none;width:100%;padding:14px;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;letter-spacing:.08em;text-transform:uppercase;background:var(--gr);border:none;color:#fff;cursor:pointer;transition:all .2s;">✓ Confirm & Submit Check-In</button>

            <!-- Result -->
            <div id="clerk-submit-res" style="display:none;padding:14px;text-align:center;border:2px solid transparent;">
              <div id="clerk-submit-ric" style="font-size:40px;line-height:1;margin-bottom:6px;"></div>
              <div id="clerk-submit-rn" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:22px;margin-bottom:3px;"></div>
              <div id="clerk-submit-rm" style="font-size:12px;color:var(--g);margin-bottom:8px;"></div>
              <div id="clerk-submit-rt" style="font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:4px 12px;display:inline-block;"></div>
              <button class="btn bout bsm" onclick="clerkNextWorker()" style="display:block;width:100%;justify-content:center;margin-top:10px;">→ Next Worker</button>
            </div>
          </div>
        </div>

        <!-- TODAY'S LOG -->
        <div class="panel">
          <div class="ph"><div class="pt">Today's Activity</div><span id="cl-cnt" style="font-size:12px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;">0 entries</span></div>
          <div class="tw"><table><thead><tr><th>Worker</th><th>Type</th><th>Time</th><th>Status</th></tr></thead><tbody id="cl-tb"><tr><td colspan="4" style="padding:16px;text-align:center;color:var(--g);font-size:13px">No activity yet.</td></tr></tbody></table></div>
        </div>
      </div>

      </div><!-- /clerk-dashboard -->
    </div><!-- /emp-wrap -->
  </div><!-- /pv-clerk -->

  <!-- ══ STOREKEEPER PORTAL ══ -->
  <div class="pview" id="pv-storekeeper" style="flex-direction:column;overflow-y:auto;min-height:0;">
    <div class="emp-wrap" style="max-width:900px;">

      <!-- PIN GATE -->
      <div id="sk-gate" style="display:flex;flex-direction:column;gap:14px;">
        <div style="background:rgba(255,152,0,.08);border:1px solid rgba(255,152,0,.25);border-left:3px solid var(--o);padding:16px 18px;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--o);">📦 StoreKeeper Portal</div>
          <div style="font-size:12px;color:var(--g);margin-top:3px;">Select your name and enter your StoreKeeper PIN to access site inventory.</div>
        </div>
        <div>
          <label class="fl">Who are you?</label>
          <select class="fi" id="sk-who" onchange="skWhoChange()" style="margin-bottom:0;"><option value="">Select your name...</option></select>
        </div>
        <div id="sk-pin-wrap" style="display:none;">
          <label class="fl">StoreKeeper PIN</label>
          <div style="display:flex;gap:8px;">
            <input class="fi" type="password" id="sk-pin-input" maxlength="4" placeholder="••••" inputmode="numeric" style="margin-bottom:0;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:28px;letter-spacing:.3em;text-align:center;flex:1;"/>
            <button class="btn" style="background:var(--o);color:#0A0A0A;font-size:18px;padding:0 20px;border-radius:8px;" onclick="verifySkPIN()">→</button>
          </div>
          <div id="sk-pin-err" style="display:none;color:var(--r);font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;margin-top:6px;">Incorrect PIN. Try again.</div>
        </div>
      </div>

      <!-- STOREKEEPER DASHBOARD -->
      <div id="sk-dashboard" style="display:none;flex-direction:column;gap:16px;">
        <div style="background:rgba(255,152,0,.08);border:1px solid rgba(255,152,0,.25);border-left:3px solid var(--o);padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;">
          <div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--o);">📦 StoreKeeper — <span id="sk-name-display"></span></div>
            <div style="font-size:12px;color:var(--g);margin-top:2px;">Site: <strong id="sk-site-display" style="color:var(--ow);"></strong></div>
          </div>
          <button class="btn bout bsm" onclick="exitSkMode()">Exit StoreKeeper Mode</button>
        </div>
        <div class="sr" style="grid-template-columns:repeat(4,1fr);">
          <div class="sc" style="border-top-color:var(--y);"><div class="scl">Items in Stock</div><div class="scv" id="sk-st0" style="color:var(--y);">0</div><div class="scs">at your site</div></div>
          <div class="sc" style="border-top-color:var(--o);"><div class="scl">Checked Out</div><div class="scv" id="sk-st1" style="color:var(--o);">0</div><div class="scs">currently issued</div></div>
          <div class="sc" style="border-top-color:var(--r);"><div class="scl">Low Stock</div><div class="scv" id="sk-st2" style="color:var(--r);">0</div><div class="scs">need reorder</div></div>
          <div class="sc" style="border-top-color:var(--r);"><div class="scl">Overdue</div><div class="scv" id="sk-st3" style="color:var(--r);">0</div><div class="scs">past due date</div></div>
        </div>
        <div class="panel">
          <div class="ph"><div class="pt">⚡ Quick Actions</div></div>
          <div style="padding:14px;display:flex;gap:10px;flex-wrap:wrap;">
            <button class="btn by" onclick="openSkIssue()" style="gap:6px;border-radius:8px;">✓ Issue Tool / Item</button>
            <button class="btn" style="background:var(--o);color:#0A0A0A;border-radius:8px;gap:6px;" onclick="openSkReturn()">← Return Tool / Item</button>
            <button class="btn bpu" style="border-radius:8px;gap:6px;" onclick="openSkReceive()">📦 Receive Stock</button>
          </div>
        </div>
        <div class="panel">
          <div class="ph"><div class="pt">🔧 Currently Checked Out</div><div id="sk-co-count" style="font-size:11px;color:var(--g);"></div></div>
          <div class="tw"><table><thead><tr><th>Item</th><th>Type</th><th>Worker</th><th>Date Out</th><th>Due Back</th><th>Status</th><th></th></tr></thead><tbody id="sk-checkout-list"></tbody></table></div>
        </div>
        <div class="panel" id="sk-low-panel" style="display:none;">
          <div class="ph"><div class="pt">⚠️ Low Stock Alerts</div></div>
          <div id="sk-low-list" style="padding:12px 16px;display:flex;flex-direction:column;gap:6px;"></div>
        </div>
        <div class="panel">
          <div class="ph"><div class="pt">📋 Site Inventory</div>
            <select id="sk-filter-type" onchange="renderSkDashboard()" class="fi" style="margin:0;padding:5px 10px;font-size:11px;border-radius:6px;width:auto;">
              <option value="">All Types</option><option value="tool">Tools</option><option value="equipment">Equipment</option><option value="consumable">Consumables</option>
            </select>
          </div>
          <div class="tw"><table><thead><tr><th>Name</th><th>Type</th><th>Qty</th><th>Condition</th><th>Status</th><th></th></tr></thead><tbody id="sk-inv-list"></tbody></table></div>
        </div>
        <div class="panel">
          <div class="ph"><div class="pt">📜 Recent Activity</div></div>
          <div id="sk-txn-list" style="padding:0;"></div>
        </div>
      </div><!-- /sk-dashboard -->
    </div><!-- /emp-wrap -->
  </div><!-- /pv-storekeeper -->

  <!-- ══ MANAGER PORTAL ══ -->
  <div class="pview" id="pv-manager" style="flex-direction:column;overflow-y:auto;padding:0;min-height:0;">
    <div class="emp-wrap" style="max-width:860px;">

      <!-- PIN GATE -->
      <div id="mgr-gate" style="display:flex;flex-direction:column;gap:14px;">
        <div style="background:rgba(167,139,250,.08);border:1px solid rgba(167,139,250,.25);border-left:3px solid var(--pu);padding:16px 18px;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--pu);">🔧 Manager Portal</div>
          <div style="font-size:12px;color:var(--g);margin-top:3px;">Select your name and enter your Manager PIN to access your site dashboard.</div>
        </div>
        <div>
          <label class="fl">Who are you?</label>
          <select class="fi" id="mgr-who" onchange="mgrWhoChange()" style="margin-bottom:0;"><option value="">Select your name...</option></select>
        </div>
        <div id="mgr-pin-wrap" style="display:none;">
          <label class="fl">Manager PIN</label>
          <div style="display:flex;gap:8px;">
            <input class="fi" type="password" id="mgr-pin-input" maxlength="4" placeholder="••••" inputmode="numeric" style="margin-bottom:0;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:28px;letter-spacing:.3em;text-align:center;flex:1;" oninput="this.value=this.value.replace(/\D/g,'')"/>
            <button class="btn bpu" onclick="verifyMgrPIN()" style="font-size:18px;padding:0 20px;">→</button>
          </div>
          <div id="mgr-pin-err" style="display:none;color:var(--r);font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;margin-top:6px;">Incorrect PIN. Try again.</div>
        </div>
      </div>

      <!-- MANAGER DASHBOARD (shown after PIN) -->
      <div id="mgr-dashboard" style="display:none;flex-direction:column;gap:16px;">

        <!-- Header bar -->
        <div style="background:rgba(167,139,250,.08);border:1px solid rgba(167,139,250,.25);border-left:3px solid var(--pu);padding:12px 18px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;">
          <div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--pu);">🔧 Manager — <span id="mgr-name-display"></span></div>
            <div style="font-size:12px;color:var(--g);margin-top:2px;">Site: <strong id="mgr-site-display" style="color:var(--ow);"></strong></div>
          </div>
          <button class="btn bout bsm" onclick="exitMgrMode()">Exit Manager Mode</button>
        </div>

        <!-- Stats row -->
        <div class="sr" id="mgr-stats">
          <div class="sc" style="border-left-color:var(--gr)"><div class="scl">Checked In</div><div class="scv" id="mgr-st0" style="color:var(--gr)">0</div><div class="scs">today at your site</div></div>
          <div class="sc"><div class="scl">Not Logged</div><div class="scv" id="mgr-st1" style="color:var(--r)">0</div><div class="scs">unaccounted</div></div>
          <div class="sc"><div class="scl">Hours Today</div><div class="scv" id="mgr-st2" style="color:var(--y)">0</div><div class="scs">at your site</div></div>
          <div class="sc" style="border-left-color:var(--r)"><div class="scl">Suspicious</div><div class="scv" id="mgr-st3" style="color:var(--r)">0</div><div class="scs">flagged today</div></div>
          <div class="sc" id="mgr-payroll-card" style="display:none;border-left-color:var(--pu)"><div class="scl">Est. Labour Cost</div><div class="scv" id="mgr-st4" style="color:var(--pu)">R0</div><div class="scs">today at your site</div></div>
        </div>

        <!-- Worker status at site -->
        <div class="panel">
          <div class="ph"><div class="pt">👷 Workers at Your Site — Today</div><span id="mgr-worker-cnt" style="font-size:12px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;"></span></div>
          <div id="mgr-worker-list" style="padding:0;"></div>
        </div>

        <!-- Suspicious activity at site -->
        <div class="panel" id="mgr-susp-panel">
          <div class="ph"><div class="pt" style="color:var(--r);">🚨 Suspicious Activity — Your Site</div><span id="mgr-susp-cnt" style="font-size:12px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;"></span></div>
          <div id="mgr-susp-list" style="padding:0;"></div>
        </div>

        <!-- Manager Actions -->
        <div class="panel">
          <div class="ph"><div class="pt">⚡ Manager Actions</div></div>
          <div style="padding:14px;display:flex;gap:8px;flex-wrap:wrap;">
            <button class="btn bpu bsm" onclick="openMgrExcuse()">📋 Excuse Worker</button>
            <button class="btn bpu bsm" onclick="openMgrDispute()">📝 Log Dispute</button>
            <button class="btn bpu bsm" onclick="openMgrCompDays()">🔄 Compensation Days</button>
            <button class="btn bpu bsm" onclick="openMgrOTDays()">💰 OT / Bonus Days</button>
            <button class="btn bpu bsm" onclick="openMgrCheckin()">✓ Check In Worker</button>
          </div>
        </div>

        <!-- Manager Check-In panel (shown on demand) -->
        <div id="mgr-checkin-panel" style="display:none;">
          <div class="panel">
            <div class="ph"><div class="pt" style="color:var(--pu);">🔧 Manager Check-In / Checkout</div><button class="btn bout bsm" onclick="closeMgrCheckin()">Close</button></div>
            <div style="padding:16px;display:flex;flex-direction:column;gap:12px;">
              <select class="fi" id="mgr-ci-sel" onchange="mgrCISelectWorker()" style="margin-bottom:0;"><option value="">Select worker at your site...</option></select>
              <div id="mgr-ci-dir-wrap" style="display:none;">
                <div style="display:flex;gap:8px;margin-bottom:10px;">
                  <button id="mgr-dir-in" onclick="mgrSetDir('in')" style="flex:1;padding:10px;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;letter-spacing:.06em;text-transform:uppercase;border:2px solid var(--gr);background:rgba(76,175,80,.1);color:var(--gr);cursor:pointer;">✓ Check In</button>
                  <button id="mgr-dir-out" onclick="mgrSetDir('out')" style="flex:1;padding:10px;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;letter-spacing:.06em;text-transform:uppercase;border:2px solid var(--bd);background:transparent;color:var(--g);cursor:pointer;">← Check Out</button>
                </div>
                <div id="mgr-ci-window" style="background:var(--bg);border:1px solid var(--bd);padding:10px 14px;font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);margin-bottom:10px;"></div>
                <button id="mgr-ci-btn" onclick="mgrSubmitCI()" style="width:100%;padding:12px;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:14px;letter-spacing:.06em;text-transform:uppercase;background:var(--gr);border:none;color:#fff;cursor:pointer;">✓ Confirm Check-In</button>
                <div id="mgr-ci-res" style="display:none;margin-top:10px;padding:12px;text-align:center;border:2px solid transparent;"></div>
              </div>
            </div>
          </div>
        </div>

      </div>
    </div>
  </div>

  <!-- ══ EMPLOYEE PORTAL ══ -->
  <div class="pview" id="pv-employee">
    <div class="emp-wrap">
      <div style="background:rgba(255,205,17,.06);border:1px solid rgba(255,205,17,.2);border-left:3px solid var(--y);padding:14px 18px;">
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;text-transform:uppercase;color:var(--y);">👷 Worker Portal</div>
        <div style="font-size:13px;color:var(--g);margin-top:2px;">Select your name to log hours. If your employer gave you clerk access, the option appears after you select yourself.</div>
      </div>
      <div><label class="fl">Who are you?</label>
        <select class="fi" id="emp-who" onchange="empSelect()" style="margin-bottom:0;"><option value="">Select your name...</option></select>
      </div>

      <!-- CLERK MODE BANNER -->
      <div id="clerk-access-banner" style="display:none;background:rgba(255,152,0,.08);border:1px solid rgba(255,152,0,.3);border-left:3px solid var(--o);padding:14px 18px;">
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;text-transform:uppercase;color:var(--o);margin-bottom:4px;">🔐 Site Clerk Access Granted</div>
        <div style="font-size:12px;color:var(--g);margin-bottom:10px;">Your employer has assigned you as Site Clerk. Switch to clerk mode to check workers in at the gate.</div>
        <button class="btn bo bsm" onclick="switchPortal('clerk',document.querySelector('.sp-item[data-sb-label=\"Clerk\"]'))">Switch to Clerk Mode</button>
      </div>

      <!-- MANAGER ACCESS BANNER -->
      <div id="mgr-access-banner" style="display:none;background:rgba(167,139,250,.08);border:1px solid rgba(167,139,250,.3);border-left:3px solid var(--pu);padding:14px 18px;">
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;text-transform:uppercase;color:var(--pu);margin-bottom:4px;">🔧 Manager Access Available</div>
        <div style="font-size:12px;color:var(--g);margin-bottom:10px;">You have manager access. Switch to the Manager tab and enter your PIN to access your site dashboard.</div>
        <button class="btn bpu bsm" onclick="switchPortal('manager',document.querySelector('.sp-item[data-sb-label="Manager"]'))">Go to Manager Portal →</button>
      </div>

      <!-- STOREKEEPER ACCESS BANNER -->
      <div id="sk-access-banner" style="display:none;background:rgba(255,152,0,.08);border:1px solid rgba(255,152,0,.3);border-left:3px solid var(--o);padding:14px 18px;">
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;text-transform:uppercase;color:var(--o);margin-bottom:4px;">📦 StoreKeeper Access Available</div>
        <div style="font-size:12px;color:var(--g);margin-bottom:10px;">You have StoreKeeper access. Switch to the StoreKeeper tab and enter your PIN to manage site inventory.</div>
        <button class="btn bsm" style="background:var(--o);color:#0A0A0A;border-radius:8px;" onclick="switchPortal('storekeeper',document.querySelector('.sp-item[data-sb-label=\'StoreKeeper\']'))">Go to StoreKeeper Portal →</button>
      </div>

      <div id="emp-form" style="display:none;flex-direction:column;gap:14px;">

        <!-- GREETING + STATUS -->
        <div style="background:var(--surf);border:1px solid var(--bd);border-top:3px solid var(--y);padding:18px;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;margin-bottom:3px;" id="emp-greeting">Good morning,</div>
          <div style="font-size:12px;color:var(--g);" id="emp-date"></div>
        </div>

        <!-- CHECK-IN STATUS -->
        <div id="emp-status-card" style="padding:16px 18px;border:1px solid var(--bd);background:var(--surf2);display:flex;align-items:center;gap:14px;">
          <div id="emp-status-icon" style="font-size:32px;line-height:1;flex-shrink:0;">⏳</div>
          <div>
            <div id="emp-status-title" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:16px;text-transform:uppercase;letter-spacing:.04em;">Not Checked In Yet</div>
            <div id="emp-status-sub" style="font-size:12px;color:var(--g);margin-top:2px;">Show your daily code to the site clerk when you arrive at work.</div>
          </div>
        </div>

        <!-- EXCUSE NOTICE — shown when worker is excused -->
        <div id="emp-excuse-notice" style="display:none;background:rgba(255,205,17,.08);border:1px solid rgba(255,205,17,.3);border-left:3px solid var(--y);padding:14px 18px;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:16px;text-transform:uppercase;letter-spacing:.04em;color:var(--y);margin-bottom:4px;">📋 You Are Excused</div>
          <div id="emp-excuse-text" style="font-size:12px;color:var(--g);line-height:1.7;"></div>
        </div>

        <!-- DAILY CODE — read only, for showing to clerk -->
        <div style="background:var(--bg);border:2px solid rgba(255,205,17,.25);padding:20px;text-align:center;">
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.15em;text-transform:uppercase;color:var(--g);margin-bottom:8px;">Your Daily Check-In Code</div>
          <div id="emp-code-val" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:58px;letter-spacing:.2em;color:var(--y);line-height:1;"></div>
          <div id="emp-code-status" style="font-size:11px;color:var(--g);margin-top:8px;">Show this to the security guard at the gate. Valid today only.</div>
          <div id="emp-time-warn" style="display:none;margin-top:10px;background:rgba(244,67,54,.08);border:1px solid rgba(244,67,54,.25);padding:8px 12px;font-size:12px;color:var(--r);font-family:'Barlow Semi Condensed',sans-serif;"></div>
        </div>

        <!-- MY HOURS THIS WEEK — read only -->
        <div class="panel">
          <div class="ph"><div class="pt">My Hours This Week</div><div id="emp-week-total" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;color:var(--y);">—</div></div>
          <div class="emp-history" id="emp-hist" style="padding:12px 16px;"><div style="color:var(--g);font-size:13px;text-align:center;padding:12px">No entries this week. Check in via the site clerk to have hours logged.</div></div>
        </div>

        <div id="emp-tools-section" style="margin-top:0;"></div>
        <div style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;text-align:center;line-height:1.7;">Hours are logged by the site clerk when you check in. You cannot submit your own hours. Contact your employer if something looks wrong.</div>
      </div>
    </div>
  </div>

</div>

<!-- STOREKEEPER — ISSUE TOOL MODAL -->
<div class="mo" id="msk-issue">
  <div class="md" style="max-width:540px;">
    <div class="mdt">✓ Issue Tool / Item</div>
    <div class="mds">Select an available item and assign it to a worker.</div>
    <div class="fg"><label class="fl">Item to Issue</label>
      <select class="fi" id="sk-issue-item" onchange="skIssueItemChange()" style="margin-bottom:0;">
        <option value="">Select item...</option>
      </select>
    </div>
    <div id="sk-issue-item-info" style="display:none;background:var(--surf2);border:1px solid var(--bd);border-left:2px solid var(--o);border-radius:8px;padding:10px 14px;margin-top:8px;font-size:12px;color:var(--g);"></div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Assign to Worker</label>
      <select class="fi" id="sk-issue-worker" style="margin-bottom:0;"><option value="">Select worker...</option></select>
    </div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Due Back Date</label>
      <input class="fi" type="date" id="sk-issue-due" style="margin-bottom:0;"/>
    </div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Condition on Issue</label>
      <div style="display:flex;gap:8px;flex-wrap:wrap;">
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;background:var(--surf2);border:1px solid var(--bd);border-radius:8px;padding:8px 14px;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;transition:all .15s;">
          <input type="radio" name="sk-issue-cond" value="good" checked style="accent-color:var(--gr);"/> Good
        </label>
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;background:var(--surf2);border:1px solid var(--bd);border-radius:8px;padding:8px 14px;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;transition:all .15s;">
          <input type="radio" name="sk-issue-cond" value="fair" style="accent-color:var(--y);"/> Fair
        </label>
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;background:var(--surf2);border:1px solid var(--bd);border-radius:8px;padding:8px 14px;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;transition:all .15s;">
          <input type="radio" name="sk-issue-cond" value="needs-repair" style="accent-color:var(--o);"/> Needs Repair
        </label>
      </div>
    </div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Notes (optional)</label>
      <input class="fi" id="sk-issue-notes" placeholder="Any notes about this issue..." style="margin-bottom:0;"/>
    </div>
    <div class="ma">
      <button class="btn bout" onclick="cm('msk-issue')">Cancel</button>
      <button class="btn" style="background:var(--y);color:#0A0A0A;border-radius:8px;" onclick="confirmSkIssue()">✓ Confirm Issue</button>
    </div>
  </div>
</div>

<!-- STOREKEEPER — RETURN TOOL MODAL -->
<div class="mo" id="msk-return">
  <div class="md" style="max-width:540px;">
    <div class="mdt">← Return Tool / Item</div>
    <div class="mds">Select the item being returned and record its condition.</div>
    <div class="fg"><label class="fl">Item Being Returned</label>
      <select class="fi" id="sk-return-item" style="margin-bottom:0;"><option value="">Select checked-out item...</option></select>
    </div>
    <div id="sk-return-item-info" style="display:none;background:var(--surf2);border:1px solid var(--bd);border-left:2px solid var(--o);border-radius:8px;padding:10px 14px;margin-top:8px;font-size:12px;color:var(--g);"></div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Condition on Return</label>
      <div style="display:flex;gap:8px;flex-wrap:wrap;">
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;background:var(--surf2);border:1px solid var(--bd);border-radius:8px;padding:8px 14px;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;">
          <input type="radio" name="sk-return-cond" value="good" checked style="accent-color:var(--gr);"/> Good
        </label>
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;background:var(--surf2);border:1px solid var(--bd);border-radius:8px;padding:8px 14px;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;">
          <input type="radio" name="sk-return-cond" value="fair" style="accent-color:var(--y);"/> Fair
        </label>
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;background:var(--surf2);border:1px solid var(--bd);border-radius:8px;padding:8px 14px;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;">
          <input type="radio" name="sk-return-cond" value="needs-repair" style="accent-color:var(--o);"/> Needs Repair
        </label>
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;background:var(--surf2);border:1px solid var(--bd);border-radius:8px;padding:8px 14px;font-size:12px;font-family:'Inter',sans-serif;font-weight:600;">
          <input type="radio" name="sk-return-cond" value="damaged" style="accent-color:var(--r);"/> Damaged
        </label>
      </div>
    </div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Notes (required if damaged)</label>
      <textarea class="fi" id="sk-return-notes" placeholder="Describe any damage or condition change..." style="margin-bottom:0;min-height:60px;resize:none;"></textarea>
    </div>
    <div class="ma">
      <button class="btn bout" onclick="cm('msk-return')">Cancel</button>
      <button class="btn" style="background:var(--o);color:#0A0A0A;border-radius:8px;" onclick="confirmSkReturn()">← Confirm Return</button>
    </div>
  </div>
</div>

<!-- STOREKEEPER — RECEIVE STOCK MODAL -->
<div class="mo" id="msk-receive">
  <div class="md" style="max-width:540px;">
    <div class="mdt">📦 Receive Stock</div>
    <div class="mds">Record incoming stock or new items for this site.</div>
    <div class="fg"><label class="fl">Item Name</label>
      <input class="fi" id="sk-recv-name" placeholder="e.g. Safety Gloves, Angle Grinder..." style="margin-bottom:0;"/>
    </div>
    <div class="mr" style="margin-top:12px;">
      <div><label class="fl">Type</label>
        <select class="fi" id="sk-recv-type" style="margin-bottom:0;">
          <option value="tool">Tool</option>
          <option value="equipment">Equipment</option>
          <option value="consumable">Consumable</option>
        </select>
      </div>
      <div><label class="fl">Quantity</label>
        <input class="fi" type="number" id="sk-recv-qty" value="1" min="1" style="margin-bottom:0;"/>
      </div>
    </div>
    <div class="mr" style="margin-top:12px;">
      <div><label class="fl">Category</label>
        <input class="fi" id="sk-recv-cat" placeholder="Power Tools, PPE, Materials..." style="margin-bottom:0;"/>
      </div>
      <div><label class="fl">Min Stock (reorder alert)</label>
        <input class="fi" type="number" id="sk-recv-min" value="0" min="0" style="margin-bottom:0;"/>
      </div>
    </div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Serial / Reference Number (optional)</label>
      <input class="fi" id="sk-recv-serial" placeholder="AG-2024-001" style="margin-bottom:0;"/>
    </div>
    <div class="fg" style="margin-top:12px;"><label class="fl">Notes (optional)</label>
      <input class="fi" id="sk-recv-notes" placeholder="Supplier, delivery note, condition..." style="margin-bottom:0;"/>
    </div>
    <div class="ma">
      <button class="btn bout" onclick="cm('msk-receive')">Cancel</button>
      <button class="btn bpu" style="border-radius:8px;" onclick="confirmSkReceive()">📦 Add to Inventory</button>
    </div>
  </div>
</div>

<!-- STOREKEEPER — INVENTORY ITEM DETAIL MODAL -->
<div class="mo" id="msk-item">
  <div class="md" style="max-width:540px;">
    <div class="mdt" id="sk-item-name-title">Item Detail</div>
    <div id="sk-item-detail-body" style="font-size:13px;line-height:2;"></div>
    <div id="sk-item-txn-history" style="margin-top:14px;border-top:1px solid var(--bd);padding-top:14px;"></div>
    <div class="ma">
      <button class="btn bout" onclick="cm('msk-item')">Close</button>
    </div>
  </div>
</div>

<!-- END OF DAY SUMMARY MODAL -->
<div class="mo" id="meod">
  <div class="md" style="max-width:620px;">
    <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;flex-wrap:wrap;gap:10px;">
      <div>
        <div class="mdt">📋 End of Day Report</div>
        <div class="mds" id="eod-date-label" style="margin-bottom:0;"></div>
      </div>
      <div style="display:flex;gap:8px;">
        <button class="btn bpu bsm" onclick="printEOD()" style="border-radius:8px;gap:6px;">🖨 Print</button>
        <button class="btn bout bsm" onclick="cm('meod')" style="border-radius:8px;">✕ Close</button>
      </div>
    </div>

    <!-- Stats strip -->
    <div id="eod-stats" style="display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin:16px 0;"></div>

    <!-- Checked in -->
    <div style="margin-bottom:14px;">
      <div style="font-family:'Inter',sans-serif;font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--g);margin-bottom:8px;">✅ Checked In Today</div>
      <div id="eod-present" style="display:flex;flex-direction:column;gap:4px;"></div>
    </div>

    <!-- Absent -->
    <div style="margin-bottom:14px;">
      <div style="font-family:'Inter',sans-serif;font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--g);margin-bottom:8px;">⚠️ Absent / Not Logged</div>
      <div id="eod-absent" style="display:flex;flex-direction:column;gap:4px;"></div>
    </div>

    <!-- Suspicious -->
    <div id="eod-susp-section" style="margin-bottom:6px;">
      <div style="font-family:'Inter',sans-serif;font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--r);margin-bottom:8px;">🚨 Suspicious Flags Today</div>
      <div id="eod-susp" style="display:flex;flex-direction:column;gap:4px;"></div>
    </div>
  </div>
</div>

<!-- ADD WORKER MODAL -->
<div class="mo" id="mw">
  <div class="md">
    <div class="mdt">Add Worker</div>
    <div class="mds">Pre-filled as a test worker. Customise the name and details before saving.</div>
    <div class="mr">
      <div><label class="fl">Name</label><input class="fi" id="wnam" style="margin-bottom:0;" placeholder="Test Worker 1"/></div>
      <div><label class="fl">Role</label><input class="fi" id="wrol" style="margin-bottom:0;" placeholder="Operator"/></div>
    </div>
    <div class="mr" style="margin-top:12px;">
      <div><label class="fl">Phone</label><input class="fi" id="wpho" style="margin-bottom:0;" placeholder="+27 82 000 0000"/></div>
      <div><label class="fl">Expected Days/Week</label><input class="fi" type="number" id="wexp" value="5" style="margin-bottom:0;"/></div>
    </div>
    <div class="fg"><label class="fl">Pay Type</label>
      <select class="fi" id="wpt" onchange="updWPF()" style="margin-bottom:0;">
        <option value="hourly">Hourly Rate</option><option value="daily">Daily Rate</option>
        <option value="weekly">Weekly Salary</option><option value="monthly">Monthly Salary</option>
        <option value="piece">Piece Rate</option><option value="day-overtime">Day Rate + Overtime</option>
        <option value="shift">Shift Rate</option><option value="contract">Contract Rate</option>
      </select>
    </div>
    <div class="fg" id="wpf"></div>
    <div class="fg"><label style="display:flex;align-items:center;gap:8px;cursor:pointer;margin-bottom:10px;"><input type="checkbox" id="wistest" checked style="accent-color:var(--pu);width:14px;height:14px;"/><span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;color:var(--g);">Tag as test worker <span style="color:var(--pu)">(excluded from real payroll exports)</span></span></label>


    <!-- STOREKEEPER ROLE -->
    <div style="border-top:1px solid var(--bd);padding-top:14px;margin-top:4px;">
      <label style="display:flex;align-items:center;gap:8px;cursor:pointer;margin-bottom:10px;">
        <input type="checkbox" id="wisskeeper" style="accent-color:var(--o);width:14px;height:14px;" onchange="updSkFields()"/>
        <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;color:var(--g);">
          📦 Assign as <span style="color:var(--o)">StoreKeeper</span> — manages site inventory
        </span>
      </label>
      <div id="skeeper-fields-wrap" style="display:none;flex-direction:column;gap:10px;background:rgba(255,152,0,.04);border:1px solid rgba(255,152,0,.2);border-radius:8px;padding:12px 14px;">
        <div class="mr">
          <div><label class="fl">StoreKeeper PIN (4 digits)</label>
            <input class="fi" type="password" id="wskeeper-pin" maxlength="4" placeholder="••••" inputmode="numeric" style="margin-bottom:0;font-family:'Barlow Condensed',sans-serif;font-size:22px;letter-spacing:.3em;text-align:center;"/>
          </div>
          <div><label class="fl">Assigned Site</label>
            <select class="fi" id="wskeeper-site" style="margin-bottom:0;">
              <option value="">All Sites</option>
            </select>
          </div>
        </div>
      </div>
    </div>
    <!-- SHIFT RULES -->
    <div style="border-top:1px solid var(--bd);padding-top:16px;margin-top:4px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px;">
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:14px;text-transform:uppercase;letter-spacing:.05em;">⏰ Shift &amp; Login Rules</div>
        <div id="shift-validity" style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.08em;text-transform:uppercase;"></div>
      </div>
      <div style="font-size:12px;color:var(--g);margin-bottom:14px;line-height:1.6;">Set the expected check-in and checkout windows for this worker. If they arrive or leave outside the window, the system flags it.</div>

      <!-- CHECK-IN WINDOW -->
      <div style="background:rgba(255,205,17,.04);border:1px solid rgba(255,205,17,.2);padding:12px 14px;margin-bottom:10px;" id="login-rule-box">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;">
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--y);">Check-In Window</div>
          <span id="login-rule-badge" style="font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:2px 8px;background:rgba(255,205,17,.15);color:var(--y);">Recommended</span>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px;">
          <div style="flex:1;min-width:100px;">
            <label class="fl">Expected from</label>
            <input type="time" class="fi" id="wlogin-from" value="05:00" style="margin-bottom:0;" oninput="updRulePreviews()"/>
          </div>
          <div style="flex:1;min-width:100px;">
            <label class="fl">Expected by</label>
            <input type="time" class="fi" id="wlogin-earliest" value="08:00" style="margin-bottom:0;" oninput="updRulePreviews()"/>
          </div>
        </div>
        <div>
          <label class="fl">Enforcement level</label>
          <div style="display:flex;gap:8px;">
            <label style="flex:1;cursor:pointer;">
              <input type="radio" name="login-rule-radio" id="wlogin-mandatory" value="mandatory" onchange="updRulePreviews()" style="display:none;"/>
              <div id="wlogin-mandatory-box" style="border:2px solid var(--bd);padding:8px 10px;text-align:center;transition:all .2s;">
                <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--r);">Mandatory</div>
                <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Block — flag &amp; deny</div>
              </div>
            </label>
            <label style="flex:1;cursor:pointer;">
              <input type="radio" name="login-rule-radio" id="wlogin-recommended" value="recommended" onchange="updRulePreviews()" checked style="display:none;"/>
              <div id="wlogin-recommended-box" style="border:2px solid var(--y);background:rgba(255,205,17,.08);padding:8px 10px;text-align:center;transition:all .2s;">
                <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--y);">Recommended</div>
                <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Warn — allow &amp; note</div>
              </div>
            </label>
          </div>
        </div>
        <div id="wlogin-preview" style="font-size:11px;color:var(--g);margin-top:10px;padding:8px 10px;background:rgba(0,0,0,.15);border-left:2px solid rgba(255,205,17,.4);line-height:1.6;font-family:'Barlow Semi Condensed',sans-serif;"></div>
      </div>

      <!-- CHECKOUT WINDOW -->
      <div style="background:rgba(255,152,0,.04);border:1px solid rgba(255,152,0,.2);padding:12px 14px;" id="logout-rule-box">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;">
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--o);">Checkout Window</div>
          <span id="logout-rule-badge" style="font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:2px 8px;background:rgba(255,205,17,.15);color:var(--y);">Recommended</span>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;margin-bottom:10px;">
          <div style="flex:1;min-width:100px;">
            <label class="fl">Expected from</label>
            <input type="time" class="fi" id="wlogout-from" value="17:00" style="margin-bottom:0;" oninput="updRulePreviews()"/>
          </div>
          <div style="flex:1;min-width:100px;">
            <label class="fl">Latest by</label>
            <input type="time" class="fi" id="wlogout-latest" value="18:00" style="margin-bottom:0;" oninput="updRulePreviews()"/>
          </div>
        </div>
        <div>
          <label class="fl">Enforcement level</label>
          <div style="display:flex;gap:8px;">
            <label style="flex:1;cursor:pointer;">
              <input type="radio" name="logout-rule-radio" id="wlogout-mandatory" value="mandatory" onchange="updRulePreviews()" style="display:none;"/>
              <div id="wlogout-mandatory-box" style="border:2px solid var(--bd);padding:8px 10px;text-align:center;transition:all .2s;">
                <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--r);">Mandatory</div>
                <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Block — flag &amp; deny</div>
              </div>
            </label>
            <label style="flex:1;cursor:pointer;">
              <input type="radio" name="logout-rule-radio" id="wlogout-recommended" value="recommended" onchange="updRulePreviews()" checked style="display:none;"/>
              <div id="wlogout-recommended-box" style="border:2px solid var(--y);background:rgba(255,205,17,.08);padding:8px 10px;text-align:center;transition:all .2s;">
                <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--y);">Recommended</div>
                <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Warn — allow &amp; note</div>
              </div>
            </label>
          </div>
        </div>
        <div id="wlogout-preview" style="font-size:11px;color:var(--g);margin-top:10px;padding:8px 10px;background:rgba(0,0,0,.15);border-left:2px solid rgba(255,152,0,.4);line-height:1.6;font-family:'Barlow Semi Condensed',sans-serif;"></div>
      </div>

      <!-- SHIFT WINDOW (reference only) -->
      <div style="background:var(--surf2);border:1px solid var(--bd);border-left:3px solid var(--g);padding:10px 14px;margin-top:10px;">
        <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:10px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--g);margin-bottom:8px;">Shift Hours (Reference)</div>
        <div style="display:flex;gap:12px;flex-wrap:wrap;">
          <div style="flex:1;min-width:110px;">
            <label class="fl">Shift Starts</label>
            <input type="time" class="fi" id="wshift-start" value="06:00" style="margin-bottom:0;" oninput="updShiftPreview()"/>
          </div>
          <div style="flex:1;min-width:110px;">
            <label class="fl">Shift Ends</label>
            <input type="time" class="fi" id="wshift-end" value="17:00" style="margin-bottom:0;" oninput="updShiftPreview()"/>
          </div>
        </div>
        <div id="shift-window-preview" style="font-size:11px;color:var(--g);margin-top:8px;font-family:'Barlow Semi Condensed',sans-serif;">Shift runs 06:00 – 17:00 (11 hrs)</div>
      </div>
    </div>

    <div style="border-top:1px solid var(--bd);padding-top:14px;margin-top:14px;">
      <label style="display:flex;align-items:center;gap:8px;cursor:pointer;margin-bottom:12px;"><input type="checkbox" id="wisclerk" onchange="toggleClerkPIN()" style="accent-color:var(--o);width:14px;height:14px;"/><span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;color:var(--g);">Grant <span style="color:var(--o)">Site Clerk access</span> — this worker can switch to clerk mode from their employee dashboard</span></label>
      <div id="clerk-pin-wrap" style="display:none;">
        <label class="fl">Clerk PIN (4 digits — worker uses this to activate clerk mode)</label>
        <input class="fi" type="text" id="wclerkpin" maxlength="4" placeholder="e.g. 1234" inputmode="numeric" style="margin-bottom:0;letter-spacing:.3em;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;" oninput="this.value=this.value.replace(/\D/g,'')"/>
        <!-- TODO: clerkSite dropdown — scopes clerk to see only workers at assigned site -->
        <label class="fl" style="margin-top:10px;">Assigned Site (optional — leave blank for all sites)</label>
        <select class="fi" id="wclerksite" style="margin-bottom:0;">
          <option value="">All Sites</option>
        </select>
      </div>
    </div>

    <!-- MANAGER ACCESS -->
    <div style="border-top:1px solid var(--bd);padding-top:14px;margin-top:0;">
      <label style="display:flex;align-items:center;gap:8px;cursor:pointer;margin-bottom:12px;"><input type="checkbox" id="wismanager" onchange="toggleManagerFields()" style="accent-color:var(--pu);width:14px;height:14px;"/><span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;color:var(--g);">Grant <span style="color:var(--pu)">Manager access</span> — this worker gets a site-scoped dashboard and can excuse, dispute, and check workers in</span></label>
      <div id="manager-fields-wrap" style="display:none;flex-direction:column;gap:10px;">
        <div style="display:flex;gap:10px;flex-wrap:wrap;">
          <div style="flex:1;min-width:120px;">
            <label class="fl">Manager PIN (4 digits)</label>
            <input class="fi" type="text" id="wmanagerpin" maxlength="4" placeholder="e.g. 5678" inputmode="numeric" style="margin-bottom:0;letter-spacing:.3em;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;" oninput="this.value=this.value.replace(/\D/g,'')"/>
          </div>
          <div style="flex:2;min-width:160px;">
            <label class="fl">Assigned Site</label>
            <select class="fi" id="wmanagersite" style="margin-bottom:0;">
              <option value="">All sites (no restriction)</option>
            </select>
          </div>
        </div>
        <label style="display:flex;align-items:center;gap:8px;cursor:pointer;padding:8px 10px;background:rgba(167,139,250,.05);border:1px solid rgba(167,139,250,.2);">
          <input type="checkbox" id="wmanager-payroll" style="accent-color:var(--pu);width:14px;height:14px;"/>
          <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;color:var(--g);">Show <span style="color:var(--pu)">payroll cost estimate</span> on manager dashboard (default OFF — sensitive)</span>
        </label>
      </div>
    </div></div>
    <!-- ABSENCE ENTITLEMENT -->
    <div style="border-top:1px solid var(--bd);padding-top:14px;margin-top:14px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;">
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:14px;text-transform:uppercase;letter-spacing:.05em;">📋 Absence Entitlement</div>
        <label style="display:flex;align-items:center;gap:6px;cursor:pointer;">
          <input type="checkbox" id="wae-enabled" style="accent-color:var(--y);width:14px;height:14px;" onchange="toggleAEFields()"/>
          <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--g);">Enable</span>
        </label>
      </div>
      <div id="wae-fields" style="display:none;flex-direction:column;gap:10px;">
        <div style="font-size:12px;color:var(--g);margin-bottom:2px;">Set how many days this worker is entitled to be absent per period without penalty.</div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;">
          <div style="flex:1;min-width:80px;">
            <label class="fl">Days Allowed</label>
            <input type="number" class="fi" id="wae-days" value="3" min="0" max="365" style="margin-bottom:0;" oninput="updAEPreview()"/>
          </div>
          <div style="flex:2;min-width:120px;">
            <label class="fl">Per Period</label>
            <select class="fi" id="wae-period" style="margin-bottom:0;" onchange="updAEPreview()">
              <option value="week">Week</option>
              <option value="month" selected>Month</option>
              <option value="term">Term (3 months)</option>
              <option value="year">Year</option>
            </select>
          </div>
        </div>
        <div style="display:flex;gap:10px;flex-wrap:wrap;">
          <div style="flex:1;min-width:120px;">
            <label class="fl">Worker Type</label>
            <select class="fi" id="wae-type" style="margin-bottom:0;">
              <option value="permanent">Permanent</option>
              <option value="contract">Contract</option>
              <option value="daylabourer">Day Labourer</option>
            </select>
          </div>
          <div style="flex:2;min-width:140px;">
            <label class="fl">When Exceeded</label>
            <select class="fi" id="wae-exceed" style="margin-bottom:0;" onchange="updAEPreview()">
              <option value="flag">Flag only — log to disputes</option>
              <option value="unpaid">Flag + mark as unpaid</option>
              <option value="notify">Flag + notify via SMS</option>
            </select>
          </div>
        </div>
        <div id="wae-preview" style="font-size:11px;color:var(--g);padding:8px 10px;background:var(--bg);border-left:2px solid rgba(255,205,17,.3);line-height:1.6;font-family:'Barlow Semi Condensed',sans-serif;"></div>
      </div>
    </div>

    <!-- GEO-FENCE OVERRIDE -->
    <div style="border-top:1px solid var(--bd);padding-top:14px;margin-top:14px;">
      <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:14px;text-transform:uppercase;letter-spacing:.05em;margin-bottom:6px;">🛰 Geo-Fence Setting</div>
      <div style="font-size:12px;color:var(--g);margin-bottom:12px;">Override the global geo-fence setting for this specific worker. <span id="wgeo-global-note" style="color:var(--y);"></span></div>
      <div style="display:flex;gap:8px;flex-wrap:wrap;">
        <label id="wgeo-enable-lbl" style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="wgeo" id="wgeo-enable" value="enabled" onchange="updGeoPreview()" style="display:none;"/>
          <div class="geo-opt" id="wgeo-enable-box" style="border:2px solid var(--bd);padding:10px 14px;text-align:center;transition:all .2s;">
            <div style="font-size:16px;margin-bottom:3px;">🛰</div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--gr);">Enable</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Always required</div>
          </div>
        </label>
        <label id="wgeo-default-lbl" style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="wgeo" id="wgeo-default" value="default" onchange="updGeoPreview()" checked style="display:none;"/>
          <div class="geo-opt" id="wgeo-default-box" style="border:2px solid var(--y);padding:10px 14px;text-align:center;transition:all .2s;">
            <div style="font-size:16px;margin-bottom:3px;">⚙️</div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--y);">Default</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Follows global</div>
          </div>
        </label>
        <label id="wgeo-disable-lbl" style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="wgeo" id="wgeo-disable" value="disabled" onchange="updGeoPreview()" style="display:none;"/>
          <div class="geo-opt" id="wgeo-disable-box" style="border:2px solid var(--bd);padding:10px 14px;text-align:center;transition:all .2s;">
            <div style="font-size:16px;margin-bottom:3px;">📵</div>
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--r);">Disable</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Never required</div>
          </div>
        </label>
      </div>
      <div id="wgeo-preview" style="margin-top:10px;font-size:12px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;line-height:1.6;"></div>
    </div>

    <div class="ma"><button class="btn bout" onclick="cm('mw')">Cancel</button><button class="btn by" id="mw-save-btn" onclick="saveWorker()">Save Worker</button></div>
  </div>
</div>

<!-- PAYSHEET FILTER MODAL -->
<div class="mo" id="mps">
  <div class="md" style="max-width:480px;">
    <div class="mdt">🖨 Configure Paysheet Export</div>
    <div class="mds">Set filters then choose your export format.</div>

    <!-- Date range -->
    <div style="margin-bottom:14px;">
      <label class="fl">Date Range</label>
      <div style="display:flex;gap:8px;margin-bottom:8px;">
        <button class="btn bsm" id="psrange-week" onclick="setPsRange('week',this)" style="flex:1;background:var(--y);color:var(--bg);border:none;">This Week</button>
        <button class="btn bout bsm" id="psrange-month" onclick="setPsRange('month',this)" style="flex:1;">This Month</button>
        <button class="btn bout bsm" id="psrange-custom" onclick="setPsRange('custom',this)" style="flex:1;">Custom</button>
      </div>
      <div id="ps-custom-dates" style="display:none;gap:8px;">
        <div style="flex:1;"><label class="fl">From</label><input type="date" class="fi" id="ps-from" style="margin-bottom:0;" oninput="updPsPreview()"/></div>
        <div style="flex:1;"><label class="fl">To</label><input type="date" class="fi" id="ps-to" style="margin-bottom:0;" oninput="updPsPreview()"/></div>
      </div>
    </div>

    <!-- Site filter -->
    <div style="margin-bottom:14px;">
      <label class="fl">Filter by Site</label>
      <select class="fi" id="ps-site" style="margin-bottom:0;" onchange="updPsPreview()">
        <option value="">All Sites</option>
      </select>
    </div>

    <!-- Pay type filter -->
    <div style="margin-bottom:14px;">
      <label class="fl">Filter by Pay Type</label>
      <select class="fi" id="ps-paytype" style="margin-bottom:0;" onchange="updPsPreview()">
        <option value="">All Pay Types</option>
        <option value="hourly">Hourly Rate</option>
        <option value="daily">Daily Rate</option>
        <option value="weekly">Weekly Salary</option>
        <option value="monthly">Monthly Salary</option>
        <option value="piece">Piece Rate</option>
        <option value="day-overtime">Day Rate + Overtime</option>
        <option value="shift">Shift Rate</option>
        <option value="contract">Contract Rate</option>
      </select>
    </div>

    <!-- Absent workers -->
    <div style="margin-bottom:20px;background:var(--surf2);border:1px solid var(--bd);padding:12px 14px;">
      <label style="display:flex;align-items:center;gap:10px;cursor:pointer;">
        <input type="checkbox" id="ps-absent" style="accent-color:var(--y);width:16px;height:16px;" onchange="updPsPreview()"/>
        <div>
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;color:var(--ow);">Include absent workers</div>
          <div style="font-size:11px;color:var(--g);margin-top:2px;">Workers with no hours logged in the selected period will appear with 0 hours and no pay calculated.</div>
        </div>
      </label>
    </div>

    <!-- Preview count -->
    <div id="ps-preview-count" style="font-size:12px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;margin-bottom:14px;padding:8px 12px;background:var(--surf2);"></div>

    <div class="ma" style="flex-direction:column;gap:8px;">
      <div style="display:flex;gap:8px;width:100%;">
        <button class="btn by" style="flex:1;justify-content:center;" onclick="runPaysheetExport('excel')">⬇ Download Excel</button>
        <button class="btn bout" style="flex:1;justify-content:center;" onclick="runPaysheetExport('pdf')">⬇ Print PDF</button>
      </div>
      <button class="btn bout" style="width:100%;justify-content:center;" onclick="cm('mps')">Cancel</button>
    </div>
  </div>
</div>

<!-- WORKER INFO MODAL -->
<div class="mo" id="mwi">
  <div class="md" style="max-width:560px;">
    <div style="display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:20px;">
      <div style="display:flex;align-items:center;gap:14px;">
        <div id="wi-avatar" style="width:52px;height:52px;background:var(--pu);display:flex;align-items:center;justify-content:center;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:26px;color:var(--bg);flex-shrink:0;"></div>
        <div>
          <div id="wi-name" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:22px;text-transform:uppercase;letter-spacing:.04em;"></div>
          <div id="wi-role" style="font-size:12px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;margin-top:2px;"></div>
          <div id="wi-badges" style="display:flex;gap:6px;flex-wrap:wrap;margin-top:6px;"></div>
        </div>
      </div>
      <button onclick="cm('mwi')" style="background:transparent;border:1px solid var(--bd);color:var(--g);width:28px;height:28px;cursor:pointer;font-size:14px;flex-shrink:0;transition:all .2s;" onmouseover="this.style.borderColor='var(--r)';this.style.color='var(--r)'" onmouseout="this.style.borderColor='var(--bd)';this.style.color='var(--g)'">✕</button>
    </div>

    <!-- Sections -->
    <div style="display:flex;flex-direction:column;gap:14px;">

      <!-- Personal + Pay -->
      <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
        <div style="background:var(--surf2);padding:12px 14px;">
          <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;margin-bottom:8px;">Contact</div>
          <div id="wi-phone" style="font-size:13px;font-family:'Barlow Semi Condensed',sans-serif;"></div>
          <div id="wi-expected" style="font-size:11px;color:var(--g);margin-top:3px;"></div>
        </div>
        <div style="background:var(--surf2);padding:12px 14px;">
          <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;margin-bottom:8px;">Pay</div>
          <div id="wi-paytype" style="font-size:13px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;color:var(--ow);"></div>
          <div id="wi-rate" style="font-size:11px;color:var(--y);margin-top:3px;font-family:'Barlow Condensed',sans-serif;font-weight:900;"></div>
        </div>
      </div>

      <!-- Shift rules -->
      <div style="background:var(--surf2);padding:12px 14px;">
        <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;margin-bottom:8px;">⏰ Shift Rules</div>
        <div id="wi-shift" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;line-height:2;"></div>
      </div>

      <!-- Check-in history -->
      <div style="background:var(--surf2);padding:12px 14px;">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;">
          <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;">Recent Check-Ins</div>
          <div id="wi-reliability" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:18px;"></div>
        </div>
        <div id="wi-checkins" style="font-size:12px;"></div>
      </div>

      <!-- Excuse history -->
      <div style="background:var(--surf2);padding:12px 14px;">
        <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;margin-bottom:10px;">📋 Excuse History</div>
        <div id="wi-excuses" style="font-size:12px;"></div>
      </div>

      <!-- Make-Up Schedule -->
      <div style="background:var(--surf2);padding:12px 14px;">
        <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;margin-bottom:10px;">🔄 Compensation Days</div>
        <div id="wi-makeup" style="font-size:12px;"></div>
      </div>

      <!-- OT / Bonus Days -->
      <div style="background:var(--surf2);padding:12px 14px;">
        <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;margin-bottom:10px;">💰 OT &amp; Bonus Days</div>
        <div id="wi-otbonus" style="font-size:12px;"></div>
      </div>

      <!-- Absence Entitlement -->
      <div style="background:var(--surf2);padding:12px 14px;">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;">
          <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;">📊 Absence Entitlement</div>
          <div id="wi-ae-badge" style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:2px 8px;"></div>
        </div>
        <div id="wi-ae-content" style="font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;"></div>
      </div>

    </div>

    <!-- Actions hamburger menu -->
    <div style="display:flex;gap:8px;margin-top:16px;align-items:center;justify-content:space-between;flex-wrap:wrap;">
      <div style="font-size:10px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;">Worker record — read only. Use actions to make changes.</div>
      <div style="position:relative;" id="wi-actions-wrap">
        <button onclick="toggleWIActions()" id="wi-actions-btn" class="btn by bsm" style="display:flex;align-items:center;gap:6px;">
          ⚡ Actions <span id="wi-actions-chevron" style="font-size:10px;transition:transform .2s;">▼</span>
        </button>
        <div id="wi-actions-menu" style="display:none;position:absolute;bottom:calc(100% + 6px);right:0;min-width:200px;background:var(--surf);border:1px solid var(--bd);border-top:3px solid var(--y);z-index:1100;box-shadow:0 -8px 32px rgba(0,0,0,.5);">
          <button onclick="cm('mwi');editW(currentWIid)" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>✏️</span>Edit Worker</button>
          <button onclick="cm('mwi');openExcuseModal()" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>📋</span>Excuse This Worker</button>
          <button onclick="cm('mwi');openMakeupModalFor(currentWIid)" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>🔄</span>Compensation Days</button>
          <button onclick="cm('mwi');openOvertimeBonusFor(currentWIid)" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>💰</span>OT / Bonus Days</button>
          <button onclick="exportWorkerXl(currentWIid)" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;border-bottom:1px solid var(--bd);color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>⬇</span>Download Excel</button>
          <button onclick="exportWorkerPdf(currentWIid)" style="width:100%;text-align:left;padding:11px 16px;background:transparent;border:none;color:var(--ow);font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:10px;" onmouseover="this.style.background='rgba(255,255,255,.04)'" onmouseout="this.style.background='transparent'"><span>📄</span>Print PDF Report</button>
        </div>
      </div>

      <!-- ── WORKER NOTES ─────────────────────────────── -->
      <div style="border-top:1px solid var(--bd);padding:16px 0 0;margin-top:4px;">
        <div style="font-family:'Inter','Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--g);margin-bottom:10px;">📝 Internal Notes</div>
        <div id="wi-notes-list" style="display:flex;flex-direction:column;gap:6px;margin-bottom:10px;max-height:140px;overflow-y:auto;"></div>
        <div style="display:flex;gap:8px;align-items:flex-end;">
          <textarea id="wi-note-input" placeholder="Add a note about this worker..." style="flex:1;background:var(--surf2);border:1px solid var(--bd);color:var(--ow);font-family:'Inter','Barlow',sans-serif;font-size:12px;padding:9px 12px;border-radius:8px;outline:none;resize:none;min-height:60px;transition:border-color .15s;line-height:1.5;" onfocus="this.style.borderColor='var(--y)'" onblur="this.style.borderColor='var(--bd)'"></textarea>
          <button class="btn by bsm" onclick="saveWorkerNote()" style="height:38px;flex-shrink:0;border-radius:8px;">Save</button>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- OVERTIME / BONUS DAYS MODAL -->
<div class="mo" id="movertimebonus">
  <div class="md" style="max-width:560px;">
    <div class="mdt">💰 Overtime & Bonus Days</div>
    <div class="mds">Schedule overtime or bonus work days for workers. These are days worked above and beyond normal hours, with enhanced pay.</div>
    <div style="margin-bottom:16px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
        <label class="fl" style="margin-bottom:0;">Select Workers</label>
        <div style="display:flex;gap:8px;">
          <button class="btn bout bsm" onclick="obSelectAll()">Select All</button>
          <button class="btn bout bsm" onclick="obSelectNone()">Clear</button>
        </div>
      </div>
      <div id="ob-worker-list" style="background:var(--bg);border:1px solid var(--bd);max-height:160px;overflow-y:auto;"></div>
    </div>
    <div style="margin-bottom:14px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;flex-wrap:wrap;gap:8px;">
        <label class="fl" style="margin-bottom:0;">Select Days</label>
        <div style="display:flex;gap:6px;align-items:center;">
          <button class="btn bout bsm" onclick="obCalNav(-1)">← Prev</button>
          <span id="ob-cal-label" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;min-width:110px;text-align:center;"></span>
          <button class="btn bout bsm" onclick="obCalNav(1)">Next →</button>
        </div>
      </div>
      <div id="ob-cal-grid" style="background:var(--bg);border:1px solid var(--bd);padding:10px;user-select:none;"></div>
      <div id="ob-selected-dates" style="margin-top:8px;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);min-height:18px;"></div>
    </div>
    <div style="margin-bottom:14px;">
      <label class="fl">Pay Rate</label>
      <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;">
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="ob-pay" id="ob-standard" value="standard" onchange="updObPayBoxes()" checked style="display:none;"/>
          <div id="ob-standard-box" style="border:2px solid var(--y);background:rgba(255,205,17,.08);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--y);">1.5× OT</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Standard overtime rate</div>
          </div>
        </label>
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="ob-pay" id="ob-double" value="double" onchange="updObPayBoxes()" style="display:none;"/>
          <div id="ob-double-box" style="border:2px solid var(--bd);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--gr);">2× Double</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Sunday / public holiday</div>
          </div>
        </label>
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="ob-pay" id="ob-bonus" value="bonus" onchange="updObPayBoxes()" style="display:none;"/>
          <div id="ob-bonus-box" style="border:2px solid var(--bd);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--pu);">Bonus</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Custom flat bonus amount</div>
          </div>
        </label>
      </div>
      <div id="ob-bonus-field" style="display:none;">
        <label class="fl">Bonus Amount (R per day)</label>
        <input type="number" class="fi" id="ob-bonus-amount" placeholder="e.g. 800" min="0" style="margin-bottom:0;" oninput="updObPreview()"/>
      </div>
    </div>
    <div style="margin-bottom:14px;">
      <label class="fl">Note (optional)</label>
      <input class="fi" id="ob-note" placeholder="e.g. Weekend project push, public holiday work..." style="margin-bottom:0;"/>
    </div>
    <div id="ob-preview" style="display:none;background:var(--surf2);border:1px solid var(--bd);border-left:3px solid var(--pu);padding:10px 14px;font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;margin-bottom:16px;line-height:1.8;"></div>
    <div class="ma">
      <button class="btn bout" onclick="cm('movertimebonus')">Cancel</button>
      <button class="btn by" onclick="saveOvertimeBonus()">✓ Save OT / Bonus Days</button>
    </div>
  </div>
</div>

<!-- MAKE-UP SCHEDULE MODAL -->
<div class="mo" id="mmakeup">
  <div class="md" style="max-width:580px;">
    <div class="mdt">🔄 Make-Up Schedule</div>
    <div class="mds">Schedule make-up days for workers who have too many excused absences. Select workers, pick the dates they will work, and set their pay rate for those days.</div>

    <!-- WORKER SELECTION -->
    <div style="margin-bottom:16px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
        <label class="fl" style="margin-bottom:0;">Select Workers</label>
        <div style="display:flex;gap:8px;">
          <button class="btn bout bsm" onclick="mkSelectAll()">Select All</button>
          <button class="btn bout bsm" onclick="mkSelectNone()">Clear</button>
        </div>
      </div>
      <div id="mk-worker-list" style="background:var(--bg);border:1px solid var(--bd);max-height:160px;overflow-y:auto;"></div>
    </div>

    <!-- DATE PICKER GRID -->
    <div style="margin-bottom:14px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;flex-wrap:wrap;gap:8px;">
        <label class="fl" style="margin-bottom:0;">Select Make-Up Days</label>
        <div style="display:flex;gap:6px;align-items:center;">
          <button class="btn bout bsm" onclick="mkCalNav(-1)">← Prev</button>
          <span id="mk-cal-label" style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;min-width:110px;text-align:center;"></span>
          <button class="btn bout bsm" onclick="mkCalNav(1)">Next →</button>
        </div>
      </div>
      <div id="mk-cal-grid" style="background:var(--bg);border:1px solid var(--bd);padding:10px;user-select:none;"></div>
      <div id="mk-selected-dates" style="margin-top:8px;font-size:11px;font-family:'Barlow Semi Condensed',sans-serif;color:var(--g);min-height:18px;"></div>
    </div>

    <!-- PAY TREATMENT -->
    <div style="margin-bottom:14px;">
      <label class="fl">Pay Rate for Make-Up Days</label>
      <div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;">
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="mk-pay" id="mk-standard" value="standard" onchange="updMkPayFields()" checked style="display:none;"/>
          <div id="mk-standard-box" style="border:2px solid var(--y);background:rgba(255,205,17,.08);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--y);">Standard</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Normal rate applies</div>
          </div>
        </label>
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="mk-pay" id="mk-double" value="double" onchange="updMkPayFields()" style="display:none;"/>
          <div id="mk-double-box" style="border:2px solid var(--bd);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--gr);">Double Pay</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">2× their normal rate</div>
          </div>
        </label>
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="mk-pay" id="mk-custom" value="custom" onchange="updMkPayFields()" style="display:none;"/>
          <div id="mk-custom-box" style="border:2px solid var(--bd);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--pu);">Custom</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Set a specific amount</div>
          </div>
        </label>
      </div>
      <div id="mk-custom-field" style="display:none;">
        <label class="fl">Custom Pay Amount (R per day)</label>
        <input type="number" class="fi" id="mk-custom-amount" placeholder="e.g. 500" min="0" style="margin-bottom:0;" oninput="updMkPreview()"/>
      </div>
    </div>

    <!-- NOTE -->
    <div style="margin-bottom:14px;">
      <label class="fl">Note (optional)</label>
      <input class="fi" id="mk-note" placeholder="e.g. Making up 3 days missed in April..." style="margin-bottom:0;"/>
    </div>

    <!-- PREVIEW -->
    <div id="mk-preview" style="display:none;background:var(--surf2);border:1px solid var(--bd);border-left:3px solid var(--gr);padding:10px 14px;font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;margin-bottom:16px;line-height:1.8;"></div>

    <div class="ma">
      <button class="btn bout" onclick="cm('mmakeup')">Cancel</button>
      <button class="btn by" onclick="saveMakeup()">✓ Save Make-Up Schedule</button>
    </div>
  </div>
</div>

<!-- WORKER ALERT ACTION MODAL -->
<div class="mo" id="mworkeralert">
  <div class="md" style="max-width:520px;">
    <div class="mdt">⚠ Worker Reliability Alert</div>
    <div class="mds" id="walert-modal-desc">Select which workers to apply an action to.</div>
    <div style="margin-bottom:14px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
        <label class="fl" style="margin-bottom:0;">Flagged Workers</label>
        <div style="display:flex;gap:8px;">
          <button class="btn bout bsm" onclick="walertSelectAll()">Affect All Flagged</button>
          <button class="btn bout bsm" onclick="walertSelectNone()">Clear</button>
        </div>
      </div>
      <div id="walert-worker-list" style="background:var(--bg);border:1px solid var(--bd);max-height:200px;overflow-y:auto;"></div>
    </div>
    <div style="margin-bottom:14px;">
      <label class="fl">Action to apply</label>
      <select class="fi" id="walert-action" style="margin-bottom:0;">
        <option value="warn">Log a warning to disputes (no pay effect)</option>
        <option value="excuse-unpaid">Excuse absent days as unpaid leave</option>
        <option value="excuse-paid">Excuse absent days as paid leave</option>
        <option value="entitlement">Enable/update Absence Entitlement tracking</option>
        <option value="note">Add a note to their record only</option>
      </select>
    </div>
    <div style="margin-bottom:14px;">
      <label class="fl">Note / Reason</label>
      <input class="fi" id="walert-note" placeholder="e.g. Reliability below threshold — formal warning" style="margin-bottom:0;"/>
    </div>
    <div class="ma">
      <button class="btn bout" onclick="cm('mworkeralert')">Cancel</button>
      <button class="btn by" onclick="saveWorkerAlertAction()">Apply Action</button>
    </div>
  </div>
</div>

<!-- MANAGER DISMISS SUSPICIOUS MODAL -->
<div class="mo" id="mmgr-dismiss">
  <div class="md" style="max-width:480px;">
    <div class="mdt">🔧 Dismiss Suspicious Flag</div>
    <div class="mds">You are dismissing this flag for your site. A summary is required — the employer will see this flag archived with your note.</div>
    <div id="mmgr-dismiss-detail" style="background:var(--bg);border:1px solid var(--bd);padding:12px 14px;margin-bottom:14px;font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;line-height:1.8;"></div>
    <div style="margin-bottom:14px;">
      <label class="fl">Summary / Reason for dismissal <span style="color:var(--r);">*</span></label>
      <input class="fi" id="mgr-dismiss-note" placeholder="e.g. Verified with worker — code was accidentally reused, not intentional..." style="margin-bottom:0;"/>
    </div>
    <div class="ma">
      <button class="btn bout" onclick="cm('mmgr-dismiss')">Cancel</button>
      <button class="btn bpu" onclick="confirmMgrDismiss()">Dismiss &amp; Archive</button>
    </div>
  </div>
</div>

<!-- EXCUSE WORKERS MODAL -->
<div class="mo" id="mexc">
  <div class="md" style="max-width:560px;">
    <div class="mdt">📋 Excuse Workers</div>
    <div class="mds">Select workers and set the excuse period. Excused workers won't be flagged as absent. An SMS notification is queued for each excused worker.</div>
    <!-- WORKER SELECTION -->
    <div style="margin-bottom:16px;">
      <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
        <label class="fl" style="margin-bottom:0;">Select Workers</label>
        <div style="display:flex;gap:8px;">
          <button class="btn bout bsm" onclick="excSelectAll()">Select All</button>
          <button class="btn bout bsm" onclick="excSelectNone()">Clear</button>
        </div>
      </div>
      <div id="exc-worker-list" style="background:var(--bg);border:1px solid var(--bd);max-height:180px;overflow-y:auto;"></div>
    </div>
    <!-- DATE RANGE -->
    <div style="margin-bottom:14px;">
      <label class="fl">Date Range</label>
      <div style="display:flex;gap:8px;margin-bottom:8px;flex-wrap:wrap;">
        <button class="btn bsm" id="exc-today-btn" onclick="setExcRange('today',this)" style="background:var(--y);color:var(--bg);border:none;">Today</button>
        <button class="btn bout bsm" id="exc-custom-btn" onclick="setExcRange('custom',this)">Custom Range</button>
      </div>
      <div id="exc-date-row" style="display:none;gap:8px;flex-wrap:wrap;">
        <div style="flex:1;min-width:120px;"><label class="fl">From</label><input type="date" class="fi" id="exc-from" style="margin-bottom:0;" oninput="updExcPreview()"/></div>
        <div style="flex:1;min-width:120px;"><label class="fl">To</label><input type="date" class="fi" id="exc-to" style="margin-bottom:0;" oninput="updExcPreview()"/></div>
      </div>
    </div>
    <!-- RECURRING -->
    <div style="margin-bottom:14px;">
      <label style="display:flex;align-items:center;gap:8px;cursor:pointer;">
        <input type="checkbox" id="exc-recurring" style="accent-color:var(--y);width:14px;height:14px;" onchange="toggleExcRecurring()"/>
        <span style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;color:var(--ow);">Recurring excuse</span>
      </label>
      <div id="exc-recurring-opts" style="display:none;margin-top:10px;background:var(--surf2);border:1px solid var(--bd);padding:12px 14px;gap:12px;flex-wrap:wrap;">
        <div style="flex:1;min-width:120px;">
          <label class="fl">Repeat pattern</label>
          <select class="fi" id="exc-recur-pattern" style="margin-bottom:0;" onchange="updExcPreview()">
            <option value="week">Weekly (same days each week)</option>
            <option value="monday">Every Monday</option>
            <option value="friday">Every Friday</option>
          </select>
        </div>
        <div style="flex:1;min-width:100px;margin-top:10px;">
          <label class="fl">For how many weeks</label>
          <input type="number" class="fi" id="exc-recur-weeks" value="3" min="1" max="12" style="margin-bottom:0;" oninput="updExcPreview()"/>
        </div>
      </div>
    </div>
    <!-- PAY TREATMENT -->
    <div style="margin-bottom:14px;">
      <label class="fl">Pay Treatment</label>
      <div style="display:flex;gap:8px;flex-wrap:wrap;">
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="exc-pay" id="exc-unpaid" value="unpaid" onchange="updExcPayBoxes()" checked style="display:none;"/>
          <div id="exc-unpaid-box" style="border:2px solid var(--r);background:rgba(244,67,54,.08);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--r);">Unpaid</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">No pay for excused days</div>
          </div>
        </label>
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="exc-pay" id="exc-paid" value="paid" onchange="updExcPayBoxes()" style="display:none;"/>
          <div id="exc-paid-box" style="border:2px solid var(--bd);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--gr);">Paid</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">Full pay as normal</div>
          </div>
        </label>
        <label style="flex:1;min-width:80px;cursor:pointer;">
          <input type="radio" name="exc-pay" id="exc-halfday" value="halfday" onchange="updExcPayBoxes()" style="display:none;"/>
          <div id="exc-halfday-box" style="border:2px solid var(--bd);padding:10px;text-align:center;transition:all .2s;">
            <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:13px;text-transform:uppercase;color:var(--y);">Half Day</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">50% pay for excused days</div>
          </div>
        </label>
      </div>
    </div>
    <!-- REASON -->
    <div style="margin-bottom:14px;">
      <label class="fl">Reason (optional)</label>
      <input class="fi" id="exc-reason" placeholder="e.g. Sick leave, family emergency, site shutdown..." style="margin-bottom:0;"/>
    </div>

    <!-- EXCUSE TOGGLES -->
    <div style="margin-bottom:14px;display:flex;flex-direction:column;gap:8px;">
      <div style="background:var(--surf2);border:1px solid var(--bd);padding:10px 14px;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;">
        <div>
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;color:var(--ow);">Affects Reliability Score</div>
          <div style="font-size:11px;color:var(--g);margin-top:2px;">When ON, excused days still count against the worker's reliability. Turn OFF for protected absences (sick note, compassionate leave).</div>
        </div>
        <label style="flex-shrink:0;cursor:pointer;display:flex;align-items:center;gap:6px;margin-top:2px;">
          <input type="checkbox" id="exc-affects-rel" style="accent-color:var(--r);width:15px;height:15px;" onchange="updExcPreview()" checked/>
          <span id="exc-rel-label" style="font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--r);">ON</span>
        </label>
      </div>
      <div id="exc-pay-override-row" style="background:var(--surf2);border:1px solid var(--bd);padding:10px 14px;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;">
        <div>
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;color:var(--ow);">Pay Override</div>
          <div style="font-size:11px;color:var(--g);margin-top:2px;">Manually override whether pay is affected for this specific excuse — independent of the global pay rule. Use when a worker has exceeded entitlement but you still want to protect their pay.</div>
        </div>
        <label style="flex-shrink:0;cursor:pointer;display:flex;align-items:center;gap:6px;margin-top:2px;">
          <input type="checkbox" id="exc-pay-override" style="accent-color:var(--y);width:15px;height:15px;" onchange="updExcPreview()"/>
          <span id="exc-pay-override-label" style="font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--g);">OFF</span>
        </label>
      </div>
    </div>
    <!-- PREVIEW -->
    <div id="exc-preview" style="display:none;background:var(--surf2);border:1px solid var(--bd);border-left:3px solid var(--y);padding:10px 14px;font-size:12px;font-family:'Barlow Semi Condensed',sans-serif;margin-bottom:16px;line-height:1.8;"></div>
    <div class="ma">
      <button class="btn bout" onclick="cm('mexc')">Cancel</button>
      <button class="btn by" onclick="saveExcuses()">✓ Save Excuses</button>
    </div>
  </div>
</div>

<div class="mo" id="ms">
  <div class="md">
    <div class="mdt">Add Site</div>
    <div class="mds">Add a job site or project. Workers select this when logging hours.</div>
    <div><label class="fl">Site Name</label><input class="fi" id="snam" placeholder="e.g. Site A — Midrand" style="margin-bottom:0;"/></div>
    <div class="fg"><label class="fl">Description (optional)</label><input class="fi" id="sdesc" placeholder="Project details..." style="margin-bottom:0;"/></div>
    <div class="ma"><button class="btn bout" onclick="cm('ms')">Cancel</button><button class="btn by" onclick="saveSite()">Save Site</button></div>
  </div>
</div>

<!-- ADD DISPUTE MODAL -->
<div class="mo" id="mdisp">
  <div class="md">
    <div class="mdt">Add Dispute / Incident</div>
    <div class="mds">Logged with a timestamp. Use for warnings, payroll disputes, or attendance issues.</div>
    <div><label class="fl">Worker</label><select class="fi" id="dw" style="margin-bottom:0;"><option value="">Select worker...</option></select></div>
    <div class="fg"><label class="fl">Type</label>
      <select class="fi" id="dtype" style="margin-bottom:0;">
        <option value="dispute">Payroll Dispute</option><option value="attendance">Attendance Issue</option>
        <option value="incident">Site Incident</option><option value="warning">Verbal Warning</option><option value="note">Note</option>
      </select>
    </div>
    <div class="fg"><label class="fl">Details</label><input class="fi" id="ddet" placeholder="Describe the issue..." style="margin-bottom:0;"/></div>
    <div class="ma"><button class="btn bout" onclick="cm('mdisp')">Cancel</button><button class="btn by" onclick="saveDispute()">Save Entry</button></div>
  </div>
</div>

<div class="toast" id="toast"></div>

<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script>
// ══ VEE INDUSTRIAL — THEME ENGINE ══════════════════════════════════
// ── 4-STAGE LUMINANCE SYSTEM ──
const STAGES=['day','dusk','dusk-dark','night'];
const STAGE_ICONS={'day':'☀️','dusk':'🌤','dusk-dark':'🌙','night':'🌑'};
const STAGE_LABELS={'day':'Day','dusk':'Dusk','dusk-dark':'Dusk Dark','night':'Night'};
const _savedStage=localStorage.getItem('vee-stage');
let currentStage=(STAGES.includes(_savedStage)?_savedStage:'night');
let pendingStage=currentStage;
// Legacy compat — keep these so existing code doesn't break
let currentView='base', pendingView='base', currentDark=true, pendingDark=true;

function applyTheme(view,dark){
  // Legacy wrapper — just applies current stage
  applyStage(currentStage);
}

function applyStage(stage){
  document.body.classList.remove('stage-day','stage-dusk','stage-dusk-dark','stage-night');
  document.body.classList.add('stage-'+stage);
  // Update topbar stage button
  const btn=document.getElementById('topbar-stage-btn');
  const icon=document.getElementById('topbar-stage-icon');
  const lbl=document.getElementById('topbar-stage-label');
  if(icon)icon.textContent=STAGE_ICONS[stage]||'🌑';
  if(lbl)lbl.textContent=STAGE_LABELS[stage]||'Night';
  // Update view-sel stage cards
  document.querySelectorAll('.vs-stage').forEach(c=>{
    c.classList.toggle('sel',c.getAttribute('data-stage')===stage);
  });
}

function cycleStage(){
  const idx=STAGES.indexOf(currentStage);
  currentStage=STAGES[(idx+1)%STAGES.length];
  localStorage.setItem('vee-stage',currentStage);
  applyStage(currentStage);
}


function selView(v,el){
  // Legacy — no-op, stages handle this now
}

function selStage(stage,el){
  pendingStage=stage;
  document.querySelectorAll('.vs-stage').forEach(c=>c.classList.remove('sel'));
  if(el)el.classList.add('sel');
  applyStage(pendingStage);
}

function selDark(mode,el){
  // Legacy wrapper — maps to nearest stage
  pendingDark=(mode==='dark');
  if(pendingDark && ['day','dusk'].includes(pendingStage))pendingStage='night';
  if(!pendingDark && ['night','dusk-dark'].includes(pendingStage))pendingStage='day';
  applyStage(pendingStage);
}

function confirmView(){
  currentStage=pendingStage;
  localStorage.setItem('vee-stage',currentStage);
  localStorage.setItem('vee-seen','1');
  applyStage(currentStage);
  document.getElementById('view-sel').classList.add('hidden');
  _startApp();
}

function openViewSel(){
  pendingStage=currentStage;
  document.querySelectorAll('.vs-stage').forEach(c=>{
    c.classList.toggle('sel',c.getAttribute('data-stage')===pendingStage);
  });
  document.getElementById('view-sel').classList.remove('hidden');
  applyStage(pendingStage);
}

function toggleDark(){
  // Cycles between day and night quickly
  currentStage=(currentStage==='night')?'day':'night';
  localStorage.setItem('vee-stage',currentStage);
  applyStage(currentStage);
}

// ── SIDEBAR EXPAND/COLLAPSE ──────────────────────────────────────
function toggleSidebar(){
  const closed=document.body.classList.toggle('sb-closed');
  localStorage.setItem('vee-sidebar',closed?'closed':'open');
}
function initSidebar(){
  if(localStorage.getItem('vee-sidebar')==='closed')
    document.body.classList.add('sb-closed');
}

function initTheme(){
  applyStage(currentStage);
  initSidebar();
}

function showViewSelector(){
  if(localStorage.getItem('vee-seen')){return;}
  pendingStage=currentStage;
  document.getElementById('view-sel').classList.remove('hidden');
  applyStage(pendingStage);
}
let tipTimer=null;
const TIP=document.getElementById('vee-tip');
const TIP_TITLE=document.getElementById('vee-tip-title');
const TIP_BODY=document.getElementById('vee-tip-body');

function showTip(el,x,y){
  const raw=el.getAttribute('data-vee-tip');
  if(!raw)return;
  const sep=raw.indexOf('|');
  const title=sep>-1?raw.slice(0,sep):raw;
  const body=sep>-1?raw.slice(sep+1):'';
  TIP_TITLE.textContent=title;
  TIP_BODY.textContent=body;
  // Position logic — default bottom-right corner area
  const vw=window.innerWidth,vh=window.innerHeight;
  const tipW=230,tipH=70;
  // Corner proximity check — if within 120px of bottom-right, shift
  let left,top;
  const nearRight=x>vw-160;
  const nearBottom=y>vh-160;
  if(nearRight&&nearBottom){left=vw-tipW-24;top=vh-tipH-80;}
  else if(nearRight){left=x-tipW-12;top=y+12;}
  else if(nearBottom){left=x+12;top=y-tipH-12;}
  else{left=x+16;top=y+16;}
  // Keep on screen
  left=Math.max(8,Math.min(left,vw-tipW-8));
  top=Math.max(8,Math.min(top,vh-tipH-8));
  TIP.style.left=left+'px';TIP.style.top=top+'px';
  TIP.classList.add('show');
}

function hideTip(){clearTimeout(tipTimer);TIP.classList.remove('show');}

document.addEventListener('mouseover',e=>{
  const el=e.target.closest('[data-vee-tip]');
  if(!el){hideTip();return;}
  clearTimeout(tipTimer);
  tipTimer=setTimeout(()=>showTip(el,e.clientX,e.clientY),1500);
});
document.addEventListener('mouseout',e=>{
  if(!e.target.closest('[data-vee-tip]'))hideTip();
});
document.addEventListener('mousemove',e=>{
  if(TIP.classList.contains('show')){
    const vw=window.innerWidth,vh=window.innerHeight;
    const tipW=230,tipH=70;
    let left=e.clientX+16,top=e.clientY+16;
    left=Math.max(8,Math.min(left,vw-tipW-8));
    top=Math.max(8,Math.min(top,vh-tipH-8));
    TIP.style.left=left+'px';TIP.style.top=top+'px';
  }
});
document.addEventListener('click',hideTip);

// ══ HELP SYSTEM ══════════════════════════════════════════════════
const HELP={
  dashboard:[
    {icon:'⚡',label:'Payroll Health Score',desc:'0–10 dial calculated from log rate, open disputes, suspicious flags, and worker reliability. Below 6 = something needs fixing before payroll runs.'},
    {icon:'📊',label:'Stats Row',desc:'Workers on books, logged today, not logged (excused excluded), and clerk check-ins. "Not Logged" is your daily action list.'},
    {icon:'⚠',label:'Worker Alerts Panel',desc:'Auto-appears when any worker drops below 60% reliability. Click Take Action to excuse, warn, or log a dispute for flagged workers. Affect All Flagged applies to everyone at once.'},
    {icon:'📋',label:"Today's Entries",desc:'Every worker status for today. Green ✓ Logged. Yellow 📋 Excused. Red ✗ Not Logged. Use arrows to view any past day.'},
    {icon:'📍',label:'Hours by Site',desc:'Bar chart ranking sites by hours today. A site that goes quiet mid-day is worth investigating.'},
  ],
  checkin:[
    {icon:'👤',label:'Code Generator (Employer)',desc:'Select a worker to see their green check-in code AND orange checkout code. Two different codes — morning code cannot be reused for checkout.'},
    {icon:'⚠',label:'Bypass Checkboxes',desc:'Override time windows per worker. Recommended rule = bypasses silently (logged suspicious). Mandatory rule = shows an acknowledgement panel you must confirm before proceeding.'},
    {icon:'✓',label:'Check-In Tab (Clerk)',desc:'Enter the 6-digit code the worker shows on their phone. Green = approved, yellow = already used, red = blocked. Flagged entries show ⚠ in the log.'},
    {icon:'←',label:'Checkout Tab (Clerk)',desc:'Uses a completely different 6-digit code from check-in. Calculates actual hours from check-in time to now. Blocks if no check-in exists.'},
    {icon:'⏰',label:'Site-Wide Time Window',desc:'Global check-in window. Individual worker windows set in Edit Worker override this per worker. Set 00:00–23:59 to disable for testing.'},
    {icon:'📋',label:'Activity Log',desc:'All check-ins and checkouts today: Worker, Type, Time, Code, Who did it, Status. Flagged entries show ⚠ next to the worker name.'},
  ],
  workers:[
    {icon:'⚡',label:'Actions Dropdown',desc:'Excuse Workers, Compensation Days, OT/Bonus Days, Geo-Fence toggle, Add Worker — all in one place.'},
    {icon:'✏️',label:'Edit Worker',desc:'Set pay type, rate, shift hours, check-in window (From→By), checkout window (From→Latest), enforcement level (Recommended/Mandatory), geo-fence, clerk access, and manager access.'},
    {icon:'🔐',label:'Clerk Badge',desc:'This worker can activate Clerk mode from the Employee tab using their 4-digit PIN to process check-ins.'},
    {icon:'🔧',label:'Manager Badge',desc:'This worker can access the Manager portal with their PIN to view site stats, excuse workers, log disputes, and dismiss suspicious flags.'},
    {icon:'📊',label:'Reliability Score',desc:'0–100% based on logged days vs expected. Protected excuses (Affects Reliability OFF) count as attended. Below 60% triggers a Worker Alert on the dashboard.'},
    {icon:'🔄',label:'Compensation Days',desc:'Schedule make-up days for workers with too many absences. Standard / Double / Custom pay. Shown in worker info history.'},
    {icon:'💰',label:'OT / Bonus Days',desc:'Log overtime (1.5×), double pay (2×), or flat bonus days. Completely separate from Compensation. Both appear in worker info.'},
  ],
  sites:[
    {icon:'📍',label:'Add Site',desc:'Create a job site. Workers and managers are scoped to sites. Hours per site appear in the dashboard bar chart and paysheet filter.'},
    {icon:'🔧',label:'Manager Site Scope',desc:'When you assign a manager to a site in Edit Worker, they only see workers and suspicious flags for that site.'},
  ],
  disputes:[
    {icon:'📝',label:'Dispute Log',desc:'Timestamped record of payroll disputes, warnings, attendance issues. Auto-populated when entitlement is exceeded. Legally defensible evidence.'},
    {icon:'🔴',label:'Status',desc:'Open = unresolved. Resolved = handled. Escalated = needs further action. Open disputes reduce the Payroll Health Score.'},
  ],
  export:[
    {icon:'📥',label:'Quick Export',desc:'Today\'s payroll for all real workers as Excel or PDF. Test workers excluded. Check "Not Logged" on dashboard before exporting.'},
    {icon:'🔽',label:'Configure & Export',desc:'Filter by date range, site, pay type. Include/exclude absent workers. Preview count before downloading.'},
  ],
  suspicious:[
    {icon:'🚨',label:'Active Flags',desc:'Every invalid code, duplicate, bypass, geo-fail, and window violation. Each shows worker, type, time, code, site, and who logged it.'},
    {icon:'🗂',label:'Archived (Manager Dismissed)',desc:'Click "Show ▼" to see flags a manager dismissed for their site. Greyed out with manager name, time, and their written summary visible on hover.'},
    {icon:'🟣',label:'Portal / Logged By',desc:'Each entry shows exactly which portal and which person triggered it — employer, manager, clerk by name, or system.'},
  ],
  calendar:[
    {icon:'📅',label:'Leave Calendar',desc:'Month grid — workers as rows, days as columns. Red=unpaid, Green=paid, Yellow=half-day, Purple=pay override, Dashed=reliability protected.'},
    {icon:'📊',label:'Entitlement Bars',desc:'Below the grid — days used vs allowed per worker. Green under 75%, orange approaching, red exceeded. ⚠ exceeded auto-creates a dispute.'},
  ],
  demo:[
    {icon:'⚡',label:'Generate Workers',desc:'Step 1: Creates test workers. Worker 1 = Clerk (PIN: 1234). Worker 2 = Manager (PIN: 5678). All 4 check-in rule combinations covered.'},
    {icon:'🕐',label:'Demo Time Override',desc:'Simulate any time of day to test window enforcement. 3:50 AM = before window. 9:30 AM = after window closes. 5–6 PM = checkout window test.'},
    {icon:'⏰',label:'Check-In Window',desc:'Also on the Live Check-In page now. Individual windows set per worker in Edit Worker override this global setting.'},
  ],
  employee:[
    {icon:'🔑',label:'Daily Check-In Code',desc:'Your unique 6-digit code. Show it to the gate clerk. Resets at midnight. A separate checkout code also exists — the employer shows both.'},
    {icon:'✅',label:'Status Card',desc:'Shows whether you are checked in, not yet in, or excused today with full excuse details.'},
    {icon:'🔐',label:'Clerk Mode',desc:'If your employer enabled it, "Switch to Clerk Mode" appears. Enter your 4-digit PIN to start processing check-ins for other workers.'},
    {icon:'🔧',label:'Manager Access',desc:'If you are a manager, a purple banner appears. Click "Go to Manager Portal" to switch to your site dashboard.'},
  ],
  manager:[
    {icon:'🔧',label:'Manager Dashboard',desc:'Site-scoped view. Stats show only your assigned site: checked in, not logged, hours, suspicious flags, and optionally payroll cost estimate.'},
    {icon:'👷',label:'Worker Status List',desc:'Every worker at your site with real-time status: ✓ In, ← Out, 📋 Excused, ✗ Not In. Includes reliability score and hours today.'},
    {icon:'🚨',label:'Dismiss Suspicious Flag',desc:'Click "Dismiss ✓" on any active flag. You must write a summary note. The employer sees it archived with your name, time, and note on hover.'},
    {icon:'⚡',label:'Manager Actions',desc:'Excuse workers, log disputes, schedule compensation or OT days, and check workers in/out — all scoped to your site.'},
  ],
};

let helpOpen=false;
let currentHelpPage='dashboard';

function getHelpPage(){
  const activePg=document.querySelector('.pg.active');
  if(activePg){const id=activePg.id.replace('pg-','');if(HELP[id])return id;}
  const mgrView=document.getElementById('pv-manager');
  if(mgrView?.classList.contains('active'))return'manager';
  const empView=document.getElementById('pv-employee');
  if(empView?.classList.contains('active'))return'employee';
  return'dashboard';
}

function toggleHelp(){
  helpOpen=!helpOpen;
  const panel=document.getElementById('vee-help-panel');
  panel.classList.toggle('open',helpOpen);
  if(helpOpen)renderHelp();
}

function renderHelp(){
  const page=getHelpPage();
  currentHelpPage=page;
  const items=HELP[page]||HELP.dashboard;
  const titles={dashboard:'Dashboard',checkin:'Live Check-In',workers:'Workers',sites:'Sites',disputes:'Dispute Log',export:'Payroll Export',suspicious:'Suspicious Activity',smsschedule:'SMS Scheduler',demo:'Demo Controls',employee:'Employee Portal'};
  document.getElementById('help-title').textContent=(titles[page]||'Help')+' — Quick Guide';
  document.getElementById('help-body').innerHTML=items.map(h=>`<div class="help-item"><div class="help-icon">${h.icon}</div><div class="help-text"><div class="help-label">${h.label}</div><div class="help-desc">${h.desc}</div></div></div>`).join('');
}

// Close help when clicking outside
document.addEventListener('click',e=>{
  if(helpOpen&&!e.target.closest('#vee-help-panel')&&!e.target.closest('#vee-help')){
    helpOpen=false;document.getElementById('vee-help-panel').classList.remove('open');
  }
});

// ══ BOOT ═════════════════════════════════════════════════════════
// ══ GUIDED TUTORIAL ══════════════════════════════════════════════
const TUT_STEPS=[
  // ══ EMPLOYER VIEW ══════════════════════════════════════════════
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Welcome',page:'dashboard',target:null,arrow:null,
    title:'Welcome to Vee Industrial V0.1',
    what:'A complete workforce tracking and payroll system built for earthmoving, construction, and mining in South Africa.',
    does:'Four portals in one: Employer (full control), Manager (site oversight), Employee (worker self-service), and Clerk (gate check-in). This tour walks through each role in order.',
    how:'Tutorial data has been loaded automatically — 5 test workers, 3 sites, and a full month of hours. Everything resets when you finish or exit the tour.',
    more:'The system tracks check-in and checkout with unique per-direction codes, enforces time windows per worker, logs all suspicious activity with full detail, and exports clean payroll-ready Excel and PDF files.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Dashboard',page:'dashboard',target:'.hsc',arrow:'right',
    title:'Payroll Health Score',
    what:'A 0–10 live dial showing how clean your payroll operation is right now.',
    does:'Calculates from hours logged vs expected, open disputes, suspicious flags, average reliability, and whether sites are configured. Red below 5, yellow 5–7, green above 7.',
    how:'Check this first every morning. Below 6 means something needs fixing before payroll runs. Click through to Disputes or Suspicious to find the cause.',
    more:'The four breakdown bars below the dial show exactly which factor is dragging the score down. Fix the lowest bar first.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Dashboard',page:'dashboard',target:'.sr',arrow:'down',
    title:'Worker Reliability Alerts',
    what:'Auto-appears when any worker drops below 60% reliability. Your early-warning system.',
    does:'Shows each flagged worker with their score, days missed, and a Take Action button. The action modal lets you select which workers to apply an action to — warn, excuse, log a dispute, or add a note. "Affect All Flagged" applies to everyone at once.',
    how:'Use this weekly, not just when it appears. Run Demo Step 3B to fill a month of data — some workers will miss days — then come back to the dashboard to see it in action.',
    more:'Actions from this panel go straight to the dispute log and/or excuse records. The reliability score updates immediately after.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Dashboard',page:'dashboard',target:'#etb',arrow:'up',
    title:"Today\'s Entries Table",
    what:'Every worker\'s status for today — the core of your daily payroll view.',
    does:'Green ✓ Logged, Yellow 📋 Excused, Red ✗ Not Logged. Shows reliability score, pay type, hours, estimated pay, site. Excused workers show their pay treatment. Navigation arrows let you view any past day.',
    how:'Scan at end of day. Every worker must be accounted for — either logged, excused, or you need to investigate. Export only after this table is complete.',
    more:'The "Not Logged" count in the stat cards above excludes excused workers. That number is your real action list for the day.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Live Check-In',page:'checkin',target:'#ci-sel',arrow:'down',
    title:'Check-In & Checkout Codes',
    what:'Every worker gets TWO codes per day — a green check-in code and an orange checkout code.',
    does:'Generated from different salts so they\'re always different. The morning check-in code cannot be reused for checkout — prevents workers from clocking out early with their morning code.',
    how:'Select a worker from the dropdown. Both codes appear immediately. Workers show the relevant code on their phone to the clerk. The clerk never sees the code — they confirm the action.',
    more:'Codes are deterministic — same worker, same day, same code every time. No network needed to verify. Codes reset at midnight.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Live Check-In',page:'checkin',target:'.ci-split',arrow:'down',
    title:'Bypass Time Windows',
    what:'Override check-in or checkout time windows directly from the code generator when needed.',
    does:'Two checkboxes appear under the worker info — one for check-in, one for checkout. If the worker\'s rule is Recommended: bypasses silently and logs to suspicious activity. If Mandatory: an acknowledgement panel appears requiring your explicit confirmation before proceeding.',
    how:'Use bypass when a worker arrives genuinely early for legitimate reasons. Always logged — the employer can see exactly who bypassed, when, which site, and what the reason was.',
    more:'The suspicious activity log records: worker name, clerk/employer name, time, site, code used, action type, and portal. Nothing is hidden from the employer.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Workers',page:'workers',target:'#worker-actions-btn',arrow:'down',
    title:'Actions Dropdown',
    what:'All bulk worker actions in one clean menu — no scattered buttons.',
    does:'Contains: Excuse Workers (bulk date range with pay treatment), Compensation Days (make-up schedule with calendar picker), OT/Bonus Days (overtime and flat bonuses), Geo-Fence toggle, and Add Worker.',
    how:'Open ⚡ Actions first whenever you need to do anything to multiple workers at once. For single worker actions, use the ⚡ Actions button inside the Worker Info modal instead.',
    more:'The geo-fence toggle affects all workers set to "Default". Workers with individual overrides (Always ON or Always OFF) ignore the global toggle.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Workers',page:'workers',target:'#wgrid',arrow:'down',
    title:'Worker Grid',
    what:'Your full workforce at a glance — reliability, pay type, badges, and status for every worker.',
    does:'Each tile shows avatar, name, role, pay type badge, geo-fence badge, Clerk or Manager badge if assigned, excused status today, reliability score with colour dot, and absence entitlement bar if enabled.',
    how:'Red dot below 60% = Worker Alert territory. Blue 🔐 Clerk badge = this worker can process gate check-ins. Purple 🔧 Mgr badge = this worker has manager portal access. Click ℹ for full profile.',
    more:'Worker tiles update in real time as hours are logged, excuses are added, and check-ins happen. No refresh needed.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Workers',page:'workers',target:'#wgrid',arrow:'down',
    title:'Add / Edit Worker — Check-In Windows',
    what:'Every worker has their own check-in window (From → By) and checkout window (From → Latest) with individual enforcement levels.',
    does:'Check-In Window e.g. 05:00–08:00: worker must arrive in this range. Checkout Window e.g. 17:00–18:00: worker must leave in this range. Recommended = warn and log if outside. Mandatory = block and log.',
    how:'Default is Recommended for both directions. Change to Mandatory only for high-security or high-accountability roles. The preview text below each section shows exactly what will happen at runtime.',
    more:'Manager and Clerk access are also set here — enable isManager, set their PIN and assigned site. Enable isClerk and set their PIN for gate clerk access.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Export',page:'export',target:'#exprev',arrow:'down',
    title:'Payroll Export',
    what:'One-click today\'s payroll or configure a full filtered paysheet.',
    does:'Quick Export: Excel and PDF for today, all real workers, test workers excluded. Configure & Export: filter by date range (This Week, This Month, or custom), site, pay type, include/exclude absent workers.',
    how:'Always check dashboard "Not Logged" count before exporting. Export after all workers are accounted for. Use "Configure & Export" for weekly runs and per-site job costing invoices.',
    more:'The Excel output has clean divider rows between worker groups. PDF is print-ready. Per-worker Excel and PDF are available inside each worker\'s info modal.'
  },
  {
    role:'employer',segment:'🏢 Employer View',
    category:'Security',page:'suspicious',target:'#susplist',arrow:'down',
    title:'Suspicious Activity Log',
    what:'Every security event logged automatically — your fraud detection layer.',
    does:'Tracks: invalid codes, duplicate codes (buddy punching), time window violations, geo-fence failures, bypass overrides (both Recommended and Mandatory), and manager check-in flags. Each entry shows worker, type, time, site, code, who logged it, and which portal.',
    how:'Review daily before finalising hours. A pattern of duplicate codes from the same worker = investigate. Geo-fence failures = verify location. Mandatory bypasses = review with the manager who approved it.',
    more:'Managers can dismiss flags for their site — those appear greyed out in an archived section below. Hover the "Archived by [name]" badge to see the manager\'s written reason.'
  },
  // ══ TRANSITION ══════════════════════════════════════════════════
  {
    role:'transition',segment:'Switching Roles',
    category:'Switching to Manager',page:'dashboard',target:null,arrow:null,
    title:'Now: Manager View 🔧',
    what:'Switching to the Manager portal — a site-scoped dashboard for on-the-ground supervisors.',
    does:'The Manager sees only their assigned site\'s data. They can check workers in and out, excuse workers, log disputes, and dismiss suspicious flags — but cannot access payroll exports, global worker settings, or other sites.',
    how:'In the demo, Test Worker 2 is the Manager (PIN: 5678). Click the 🔧 Manager tab at the top to proceed.',
    more:''
  },
  // ══ MANAGER VIEW ════════════════════════════════════════════════
  {
    role:'manager',segment:'🔧 Manager View',
    category:'Manager',page:'dashboard',target:'#sidebar-portals',arrow:'down',
    title:'Manager Portal Access',
    what:'The Manager tab sits between Employer and Worker. Activated by selecting a name and entering a 4-digit PIN.',
    does:'After PIN verification, the manager sees a site-scoped dashboard: checked in count, not logged, hours today, suspicious flags for their site, and optionally payroll cost estimate (employer controls this toggle per manager).',
    how:'In the demo: click the 🔧 Manager tab → select Test Worker 2 → enter PIN 5678. The dashboard loads scoped to that manager\'s assigned site.',
    more:'Managers can also access the portal from inside the Employee tab — selecting themselves shows a purple "Manager Access Available" banner with a direct link.'
  },
  {
    role:'manager',segment:'🔧 Manager View',
    category:'Manager',page:'dashboard',target:'#mgr-dashboard',arrow:'right',
    title:'Site Worker List',
    what:'Real-time status of every worker at the manager\'s site — no global worker data exposed.',
    does:'Each row shows the worker\'s name, role, reliability score, hours logged today, and live status: ✓ In, ← Out, 📋 Excused, or ✗ Not In. Updates instantly as check-ins and checkouts happen.',
    how:'Use this throughout the day to track site attendance. If a worker shows ✗ Not In past start time, you can check them in directly from the Manager Actions panel below.',
    more:'Workers shown here are those who have logged hours at this site, or all workers if the manager has no site restriction. Reliability scores are calculated identically to the employer view.'
  },
  {
    role:'manager',segment:'🔧 Manager View',
    category:'Manager',page:'dashboard',target:'#mgr-susp-panel',arrow:'up',
    title:'Site Suspicious Flags & Dismissal',
    what:'Active suspicious flags scoped to this manager\'s site — with the ability to dismiss and archive them.',
    does:'Each active flag shows type, worker, note, time, and who logged it. Clicking "Dismiss ✓" opens a modal requiring a written summary. Once dismissed, the flag moves to the employer\'s archived section — greyed out with the manager\'s name, time, and summary visible on hover.',
    how:'Write a clear, factual summary when dismissing. The employer sees everything — the original flag data AND your note. This is a record, not a deletion.',
    more:'Managers can dismiss all flag types with a mandatory summary. The employer can always expand the archive to review what was dismissed and why.'
  },
  // ══ TRANSITION ══════════════════════════════════════════════════
  {
    role:'transition',segment:'Switching Roles',
    category:'Switching to Clerk',page:'dashboard',target:null,arrow:null,
    title:'Now: Clerk View 🔐',
    what:'Switching to the Site Clerk portal — the gate guard\'s interface for processing check-ins and checkouts.',
    does:'The Clerk never sees any codes. They select a worker, choose In or Out, confirm the time window status, and submit. The system generates and validates the code internally. All bypasses require explicit acknowledgement.',
    how:'In the demo, Test Worker 1 is the Clerk (PIN: 1234). Click the 👷 Worker tab, select Test Worker 1, then click "Switch to Clerk Mode".',
    more:''
  },
  // ══ CLERK VIEW ══════════════════════════════════════════════════
  {
    role:'clerk',segment:'🔐 Clerk View',
    category:'Clerk',page:'dashboard',target:'#sidebar-portals',arrow:'down',
    title:'Activating Clerk Mode',
    what:'Clerk mode lives inside the Worker/Employee tab — clerks are workers who have been granted gate access by the employer.',
    does:'Select your name → a orange "Site Clerk Access Granted" banner appears → click "Switch to Clerk Mode" → enter your 4-digit PIN. Clerk mode activates with a different interface designed for fast gate processing.',
    how:'Demo: click 👷 Worker tab → select Test Worker 1 → click Switch to Clerk Mode → enter PIN 1234.',
    more:'Clerks only see their own daily code in the Employee view. The clerk interface shows no codes at all — designed for security so clerks cannot pre-learn codes.'
  },
  {
    role:'clerk',segment:'🔐 Clerk View',
    category:'Clerk',page:'dashboard',target:'#clerk-worker-sel',arrow:'down',
    title:'Clerk Check-In Flow',
    what:'A step-by-step interface: select worker → choose direction → see time window status → confirm.',
    does:'Step 1: Select the worker from the dropdown. Step 2: Choose ✓ Check In or ← Check Out. Step 3: A status indicator shows ✅ in-window or ❌ outside-window with the exact window times and enforcement level. Step 4: If in window → Confirm button appears. If outside → bypass checkbox appears.',
    how:'The worker tells you their name. You select it. You never ask for or see a code number. The confirm button is large and clear — designed for fast gate processing on a tablet.',
    more:'If the bypass checkbox is ticked on a Mandatory-rule worker, a second confirmation appears: "I acknowledge — this will be logged to suspicious activity." Both must be confirmed before submit.'
  },
  // ══ TRANSITION ══════════════════════════════════════════════════
  {
    role:'transition',segment:'Switching Roles',
    category:'Switching to Employee',page:'dashboard',target:null,arrow:null,
    title:'Now: Employee / Worker View 👷',
    what:'Switching to the Employee portal — what each worker sees on their own phone.',
    does:'Workers see their daily check-in code (large, easy to read), their check-in status for today, any excuse notice from the employer, and their hours logged this week.',
    how:'Click the 👷 Worker tab and select any worker to see their personal view.',
    more:''
  },
  // ══ EMPLOYEE VIEW ═══════════════════════════════════════════════
  {
    role:'employee',segment:'👷 Employee View',
    category:'Employee',page:'dashboard',target:'#emp-code-val',arrow:'up',
    title:'Worker\'s Daily Check-In Code',
    what:'The worker\'s unique 6-digit check-in code — the only thing they need to enter work each day.',
    does:'Large, high-contrast number designed to be read at arm\'s length. Valid today only — resets at midnight. The worker shows this to the clerk at the gate. A completely separate checkout code exists (employer sees both in the code generator).',
    how:'In a real deployment, workers open the app on their own phone. The code is generated instantly without any network connection needed.',
    more:'The code is deterministic — generated from the worker ID + today\'s date + a private salt. Same worker, same day = same code on any device. The clerk\'s system verifies it the same way without any server call.'
  },
  {
    role:'employee',segment:'👷 Employee View',
    category:'Employee',page:'dashboard',target:'#emp-status-card',arrow:'down',
    title:'Check-In Status Card',
    what:'Shows the worker\'s current status for today — checked in, not yet in, or excused.',
    does:'Checked in ✅: shows the time they checked in. Not checked in ⏳: prompts them to show their code. Excused 📋: shows the excuse details including dates, reason, and pay treatment. Checked out: shows checkout time and hours logged.',
    how:'Workers can open this at any time to confirm their status. If they see "Not Checked In" after arriving, they should find the clerk immediately.',
    more:'The excuse notice includes everything the employer set: the reason, the date range, whether it affects their reliability score, and the pay treatment (paid/unpaid/half-day).'
  },
  // ══ WRAP-UP ═════════════════════════════════════════════════════
  {
    role:'done',segment:'Tour Complete',
    category:"You\'re Ready",page:'dashboard',target:null,arrow:null,
    title:'Tour Complete 🎓',
    what:'You\'ve seen all four portals: Employer (full control), Manager (site oversight), Clerk (gate processing), and Employee (worker self-service).',
    does:'Demo data will be cleared now. You can reload fresh test data any time via Demo Controls → Steps 1–3.',
    how:'The ? help button bottom-right is always context-aware — tap it on any page for a cheat sheet specific to where you are. The 🎓 button in the help panel restarts this tour any time.',
    more:'For production use: workers get the Employee portal link, clerks use their PIN, managers use their PIN, and the employer uses the full Employer dashboard. Each role only sees what they need.'
  },
];
let tutIdx=0;

let tutDataLoaded=false;

function _tutLoadDemoData(){
  if(tutDataLoaded)return;
  W=[];E=[];S=[];D=[];Checkins=[];Susp=[];Excuses=[];SmsQueue=[];Makeups=[];OvertimeBonuses=[];
  demoWorkers(5);
  demoSites();
  demoHours();
  demoFillMonth();
  demoSusp();
  tutDataLoaded=true;
  renderAll();
}

function startTutorial(){
  // TODO: Some tutorial step targets were designed for the old ptab layout
  // TODO: Re-verify all 30+ step selectors work against current DOM after redesign
  tutIdx=0;
  tutDataLoaded=false;
  // Auto-load demo data so tutorial has real data to show
  setTimeout(()=>{
    _tutLoadDemoData();
    // Switch to employer portal to start
    const empTab=document.querySelector('.sp-item[data-sb-label="Office"]');
    if(empTab)switchPortal('employer',empTab);
    const ni=document.querySelector('.ni[onclick*="dashboard"]');
    if(ni)showPg('dashboard',ni);
    _tutShow();
  },100);
}

function tutNext(){
  if(tutIdx<TUT_STEPS.length-1){tutIdx++;_tutShow();}
  else _tutFinish();
}

function tutPrev(){
  if(tutIdx>0){tutIdx--;_tutShow();}
}

function tutSkip(){
  _tutFinish();
}

function _tutFinish(){
  const _to2=document.getElementById('tut-overlay');_to2.style.display='none';_to2.classList.remove('tut-active');
  document.body.style.overflow='';
  // Reset demo data on exit
  W=[];E=[];S=[];D=[];Checkins=[];Susp=[];Excuses=[];SmsQueue=[];Makeups=[];OvertimeBonuses=[];
  tutDataLoaded=false;
  managerWorker=null;
  const empTab=document.querySelector('.sp-item[data-sb-label="Office"]');
  if(empTab)switchPortal('employer',empTab);
  const ni=document.querySelector('.ni[onclick*="dashboard"]');
  if(ni)showPg('dashboard',ni);
  renderAll();
  toast('Tutorial complete — demo data cleared. Run Demo Controls to reload test data.');
}

function _tutShow(){
  const step=TUT_STEPS[tutIdx];
  const _to=document.getElementById('tut-overlay');_to.style.display='block';_to.classList.add('tut-active');
  document.body.style.overflow='hidden';

  // Role-based portal navigation
  if(step.role==='employer'||step.role==='transition'){
    const t=document.querySelector('.sp-item[data-sb-label="Office"]');
    if(t&&!t.classList.contains('active'))switchPortal('employer',t);
  }else if(step.role==='manager'){
    const t=document.querySelector('.sp-item[data-sb-label="Manager"]');
    if(t&&!t.classList.contains('active'))switchPortal('manager',t);
    // Auto-login manager if not already in
    if(!managerWorker){
      const mgr=W.find(w=>w.isManager);
      if(mgr){
        managerWorker=mgr;
        const gate=document.getElementById('mgr-gate');
        const dash=document.getElementById('mgr-dashboard');
        if(gate)gate.style.display='none';
        if(dash)dash.style.display='flex';
        const nd=document.getElementById('mgr-name-display');
        const sd=document.getElementById('mgr-site-display');
        if(nd)nd.textContent=mgr.name;
        if(sd)sd.textContent=mgr.managerSite?S.find(s=>s.id===mgr.managerSite)?.name||'All Sites':'All Sites';
        renderMgrDashboard();
      }
    }
  }else if(step.role==='clerk'){
    const t=document.querySelector('.sp-item[data-sb-label="Worker"]');
    if(t&&!t.classList.contains('active'))switchPortal('employee',t);
    // Auto-select clerk worker and show clerk active mode
    const clerk=W.find(w=>w.isClerk);
    if(clerk&&!clerkWorker){
      const sel=document.getElementById('emp-who');
      if(sel){sel.value=clerk.id;empSelect();}
      // Open clerk mode directly
      clerkWorker=clerk;
      const cam=document.getElementById('clerk-active-mode');
      const cab=document.getElementById('clerk-access-banner');
      const cpe=document.getElementById('clerk-pin-entry');
      if(cam){cam.style.display='flex';updMgrDrops&&updMgrDrops();}
      if(cab)cab.style.display='none';
      if(cpe)cpe.style.display='none';
      const can=document.getElementById('clerk-active-name');
      if(can)can.textContent=clerk.name+' — Clerk mode active';
      const ef=document.getElementById('emp-form');
      if(ef)ef.style.display='flex';
      updMgrDrops();
      const csel=document.getElementById('clerk-worker-sel');
      if(csel)csel.innerHTML='<option value="">Select worker...</option>'+W.map(w=>`<option value="${w.id}">${w.name}</option>`).join('');
    }
  }else if(step.role==='employee'){
    const t=document.querySelector('.sp-item[data-sb-label="Worker"]');
    if(t&&!t.classList.contains('active'))switchPortal('employee',t);
    // Exit clerk mode if active, show regular employee view
    if(clerkWorker){
      clerkWorker=null;
      const cam=document.getElementById('clerk-active-mode');
      if(cam)cam.style.display='none';
    }
    const nonClerkW=W.find(w=>!w.isClerk&&!w.isManager);
    if(nonClerkW){
      const sel=document.getElementById('emp-who');
      if(sel){sel.value=nonClerkW.id;empSelect();}
    }
  }

  // Page navigation within employer portal
  if(step.role==='employer'&&step.page&&step.page!=='dashboard'||step.role==='employer'&&step.page==='dashboard'){
    const pgEl=document.getElementById('pg-'+step.page);
    if(pgEl&&!pgEl.classList.contains('active')){
      const ni=document.querySelector(`.ni[onclick*="'${step.page}'"]`);
      if(ni)showPg(step.page,ni);
    }
  }

  // Segment transition card styling
  const isTransition=step.role==='transition'||step.role==='done';
  const segmentEl=document.getElementById('tut-segment');
  if(segmentEl){
    segmentEl.textContent=step.segment||'';
    segmentEl.style.display=step.segment?'block':'none';
    segmentEl.style.background=isTransition?'rgba(167,139,250,.15)':'rgba(255,205,17,.08)';
    segmentEl.style.color=isTransition?'var(--pu)':'var(--y)';
    segmentEl.style.borderColor=isTransition?'rgba(167,139,250,.3)':'rgba(255,205,17,.2)';
  }

  // Populate card content
  document.getElementById('tut-category').textContent=step.category;
  document.getElementById('tut-title').textContent=step.title;
  document.getElementById('tut-what-text').textContent=step.what;
  document.getElementById('tut-does-text').textContent=step.does;
  document.getElementById('tut-how-text').textContent=step.how;

  // See More button
  const moreBtn=document.getElementById('tut-more-btn');
  const moreContent=document.getElementById('tut-more-content');
  if(moreBtn&&moreContent){
    if(step.more){
      moreBtn.style.display='block';
      moreContent.style.display='none';
      moreContent.textContent=step.more;
      moreBtn.textContent='▼ See More';
      moreBtn.onclick=function(){
        const open=moreContent.style.display==='block';
        moreContent.style.display=open?'none':'block';
        moreBtn.textContent=open?'▼ See More':'▲ Less';
      };
    }else{
      moreBtn.style.display='none';
      moreContent.style.display='none';
    }
  }

  document.getElementById('tut-step-counter').textContent=(tutIdx+1)+' / '+TUT_STEPS.length;
  document.getElementById('tut-next-btn').textContent=tutIdx===TUT_STEPS.length-1?'Finish ✓':'Next →';
  const prevBtn=document.getElementById('tut-prev-btn');
  prevBtn.style.opacity=tutIdx===0?'0':'1';
  prevBtn.style.pointerEvents=tutIdx===0?'none':'auto';

  // Progress dots — colour by role
  const roleColour={employer:'var(--y)',manager:'var(--pu)',clerk:'var(--o)',employee:'var(--gr)',transition:'var(--g)',done:'var(--gr)'};
  document.getElementById('tut-dots').innerHTML=TUT_STEPS.map((s,i)=>{
    const col=roleColour[s.role]||'var(--y)';
    return`<div style="width:${i===tutIdx?'20':'6'}px;height:6px;background:${i===tutIdx?col:i<tutIdx?'rgba(255,255,255,.2)':'var(--bd)'};transition:all .3s;"></div>`;
  }).join('');

  // Wait for page render then position — longer delay for portal switches
  const delay=step.role==='manager'||step.role==='clerk'||step.role==='employee'?400:step.page?250:80;
  setTimeout(()=>_tutPosition(step),delay);
}

function _tutPosition(step){
  const vw=window.innerWidth, vh=window.innerHeight;
  const PAD=10;

  const ring=document.getElementById('tut-ring');
  const card=document.getElementById('tut-card');
  const arrow=document.getElementById('tut-arrow');
  const dims={
    top:document.getElementById('tut-dim-top'),
    bot:document.getElementById('tut-dim-bottom'),
    left:document.getElementById('tut-dim-left'),
    right:document.getElementById('tut-dim-right')
  };

  // Try to find the target element
  let el=null;
  if(step.target){
    try{ el=document.querySelector(step.target); }catch(e){}
    if(el){
      // Scroll into view first, then check if actually visible
      try{el.scrollIntoView({block:'nearest',behavior:'instant'});}catch(e){}
      const r=el.getBoundingClientRect();
      // Only treat as missing if element has genuinely zero dimensions
      // (not just partially off-screen)
      const cs=window.getComputedStyle(el);
      if((r.width===0&&r.height===0)||cs.display==='none'||cs.visibility==='hidden'||cs.opacity==='0')el=null;
    }
  }

  if(!el){
    // Full-screen dim, centred card, no ring
    ring.style.display='none';
    arrow.style.display='none';
    dims.top.style.cssText='position:absolute;left:0;top:0;right:0;bottom:0;background:rgba(0,0,0,.82);';
    dims.bot.style.cssText='position:absolute;display:none;';
    dims.left.style.cssText='position:absolute;display:none;';
    dims.right.style.cssText='position:absolute;display:none;';
    const cw=Math.min(360, vw-32);
    card.style.width=cw+'px';
    card.style.left=Math.max(16,(vw-cw)/2)+'px';
    card.style.top='50%';
    card.style.transform='translateY(-50%)';
    return;
  }

  card.style.transform='';

  // Scroll element into view gently
  el.scrollIntoView({block:'nearest',behavior:'smooth'});

  setTimeout(()=>{
    const r=el.getBoundingClientRect();
    // Clamp rect to be within viewport
    const rx=Math.max(0, r.left-PAD);
    const ry=Math.max(0, r.top-PAD);
    const rRight=Math.min(vw, r.right+PAD);
    const rBot=Math.min(vh, r.bottom+PAD);
    const rw=rRight-rx;
    const rh=rBot-ry;

    // Ring
    ring.style.display='block';
    ring.style.cssText=`display:block;position:absolute;left:${rx}px;top:${ry}px;width:${rw}px;height:${rh}px;border:2px solid var(--y);box-shadow:0 0 0 3px rgba(255,205,17,.2),0 0 24px rgba(255,205,17,.15);animation:tut-pulse 1.5s ease-in-out infinite;`;

    // Dim rects (4 panels around the ring)
    const topH=Math.max(0,ry);
    const botH=Math.max(0,vh-ry-rh);
    const leftW=Math.max(0,rx);
    const rightW=Math.max(0,vw-rx-rw);
    dims.top.style.cssText=`position:absolute;left:0;top:0;right:0;height:${topH}px;background:rgba(0,0,0,.82);`;
    dims.bot.style.cssText=`position:absolute;left:0;bottom:0;right:0;height:${botH}px;background:rgba(0,0,0,.82);display:block;`;
    dims.left.style.cssText=`position:absolute;left:0;top:${ry}px;width:${leftW}px;height:${rh}px;background:rgba(0,0,0,.82);display:block;`;
    dims.right.style.cssText=`position:absolute;left:${rx+rw}px;top:${ry}px;width:${rightW}px;height:${rh}px;background:rgba(0,0,0,.82);display:block;`;

    // Arrow — pointing AT the element
    if(step.arrow){
      const arrowMap={down:'⬇',up:'⬆',left:'⬅',right:'➡'};
      arrow.textContent=arrowMap[step.arrow]||'⬇';
      arrow.style.display='block';
      arrow.style.fontSize='24px';
      arrow.style.lineHeight='1';
      arrow.style.color='var(--y)';
      if(step.arrow==='down'){
        // Arrow above element pointing down into it
        arrow.style.left=(rx+rw/2-12)+'px';
        arrow.style.top=Math.max(4, ry-36)+'px';
        arrow.style.animation='tut-bounce .65s ease-in-out infinite alternate';
      } else if(step.arrow==='up'){
        // Arrow below element pointing up into it
        arrow.style.left=(rx+rw/2-12)+'px';
        arrow.style.top=Math.min(vh-36, ry+rh+8)+'px';
        arrow.style.animation='tut-bounce-up .65s ease-in-out infinite alternate';
      } else if(step.arrow==='right'){
        // Arrow left of element pointing right into it
        arrow.style.left=Math.max(4, rx-36)+'px';
        arrow.style.top=(ry+rh/2-12)+'px';
        arrow.style.animation='tut-bounce-h .65s ease-in-out infinite alternate';
      } else if(step.arrow==='left'){
        // Arrow right of element pointing left into it
        arrow.style.left=Math.min(vw-36, rx+rw+8)+'px';
        arrow.style.top=(ry+rh/2-12)+'px';
        arrow.style.animation='tut-bounce-h-rev .65s ease-in-out infinite alternate';
      }
    } else {
      arrow.style.display='none';
    }

    // Card position — measure real card height
    const cardW=Math.min(340, vw-32);
    card.style.width=cardW+'px';
    // Force a layout read for real height
    const cardH=card.offsetHeight||320;
    const MARGIN=12;
    let cx, cy;

    // Horizontal: try to align left edge with element, clamp to viewport
    cx=Math.min(rx, vw-cardW-MARGIN);
    cx=Math.max(MARGIN, cx);

    // Vertical preference order: below → above → beside → overlap
    if(ry+rh+MARGIN+cardH <= vh-MARGIN){
      cy=ry+rh+MARGIN;             // below
    } else if(ry-MARGIN-cardH >= MARGIN){
      cy=ry-MARGIN-cardH;          // above
    } else if(rx+rw+MARGIN+cardW <= vw){
      // beside right — also shift horizontal
      cx=rx+rw+MARGIN;
      cy=Math.max(MARGIN, Math.min(ry, vh-cardH-MARGIN));
    } else {
      // Last resort: overlay centered on screen
      cx=Math.max(MARGIN,(vw-cardW)/2);
      cy=Math.max(MARGIN,(vh-cardH)/2);
    }

    card.style.left=cx+'px';
    card.style.top=cy+'px';
  }, 150);
}

// Click dim areas to dismiss
setTimeout(()=>{
  ['tut-dim-top','tut-dim-bottom','tut-dim-left','tut-dim-right'].forEach(id=>{
    const el=document.getElementById(id);
    if(el)el.addEventListener('click',tutSkip);
  });
},200);


initTheme();
// ── MOBILE NAV ────────────────────────────────────────────────────
function mobileNav(page,btn){
  const ni=document.querySelector(`.ni[onclick*="'${page}'"]`);
  if(ni)showPg(page,ni);
  document.querySelectorAll('.mn-item').forEach(b=>b.classList.remove('active'));
  if(btn)btn.classList.add('active');
  else{
    const match=document.querySelector(`#mobile-nav .mn-item[onclick*="${page}"]`);
    if(match)match.classList.add('active');
  }
}



document.addEventListener('click',e=>{
  const m=document.getElementById('mobile-more-menu');
  const btn=document.getElementById('mn-more');
  if(m&&m.style.display!=='none'&&!m.contains(e.target)&&!btn?.contains(e.target)){
    m.style.display='none';btn?.classList.remove('active');
  }
});

let W=[],E=[],S=[],D=[],Checkins=[],Susp=[],Excuses=[],SmsQueue=[],Makeups=[],OvertimeBonuses=[],WorkerNotes={};
let Inventory=[],InventoryTxn=[];
let storekeepWorker=null;
let empHours=8,empWorker=null,clerkWorker=null,managerWorker=null;
let mgrDir='in';
let mgrDismissPending=null;
let excRangeMode='today';
let mkCalYear=new Date().getFullYear(),mkCalMonth=new Date().getMonth(),mkSelectedDates=new Set();
const EMPLOYER_NAME='Demo Employer (Victor)'; // tracks who is logged in as employer

const today=()=>{const d=new Date();return`${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;};
const now=()=>{if(demoTimeOverride){const{h,m}=demoTimeOverride;return String(h).padStart(2,'0')+':'+String(m).padStart(2,'0');}return new Date().toLocaleTimeString('en-ZA',{hour:'2-digit',minute:'2-digit'});};
const fmtD=()=>new Date().toLocaleDateString('en-ZA',{weekday:'long',day:'numeric',month:'long',year:'numeric'});

const PT={
  hourly:{l:'Hourly Rate',rl:'Rate (R/hr)',f:r=>`R${r}/hr`,c:(h,w)=>h*(+w.rate||0)},
  daily:{l:'Daily Rate',rl:'Rate (R/day)',f:r=>`R${r}/day`,c:(h,w)=>+w.rate||0},
  weekly:{l:'Weekly Salary',rl:'Weekly (R)',f:r=>`R${r}/wk`,c:(h,w)=>+w.rate||0},
  monthly:{l:'Monthly Salary',rl:'Monthly (R)',f:r=>`R${r}/mo`,c:(h,w)=>+w.rate||0},
  piece:{l:'Piece Rate',rl:'Rate/unit (R)',f:r=>`R${r}/unit`,c:(h,w)=>h*(+w.rate||0)},
  'day-overtime':{l:'Day Rate+OT',rl:'Day Rate (R)',f:r=>`R${r}+OT`,c:(h,w)=>{const r=+w.rate||0,ot=+w.ot||9,om=+w.otMult||1.5;return r+Math.max(0,h-ot)*(r/ot)*om;}},
  shift:{l:'Shift Rate',rl:'Rate/shift (R)',f:r=>`R${r}/shift`,c:(h,w)=>+w.rate||0},
  contract:{l:'Contract Rate',rl:'Project Rate (R)',f:r=>`R${r} proj`,c:(h,w)=>+w.rate||0},
};
const ptL=pt=>PT[pt]?.l||pt||'—';
const ptF=w=>PT[w.payType]?PT[w.payType].f(+w.rate||0):'';
const calcPay=(w,h)=>PT[w.payType]?PT[w.payType].c(h,w):null;

// Daily code generator — deterministic per worker per day
function genCodeFor(wId){
  const str=wId+today()+'vee-salt-2025';
  let h=0;for(let i=0;i<str.length;i++){h=Math.imul(31,h)+str.charCodeAt(i)|0;}
  return String(Math.abs(h)).slice(0,6).padStart(6,'0');
}

function uid(){return Math.random().toString(36).slice(2,10);}

function rel(wId){
  const w=W.find(x=>x.id===wId);
  const exp=(+w?.expectedDays||5)*4;
  // Count actual entries, but also count excused days with affectsReliability=false as "attended"
  const act=E.filter(e=>e.workerId===wId).length;
  // Days excused with reliability protection (don't count as absent)
  const protectedDays=new Set();
  Excuses.filter(ex=>ex.workerIds.includes(wId)&&ex.affectsReliability===false).forEach(ex=>{
    ex.dates.forEach(d=>protectedDays.add(d));
  });
  // Effective attended = actual entries + protected excused days (up to expected)
  const effective=Math.min(exp,act+protectedDays.size);
  const pct=exp>0?Math.min(100,Math.round((effective/exp)*100)):100;
  return pct;
}

// ── GATE ──────────────────────────────────────────────────────────
function unlock(){
  // TODO: Replace this demo gate with Firebase Auth (signInWithEmailAndPassword)
  // TODO: Real auth flow: show loading spinner, catch auth errors, redirect on success
  const pw=document.getElementById('gpw').value.trim();
  if(pw==='veedemo'){
    document.getElementById('gate').style.display='none';
    showViewSelector();
    if(localStorage.getItem('vee-seen')){
      document.getElementById('app').style.display='flex';
  initSidebar();
      try{init();}catch(e){console.warn('Init error:',e);init();}
    }
  }else{
    document.getElementById('gerr').style.display='block';
  }
}

// Modified confirmView — also starts the app after view is chosen
function _startApp(){
  document.getElementById('app').style.display='flex';
  init();
}
document.getElementById('gpw').addEventListener('keydown',e=>{if(e.key==='Enter')unlock();});
document.getElementById('clerk-pin-input').addEventListener('keydown',e=>{if(e.key==='Enter')verifyClerkPIN();});
// ── INIT ──────────────────────────────────────────────────────────
function init(){
  updWPF();
  renderAll();
}

function renderAll(){
  // TODO: Once Firebase is wired, replace in-memory array reads with Firestore listeners
  // TODO: Each render function should accept data param or use a shared state store
  renderDash();renderWorkerGrid();renderSites();renderDisputes();renderExport();renderSuspicious();renderCILog();renderEmpHistory();updateAlertsBadges();
  renderEmpCheckedOutTools();updBanner();updDemoState();updWDrops();updEmpDrops();updMgrDrops();
  if(managerWorker)renderMgrDashboard();
  // Re-render calendar if it's the active page
  if(document.getElementById('pg-calendar')?.classList.contains('active'))renderCalendar();
}

function updBanner(){
  const td=today();
  const wcb=document.getElementById('worker-count-banner');
  if(wcb)wcb.textContent=W.length+' workers';
  const ecb=document.getElementById('entry-count-banner');
  if(ecb)ecb.textContent=E.filter(e=>e.date===td).length;
}

// ── PORTAL SWITCHING ──────────────────────────────────────────────
function switchPortal(name,el){
  // Update sidebar portal switcher items
  document.querySelectorAll('.sp-item').forEach(t=>t.classList.remove('active'));
  if(el)el.classList.add('active');
  // Show correct portal view
  document.querySelectorAll('.pview').forEach(v=>v.classList.remove('active'));
  const pv=document.getElementById('pv-'+name);
  if(pv)pv.classList.add('active');
  // Show employer nav only when on employer portal
  const nav=document.getElementById('sidebar-nav');
  if(nav)nav.style.display=(name==='employer'?'block':'none');
  if(name==='employee'){updEmpDrops();renderEmpHistory();renderCILog();}
  if(name==='clerk'){updClerkGateDrops();if(clerkWorker)renderCILog();}
  if(name==='manager'){updMgrDrops();if(managerWorker)renderMgrDashboard();}
}

function showPg(name,el){
  document.querySelectorAll('.pg').forEach(p=>p.classList.remove('active'));
  document.querySelectorAll('.ni').forEach(n=>n.classList.remove('active'));
  document.getElementById('pg-'+name).classList.add('active');
  if(el)el.classList.add('active');
  if(name==='export')renderExport();
  if(name==='checkin'){updCISel();renderCILog();}
  if(name==='calendar')renderCalendar();
}

// ── DASHBOARD ─────────────────────────────────────────────────────
function renderDash(){
  const td=today();
  const todayE=E.filter(e=>e.date===td);
  const logged=new Set(todayE.map(e=>e.workerId));
  const excusedToday=new Set(W.filter(w=>isExcusedOn(w.id,td)).map(w=>w.id));
  const notLogged=W.filter(w=>!logged.has(w.id)&&!excusedToday.has(w.id));
  document.getElementById('st0').textContent=W.length;
  document.getElementById('st1').textContent=logged.size;
  document.getElementById('st2').textContent=notLogged.length;
  document.getElementById('st3').textContent=Checkins.filter(c=>c.date===td&&c.status==='ok').length;
  calcHS();
  // Entries table
  const tb=document.getElementById('etb');
  if(!W.length){tb.innerHTML=`<tr><td colspan="7" style="padding:20px;text-align:center;color:var(--g);font-size:13px">No workers yet.</td></tr>`;return;}
  let r='';
  todayE.forEach(e=>{
    const w=W.find(x=>x.id===e.workerId);
    const pay=w?calcPay(w,+e.hours):null;
    const pct=rel(e.workerId);
    const rdot=pct>=85?'rdg':pct>=60?'rdy':'rdr';
    r+=`<tr><td><span class="wn">${w?w.name:e.workerName}</span></td>
    <td><span class="rd ${rdot}"></span> <span style="font-size:12px;color:var(--g)">${pct}%</span></td>
    <td><span class="ptag">${w?ptL(w.payType):'—'}</span></td>
    <td><span class="hv">${e.hours}</span></td>
    <td style="color:var(--y);font-family:'Barlow Condensed',sans-serif;font-weight:900">${pay!=null?'R'+pay.toFixed(0):'—'}</td>
    <td style="font-size:12px;color:var(--g)">${e.site||'—'}</td>
    <td><span class="badge bgr">✓ Logged</span></td></tr>`;
  });
  // Excused workers
  W.filter(w=>excusedToday.has(w.id)&&!logged.has(w.id)).forEach(w=>{
    const exc=Excuses.find(e=>e.workerIds.includes(w.id)&&e.dates.includes(td));
    const payCol={unpaid:'var(--g)',paid:'var(--gr)',halfday:'var(--y)'}[exc?.payType||'unpaid'];
    const payLbl={unpaid:'Unpaid',paid:'Paid Leave',halfday:'Half-Day'}[exc?.payType||'unpaid'];
    const pct=rel(w.id);const rdot=pct>=85?'rdg':pct>=60?'rdy':'rdr';
    r+=`<tr style="opacity:.8"><td><span class="wn" style="color:var(--g)">${w.name}${w.isTest?` <span style="font-size:10px;color:var(--pu)">(Test)</span>`:''}</span></td>
    <td><span class="rd ${rdot}"></span> <span style="font-size:12px;color:var(--g)">${pct}%</span></td>
    <td><span class="ptag">${ptL(w.payType)}</span></td>
    <td style="color:${payCol};font-size:12px">${payLbl}</td><td style="color:var(--g)">—</td>
    <td style="font-size:11px;color:var(--g)">${exc?.reason||'Excused'}</td>
    <td><span class="badge" style="background:rgba(255,205,17,.1);color:var(--y);border:1px solid rgba(255,205,17,.2)">📋 Excused</span></td></tr>`;
  });
  // Not logged, not excused
  notLogged.forEach(w=>{
    const pct=rel(w.id);const rdot=pct>=85?'rdg':pct>=60?'rdy':'rdr';
    r+=`<tr><td><span class="wn" style="color:var(--g)">${w.name}${w.isTest?` <span style="font-size:10px;color:var(--pu)">(Test)</span>`:''}</span></td>
    <td><span class="rd ${rdot}"></span> <span style="font-size:12px;color:var(--g)">${pct}%</span></td>
    <td><span class="ptag">${ptL(w.payType)}</span></td>
    <td style="color:var(--g)">—</td><td style="color:var(--g)">—</td><td style="color:var(--g)">—</td>
    <td><span class="badge brd">✗ Not Logged</span></td></tr>`;
  });
  tb.innerHTML=r;
  // Site breakdown
  const sm={};todayE.forEach(e=>{const s=e.site||'Unassigned';sm[s]=(sm[s]||0)+(+e.hours||0);});
  const sorted=Object.entries(sm).sort((a,b)=>b[1]-a[1]);
  const maxH=sorted[0]?.[1]||1;
  const sbd=document.getElementById('sitebd');
  if(!sorted.length){sbd.innerHTML=`<div style="color:var(--g);font-size:13px;text-align:center;padding:10px">No site data yet.</div>`;return;}
  sbd.innerHTML=sorted.map(([s,h])=>`<div class="srow"><div style="font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;font-size:13px;min-width:120px">${s}</div><div class="sbw"><div class="sbar" style="width:${Math.round((h/maxH)*100)}%"></div></div><div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:16px;color:var(--y);min-width:60px;text-align:right">${h}hrs</div></div>`).join('');
  // Check worker health alerts after rendering
  checkWorkerAlerts();
}

function calcHS(){
  // TODO: PAYE and UIF deductions not yet calculated — gross pay only
  // TODO: Add South African tax brackets + UIF (1% employee / 1% employer) engine
  if(!W.length){document.getElementById('hscore').textContent='—';document.getElementById('hsdesc').textContent='Add workers to start.';document.getElementById('hbr').innerHTML='';return;}
  const td=today();const todayE=E.filter(e=>e.date===td);
  const logRate=W.length>0?todayE.length/W.length:0;
  const openDisp=D.filter(d=>d.status==='open').length;
  const dp=Math.min(0.3,openDisp*0.05);
  const sc=Math.min(1,Math.max(0,logRate*(1-dp)+(S.length>0?0.05:0)));
  const s10=Math.round(sc*100)/10;
  const arc=document.getElementById('harc');
  arc.style.strokeDashoffset=264-(sc*264);
  arc.style.stroke=s10>=8?'#4CAF50':s10>=6?'#FFCD11':'#F44336';
  const num=document.getElementById('hscore');
  num.textContent=s10.toFixed(1);
  num.style.color=s10>=8?'var(--gr)':s10>=6?'var(--y)':'var(--r)';
  document.getElementById('hsdesc').textContent=s10>=9?'Excellent — payroll running cleanly.':s10>=8?'Very good — minor gaps.':s10>=6?'Fair — some workers not logging.':'Needs attention.';
  document.getElementById('hbr').innerHTML=`
    <div class="hbi"><div class="hbv" style="color:var(--y)">${Math.round(logRate*100)}%</div><div class="hbl">Log Rate</div></div>
    <div class="hbi"><div class="hbv" style="color:${openDisp>0?'var(--r)':'var(--gr)'}">${openDisp}</div><div class="hbl">Disputes</div></div>
    <div class="hbi"><div class="hbv" style="color:var(--y)">${todayE.length}/${W.length}</div><div class="hbl">Today</div></div>`;
}

// ── WORKERS ───────────────────────────────────────────────────────
function renderWorkerGrid(){
  const g=document.getElementById('wgrid');
  if(!W.length){g.innerHTML=`<div style="grid-column:1/-1;padding:30px;text-align:center;color:var(--g);font-size:13px">No workers yet.</div>`;return;}
  const td=today();
  g.innerHTML=W.map(w=>{
    const pct=rel(w.id);
    const rdot=pct>=85?'rdg':pct>=60?'rdy':'rdr';
    // Geo badge
    const geoEff=effectiveGeo(w);
    const geoBadge=w.geoFence==='enabled'
      ?`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(76,175,80,.12);color:var(--gr);padding:2px 7px;">🛰 Geo ON</span>`
      :w.geoFence==='disabled'
      ?`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(244,67,54,.1);color:var(--r);padding:2px 7px;">📵 Geo OFF</span>`
      :`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(136,136,128,.1);color:var(--g);padding:2px 7px;">⚙️ Default (${geoEff?'ON':'OFF'})</span>`;
    // Excused badge
    const excusedNow=isExcusedOn(w.id,td);
    const excuseBadge=excusedNow
      ?`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(255,205,17,.1);color:var(--y);padding:2px 7px;border:1px solid rgba(255,205,17,.2);">📋 Excused</span>`
      :'';
    return`<div class="wt${w.isTest?' test':''}${excusedNow?' excused':''}">
      <div class="av" style="${excusedNow?'opacity:.5;':''}">${w.name.charAt(0).toUpperCase()}</div>
      <div style="flex:1;min-width:0">
        <div style="font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;font-size:14px">${w.name}${w.isTest?` <span style="font-size:10px;color:var(--pu)">(Test)</span>`:''}${w.isClerk?` <span style="font-size:10px;color:var(--o);">🔐 Clerk</span>`:''}${w.isManager?` <span style="font-size:10px;color:var(--pu);">🔧 Mgr</span>`:''}</div>
        <div style="font-size:11px;color:var(--g);margin-top:1px">${w.role||'Worker'}</div>
        <div style="margin-top:5px;display:flex;align-items:center;gap:6px;flex-wrap:wrap;"><span class="ptag">${ptL(w.payType)}</span>${geoBadge}${excuseBadge}</div>
        <div style="margin-top:4px;display:flex;align-items:center;gap:5px"><span class="rd ${rdot}"></span><span style="font-size:11px;color:var(--g)">${pct}% reliability</span></div>
        ${w.aeEnabled?(()=>{const s=getEntitlementStatus(w);if(!s)return'';const barPct=Math.min(100,Math.round((s.used/s.allowed)*100));const bc=s.exceeded?'var(--r)':barPct>=75?'var(--o)':'var(--gr)';return`<div style="margin-top:6px;"><div style="height:4px;background:var(--surf2);"><div style="height:100%;width:${barPct}%;background:${bc};transition:width .3s;"></div></div><div style="font-size:10px;color:${bc};margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif;">${s.exceeded?'⚠ ':''} ${s.used}/${s.allowed} leave days${s.exceeded?' — exceeded':''}</div></div>`;})():''}
      </div>
      <div style="display:flex;flex-direction:column;gap:5px;flex-shrink:0;">
        <button onclick="openWorkerInfo('${w.id}')" title="Worker info" data-vee-tip="Worker Info|Full profile, pay details, shift rules, and check-in history for this worker." style="background:transparent;border:1px solid var(--bd);color:var(--g);width:28px;height:28px;cursor:pointer;font-size:12px;transition:all .2s;" onmouseover="this.style.borderColor='var(--pu)';this.style.color='var(--pu)'" onmouseout="this.style.borderColor='var(--bd)';this.style.color='var(--g)'">ℹ</button>
        <button onclick="editW('${w.id}')" style="background:transparent;border:1px solid var(--bd);color:var(--g);width:28px;height:28px;cursor:pointer;font-size:12px;transition:all .2s;" onmouseover="this.style.borderColor='var(--y)';this.style.color='var(--y)'" onmouseout="this.style.borderColor='var(--bd)';this.style.color='var(--g)'">✏️</button>
        <button onclick="demoSimulateGeoFail('${w.id}')" title="Simulate geo-fence failure" style="background:transparent;border:1px solid var(--bd);color:var(--g);width:28px;height:28px;cursor:pointer;font-size:11px;transition:all .2s;" onmouseover="this.style.borderColor='var(--o)';this.style.color='var(--o)'" onmouseout="this.style.borderColor='var(--bd)';this.style.color='var(--g)'">🛰</button>
        <button onclick="delW('${w.id}')" style="background:transparent;border:1px solid var(--bd);color:var(--g);width:28px;height:28px;cursor:pointer;font-size:12px;transition:all .2s;" onmouseover="this.style.borderColor='var(--r)';this.style.color='var(--r)'" onmouseout="this.style.borderColor='var(--bd)';this.style.color='var(--g)'">🗑</button>
      </div>
    </div>`;
  }).join('');
}

let editingWId=null;

function openAddWorker(){
  editingWId=null;
  document.getElementById('mw').querySelector('.mdt').textContent='Add Worker';
  document.getElementById('mw-save-btn').textContent='Save Worker';
  const n=W.length+1;
  document.getElementById('wnam').value=`Test Worker ${n}`;
  document.getElementById('wrol').value='Operator';
  const pts=Object.keys(PT);
  const pt=pts[W.length%pts.length];
  document.getElementById('wpt').value=pt;
  document.getElementById('wpho').value=`+27 82 ${String(1000000+n*111111).slice(0,7)}`;
  document.getElementById('wexp').value='5';
  document.getElementById('wistest').checked=true;
  document.getElementById('wisclerk').checked=false;
  document.getElementById('wclerkpin').value='';
  document.getElementById('clerk-pin-wrap').style.display='none';
  document.getElementById('wismanager').checked=false;
  document.getElementById('manager-fields-wrap').style.display='none';
  document.getElementById('wmanagerpin').value='';
  document.getElementById('wmanager-payroll').checked=false;
  // Populate manager site dropdown
  const mgrSiteSel=document.getElementById('wmanagersite');
  if(mgrSiteSel)mgrSiteSel.innerHTML='<option value="">All sites (no restriction)</option>'+S.map(s=>`<option value="${s.id}">${s.name}</option>`).join('');
  document.getElementById('wshift-start').value='06:00';
  document.getElementById('wshift-end').value='17:00';
  document.getElementById('wlogin-from').value='05:00';
  document.getElementById('wlogin-earliest').value='08:00';
  document.getElementById('wlogin-recommended').checked=true;
  document.getElementById('wlogout-from').value='17:00';
  document.getElementById('wlogout-latest').value='18:00';
  document.getElementById('wlogout-recommended').checked=true;
  document.getElementById('wgeo-default').checked=true;
  // Reset AE fields
  document.getElementById('wae-enabled').checked=false;
  document.getElementById('wae-fields').style.display='none';
  document.getElementById('wae-days').value='3';
  document.getElementById('wae-period').value='month';
  document.getElementById('wae-type').value='permanent';
  document.getElementById('wae-exceed').value='flag';
  updWPF();updShiftPreview();updGeoPreview();
  document.getElementById('mw').classList.add('open');
  setTimeout(()=>{const ni=document.getElementById('wnam');ni.focus();ni.select();},100);
}

function editW(id){
  const w=W.find(x=>x.id===id);if(!w)return;
  editingWId=id;
  document.getElementById('mw').querySelector('.mdt').textContent='Edit Worker';
  document.getElementById('mw-save-btn').textContent='Save Changes';
  document.getElementById('wnam').value=w.name||'';
  document.getElementById('wrol').value=w.role||'';
  document.getElementById('wpt').value=w.payType||'hourly';
  document.getElementById('wpho').value=w.phone||'';
  document.getElementById('wexp').value=w.expectedDays||5;
  document.getElementById('wistest').checked=!!w.isTest;
  document.getElementById('wisclerk').checked=!!w.isClerk;
  document.getElementById('wclerkpin').value=w.clerkPin||'';
  // Load clerkSite into dropdown
  const clerkSiteSel=document.getElementById('wclerksite');
  if(clerkSiteSel){
    if(clerkSiteSel.options.length<=1){S.forEach(s=>{const o=document.createElement('option');o.value=s.id;o.textContent=s.name;clerkSiteSel.appendChild(o);});}
    clerkSiteSel.value=w.clerkSite||'';
  }
  document.getElementById('clerk-pin-wrap').style.display=w.isClerk?'block':'none';
  document.getElementById('wismanager').checked=!!w.isManager;
  document.getElementById('manager-fields-wrap').style.display=w.isManager?'flex':'none';
  document.getElementById('wmanagerpin').value=w.managerPin||'';
  document.getElementById('wmanager-payroll').checked=!!w.managerShowPayroll;
  // Populate manager site dropdown
  const mgrSiteSel=document.getElementById('wmanagersite');
  if(mgrSiteSel){
    mgrSiteSel.innerHTML='<option value="">All sites (no restriction)</option>'+S.map(s=>`<option value="${s.id}">${s.name}</option>`).join('');
    mgrSiteSel.value=w.managerSite||'';
  }
  document.getElementById('wshift-start').value=w.shiftStart||'06:00';
  document.getElementById('wshift-end').value=w.shiftEnd||'17:00';
  document.getElementById('wlogin-from').value=w.loginFrom||'05:00';
  document.getElementById('wlogin-earliest').value=w.loginEarliest||'08:00';
  const lr=w.loginRule||'recommended';
  document.getElementById('wlogin-mandatory').checked=lr==='mandatory';
  document.getElementById('wlogin-recommended').checked=lr!=='mandatory';
  document.getElementById('wlogout-from').value=w.logoutFrom||'17:00';
  document.getElementById('wlogout-latest').value=w.logoutLatest||'18:00';
  const or2=w.logoutRule||'recommended';
  document.getElementById('wlogout-mandatory').checked=or2==='mandatory';
  document.getElementById('wlogout-recommended').checked=or2!=='mandatory';
  // Geo setting
  const geo=w.geoFence||'default';
  document.getElementById('wgeo-enable').checked=geo==='enabled';
  document.getElementById('wgeo-default').checked=geo==='default';
  document.getElementById('wgeo-disable').checked=geo==='disabled';
  // AE fields
  const aeOn=!!w.aeEnabled;
  document.getElementById('wae-enabled').checked=aeOn;
  document.getElementById('wae-fields').style.display=aeOn?'flex':'none';
  document.getElementById('wae-days').value=w.aeDays||'3';
  document.getElementById('wae-period').value=w.aePeriod||'month';
  document.getElementById('wae-type').value=w.aeType||'permanent';
  document.getElementById('wae-exceed').value=w.aeExceed||'flag';
  if(aeOn)updAEPreview();
  updWPF();updShiftPreview();updGeoPreview();
  document.getElementById('mw').classList.add('open');
}

function updWPF(){
  const pt=document.getElementById('wpt').value;
  const existing=document.getElementById('w-rate');
  // Don't rebuild if same pay type already rendered — preserves user's typed value
  if(existing&&existing.dataset.pt===pt)return;
  const pre='w';
  let h=`<label class="fl">${PT[pt]?.rl||'Rate (R)'}</label><input class="fi" id="${pre}-rate" type="number" placeholder="0" data-pt="${pt}" style="margin-bottom:0"/>`;
  if(pt==='day-overtime')h+=`<div class="mr" style="margin-top:10px"><div><label class="fl">OT after (hrs)</label><input class="fi" id="${pre}-ot" type="number" placeholder="9" value="9" style="margin-bottom:0"/></div><div><label class="fl">OT Multiplier</label><select class="fi" id="${pre}-om" style="margin-bottom:0"><option value="1.5">1.5× Standard</option><option value="2">2× Sunday/PH</option></select></div></div>`;
  document.getElementById('wpf').innerHTML=h;
  const defaults={hourly:45,daily:380,weekly:1800,monthly:7500,piece:28,'day-overtime':350,shift:420,contract:5000};
  const ri=document.getElementById('w-rate');if(ri&&defaults[pt])ri.value=defaults[pt];
}

function saveWorker(){
  const name=document.getElementById('wnam').value.trim();
  if(!name){toast('Enter a name');return;}
  const pt=document.getElementById('wpt').value;
  const rate=document.getElementById('w-rate')?.value||'0';
  const ot=document.getElementById('w-ot')?.value||'9';
  const otMult=document.getElementById('w-om')?.value||'1.5';
  const isTest=document.getElementById('wistest').checked;
  const isClerk=document.getElementById('wisclerk').checked;
  const clerkPin=document.getElementById('wclerkpin')?.value.trim()||'';
  const isManager=document.getElementById('wismanager').checked;
  const managerPin=document.getElementById('wmanagerpin')?.value.trim()||'';
  const managerSite=document.getElementById('wmanagersite')?.value||'';
  const managerShowPayroll=document.getElementById('wmanager-payroll')?.checked||false;
  if(isClerk&&clerkPin.length!==4){toast('Enter a 4-digit clerk PIN');return;}
  const shiftStart=document.getElementById('wshift-start').value||'06:00';
  const shiftEnd=document.getElementById('wshift-end').value||'17:00';
  const loginFrom=document.getElementById('wlogin-from').value||'05:00';
  const loginEarliest=document.getElementById('wlogin-earliest').value||'08:00';
  const loginRule=document.querySelector('input[name="login-rule-radio"]:checked')?.value||'recommended';
  const logoutFrom=document.getElementById('wlogout-from').value||'17:00';
  const logoutLatest=document.getElementById('wlogout-latest').value||'18:00';
  const logoutRule=document.querySelector('input[name="logout-rule-radio"]:checked')?.value||'recommended';
  const geoFence=document.querySelector('input[name="wgeo"]:checked')?.value||'default';
  const aeEnabled=document.getElementById('wae-enabled').checked;
  const aeDays=parseInt(document.getElementById('wae-days').value)||3;
  const aePeriod=document.getElementById('wae-period').value||'month';
  const aeType=document.getElementById('wae-type').value||'permanent';
  const aeExceed=document.getElementById('wae-exceed').value||'flag';
  const data={name,role:document.getElementById('wrol').value.trim()||'Worker',phone:document.getElementById('wpho').value.trim(),expectedDays:parseInt(document.getElementById('wexp').value)||5,payType:pt,rate,ot,otMult,isTest,isClerk,clerkPin,clerkSite:document.getElementById('wclerksite')?.value||'',isManager,managerPin,managerSite,managerShowPayroll,shiftStart,shiftEnd,loginFrom,loginEarliest,loginRule,logoutFrom,logoutLatest,logoutRule,geoFence,aeEnabled,aeDays,aePeriod,aeType,aeExceed};
  if(editingWId){
    const idx=W.findIndex(x=>x.id===editingWId);
    if(idx>-1)W[idx]={...W[idx],...data};
    toast('Worker updated');
  }else{
    W.push({id:uid(),...data,createdAt:new Date().toISOString()});
    toast('Worker added');
  }
  editingWId=null;cm('mw');renderAll();
}

function toggleClerkPIN(){
  const show=document.getElementById('wisclerk').checked;
  document.getElementById('clerk-pin-wrap').style.display=show?'block':'none';
  if(show){
    setTimeout(()=>document.getElementById('wclerkpin').focus(),50);
    // Populate clerk site dropdown
    const siteSel=document.getElementById('wclerksite');
    if(siteSel&&siteSel.options.length<=1){
      S.forEach(s=>{const o=document.createElement('option');o.value=s.id;o.textContent=s.name;siteSel.appendChild(o);});
    }
  }
}

function toggleManagerFields(){
  const show=document.getElementById('wismanager').checked;
  document.getElementById('manager-fields-wrap').style.display=show?'flex':'none';
  // Populate site dropdown when opened
  if(show){
    const sel=document.getElementById('wmanagersite');
    if(sel){sel.innerHTML='<option value="">All sites (no restriction)</option>'+S.map(s=>`<option value="${s.id}">${s.name}</option>`).join('');}
    setTimeout(()=>document.getElementById('wmanagerpin').focus(),50);
  }
}

// ── EXCUSE SYSTEM ────────────────────────────────────────────────
// (Excuses and SmsQueue declared in state array above)

function openExcuseModal(){
  if(!W.length){toast('Add workers first');return;}
  excRangeMode='today';
  // Reset state
  document.getElementById('exc-recurring').checked=false;
  document.getElementById('exc-recurring-opts').style.display='none';
  document.getElementById('exc-unpaid').checked=true;
  document.getElementById('exc-reason').value='';
  document.getElementById('exc-preview').style.display='none';
  document.getElementById('exc-date-row').style.display='none';
  // Reset the two new toggles
  document.getElementById('exc-affects-rel').checked=true;
  document.getElementById('exc-rel-label').textContent='ON';
  document.getElementById('exc-rel-label').style.color='var(--r)';
  document.getElementById('exc-pay-override').checked=false;
  document.getElementById('exc-pay-override-label').textContent='OFF';
  document.getElementById('exc-pay-override-label').style.color='var(--g)';
  // Set today's date in inputs
  const td=today();
  document.getElementById('exc-from').value=td;
  document.getElementById('exc-to').value=td;
  // Reset range buttons
  document.getElementById('exc-today-btn').style.cssText='background:var(--y);color:var(--bg);border:none;';
  document.getElementById('exc-custom-btn').style.cssText='';
  // Build worker checklist
  const list=document.getElementById('exc-worker-list');
  list.innerHTML=W.map(w=>`
    <label style="display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--bd);cursor:pointer;transition:background .15s;" onmouseover="this.style.background='rgba(255,255,255,.03)'" onmouseout="this.style.background='transparent'">
      <input type="checkbox" class="exc-chk" data-id="${w.id}" style="accent-color:var(--y);width:15px;height:15px;flex-shrink:0;" onchange="updExcPreview()"/>
      <div style="flex:1;">
        <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;">${w.name}${w.isTest?' <span style="font-size:10px;color:var(--pu)">(Test)</span>':''}</div>
        <div style="font-size:11px;color:var(--g);">${w.role||'Worker'} · ${ptL(w.payType)}</div>
      </div>
      ${isExcusedToday(w.id)?'<span style="font-size:10px;font-family:\'Barlow Semi Condensed\',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(255,205,17,.12);color:var(--y);padding:2px 8px;">Already Excused</span>':''}
    </label>`).join('');
  updExcPayBoxes();
  document.getElementById('mexc').classList.add('open');
}

function isExcusedToday(wId){
  const td=today();
  return Excuses.some(e=>e.workerIds.includes(wId)&&e.dates.includes(td));
}

function isExcusedOn(wId,date){
  return Excuses.some(e=>e.workerIds.includes(wId)&&e.dates.includes(date));
}

function getActiveExcuse(wId){
  const td=today();
  return Excuses.find(e=>e.workerIds.includes(wId)&&e.dates.some(d=>d>=td));
}

function excSelectAll(){
  document.querySelectorAll('.exc-chk').forEach(c=>{c.checked=true;});
  updExcPreview();
}

function excSelectNone(){
  document.querySelectorAll('.exc-chk').forEach(c=>{c.checked=false;});
  updExcPreview();
}

function setExcRange(mode,btn){
  excRangeMode=mode;
  const td=today();
  document.getElementById('exc-today-btn').style.cssText='';
  document.getElementById('exc-custom-btn').style.cssText='';
  btn.style.cssText='background:var(--y);color:var(--bg);border:none;';
  if(mode==='today'){
    document.getElementById('exc-date-row').style.display='none';
    document.getElementById('exc-from').value=td;
    document.getElementById('exc-to').value=td;
  }else{
    document.getElementById('exc-date-row').style.display='flex';
  }
  updExcPreview();
}

function toggleExcRecurring(){
  const on=document.getElementById('exc-recurring').checked;
  const opts=document.getElementById('exc-recurring-opts');
  opts.style.display=on?'flex':'none';
  if(on){
    // Force custom range when recurring
    setExcRange('custom',document.getElementById('exc-custom-btn'));
  }
  updExcPreview();
}

function updExcPayBoxes(){
  const val=document.querySelector('input[name="exc-pay"]:checked')?.value||'unpaid';
  const cols={unpaid:'var(--r)',paid:'var(--gr)',halfday:'var(--y)'};
  const bgs={unpaid:'rgba(244,67,54,.08)',paid:'rgba(76,175,80,.08)',halfday:'rgba(255,205,17,.06)'};
  ['unpaid','paid','halfday'].forEach(v=>{
    const box=document.getElementById(`exc-${v}-box`);
    if(v===val){box.style.borderColor=cols[v];box.style.background=bgs[v];}
    else{box.style.borderColor='var(--bd)';box.style.background='transparent';}
  });
  updExcPreview();
}

function buildExcuseDates(){
  const from=document.getElementById('exc-from').value;
  const to=document.getElementById('exc-to').value;
  const recurring=document.getElementById('exc-recurring').checked;
  if(!from||!to)return[];
  // Build base dates (every day from→to)
  const dates=[];
  let cur=new Date(from);
  const end=new Date(to);
  while(cur<=end){
    dates.push(cur.toISOString().slice(0,10));
    cur.setDate(cur.getDate()+1);
  }
  if(!recurring)return dates;
  // Expand with recurring pattern
  const pattern=document.getElementById('exc-recur-pattern').value;
  const weeks=parseInt(document.getElementById('exc-recur-weeks').value)||3;
  const allDates=[...dates];
  for(let w=1;w<weeks;w++){
    if(pattern==='week'){
      // Repeat same set of days each week
      dates.forEach(d=>{
        const nd=new Date(d);nd.setDate(nd.getDate()+7*w);
        allDates.push(nd.toISOString().slice(0,10));
      });
    }else if(pattern==='monday'||pattern==='friday'){
      const dow=pattern==='monday'?1:5;
      // Find first matching day in range
      const base=new Date(from);
      while(base.getDay()!==dow)base.setDate(base.getDate()+1);
      for(let ww=0;ww<weeks;ww++){
        const nd=new Date(base);nd.setDate(nd.getDate()+7*ww);
        allDates.push(nd.toISOString().slice(0,10));
      }
    }
  }
  return[...new Set(allDates)].sort();
}

function updExcPreview(){
  const selected=[...document.querySelectorAll('.exc-chk:checked')].map(c=>c.dataset.id);
  const from=document.getElementById('exc-from').value;
  const to=document.getElementById('exc-to').value;
  const payVal=document.querySelector('input[name="exc-pay"]:checked')?.value||'unpaid';
  const recurring=document.getElementById('exc-recurring').checked;
  // Sync toggle labels
  const affectsRel=document.getElementById('exc-affects-rel')?.checked;
  const relLabel=document.getElementById('exc-rel-label');
  if(relLabel){relLabel.textContent=affectsRel?'ON':'OFF';relLabel.style.color=affectsRel?'var(--r)':'var(--gr)';}
  const payOvr=document.getElementById('exc-pay-override')?.checked;
  const payOvrLabel=document.getElementById('exc-pay-override-label');
  if(payOvrLabel){payOvrLabel.textContent=payOvr?'ON':'OFF';payOvrLabel.style.color=payOvr?'var(--y)':'var(--g)';}
  const preview=document.getElementById('exc-preview');
  if(!selected.length||!from){preview.style.display='none';return;}
  const dates=buildExcuseDates();
  const payLabel={unpaid:'Unpaid',paid:'Paid (full)',halfday:'Half-day pay'};
  const names=selected.map(id=>W.find(w=>w.id===id)?.name||id);
  let txt=`<strong style="color:var(--y)">${names.length} worker${names.length!==1?'s':''}</strong> will be excused — `;
  txt+=from===to?`<strong>${from}</strong>`:recurring?`${dates.length} days across ${document.getElementById('exc-recur-weeks').value||3} weeks`:`<strong>${from}</strong> to <strong>${to}</strong> (${dates.length} day${dates.length!==1?'s':''})`;
  txt+=`<br>Pay: <strong style="color:${payVal==='unpaid'?'var(--r)':payVal==='paid'?'var(--gr)':'var(--y)'}">${payLabel[payVal]}</strong>`;
  txt+=affectsRel===false?` · <span style="color:var(--gr)">✓ Reliability protected</span>`:` · <span style="color:var(--r)">Affects reliability</span>`;
  if(payOvr)txt+=` · <span style="color:var(--y)">Pay Override ON</span>`;
  txt+=`<br>📱 SMS notification queued for each worker with a phone number.`;
  preview.innerHTML=txt;
  preview.style.display='block';
}

function saveExcuses(){
  const selected=[...document.querySelectorAll('.exc-chk:checked')].map(c=>c.dataset.id);
  if(!selected.length){toast('Select at least one worker');return;}
  const from=document.getElementById('exc-from').value;
  const to=document.getElementById('exc-to').value;
  if(!from||!to){toast('Set a date range');return;}
  const payType=document.querySelector('input[name="exc-pay"]:checked')?.value||'unpaid';
  const reason=document.getElementById('exc-reason').value.trim();
  const recurring=document.getElementById('exc-recurring').checked;
  const recurPattern=document.getElementById('exc-recur-pattern').value;
  const recurWeeks=parseInt(document.getElementById('exc-recur-weeks').value)||3;
  const affectsReliability=document.getElementById('exc-affects-rel').checked;
  const payOverride=document.getElementById('exc-pay-override').checked;
  const dates=buildExcuseDates();
  const exc={
    id:uid(),
    workerIds:selected,
    fromDate:from,
    toDate:to,
    payType,
    reason:reason||'Excused by employer',
    excusedBy:EMPLOYER_NAME,
    dates,
    recurring,
    recurPattern:recurring?recurPattern:null,
    recurWeeks:recurring?recurWeeks:null,
    affectsReliability,
    payOverride,
    createdAt:new Date().toISOString()
  };
  Excuses.push(exc);
  // Check entitlement for each selected worker and auto-escalate if exceeded
  selected.forEach(wId=>{
    const w=W.find(x=>x.id===wId);if(!w)return;
    if(w.aeEnabled){
      const status=getEntitlementStatus(w);
      if(status&&status.exceeded){
        const exceedAction=w.aeExceed||'flag';
        // Auto-log to dispute
        D.push({id:uid(),workerId:wId,workerName:w.name,type:'attendance',
          details:`Absence Entitlement exceeded: ${status.used} days used of ${status.allowed} allowed per ${AE_PERIOD_LABELS[status.period]}. Excuse: ${reason||'Excused by employer'}. Pay Override: ${payOverride?'YES':'NO'}.`,
          status:'open',time:new Date().toLocaleString('en-ZA'),auto:true});
        // SMS notify if configured
        if(exceedAction==='notify'&&w.phone){
          SmsQueue.push({id:uid(),workerId:wId,workerName:w.name,phone:w.phone,
            message:`VEE ALERT: ${w.name} has exceeded their absence entitlement (${status.used}/${status.allowed} days this ${AE_PERIOD_LABELS[status.period]}). Please review.`,
            type:'entitlement-exceeded',scheduled:now(),status:'pending'});
        }
        toast(`⚠ ${w.name} exceeded entitlement — logged to disputes`);
      }
    }
    // Queue excuse SMS
    if(!w.phone)return;
    const dateStr=from===to?from:`${from} to ${to}`;
    const payMsg={unpaid:'This is unpaid leave.',paid:'You will receive full pay.',halfday:'You will receive half-day pay.'};
    const overrideMsg=payOverride?' Your pay has been protected by your employer.':'';
    SmsQueue.push({id:uid(),workerId:wId,workerName:w.name,phone:w.phone,
      message:`VEE: You have been excused from ${dateStr}. ${reason?'Reason: '+reason+'. ':''} ${payMsg[payType]}${overrideMsg} Contact your employer for more info.`,
      type:'excuse',scheduled:now(),status:'pending'});
  });
  cm('mexc');
  renderAll();
  toast(`✓ ${selected.length} worker${selected.length!==1?'s':''} excused for ${dates.length} day${dates.length!==1?'s':''}`);
}

// ── ABSENCE ENTITLEMENT ───────────────────────────────────────────
const AE_PERIODS={week:7,month:30,term:91,year:365};
const AE_PERIOD_LABELS={week:'week',month:'month',term:'3-month term',year:'year'};

function toggleAEFields(){
  const on=document.getElementById('wae-enabled').checked;
  document.getElementById('wae-fields').style.display=on?'flex':'none';
  if(on)updAEPreview();
}

function updAEPreview(){
  const days=document.getElementById('wae-days').value||'3';
  const period=document.getElementById('wae-period').value||'month';
  const exceed=document.getElementById('wae-exceed').value||'flag';
  const exceedMap={flag:'disputes log entry only',unpaid:'disputes log + mark absence as unpaid',notify:'disputes log + SMS notification to employer'};
  const prev=document.getElementById('wae-preview');
  if(prev)prev.textContent=`Worker is entitled to ${days} excused day${days!=='1'?'s':''} per ${AE_PERIOD_LABELS[period]}. When exceeded: ${exceedMap[exceed]}.`;
}

function getExcusedDaysInPeriod(wId,period){
  const now=new Date();
  let fromDate;
  if(period==='week'){fromDate=new Date(now);fromDate.setDate(now.getDate()-now.getDay()+1);}
  else if(period==='month'){fromDate=new Date(now.getFullYear(),now.getMonth(),1);}
  else if(period==='term'){const m=now.getMonth();fromDate=new Date(now.getFullYear(),m-(m%3),1);}
  else{fromDate=new Date(now.getFullYear(),0,1);}
  const fromStr=fromDate.toISOString().slice(0,10);
  const toStr=now.toISOString().slice(0,10);
  const used=new Set();
  Excuses.filter(ex=>ex.workerIds.includes(wId)).forEach(ex=>{
    ex.dates.forEach(d=>{if(d>=fromStr&&d<=toStr)used.add(d);});
  });
  return used.size;
}

function getEntitlementStatus(w){
  if(!w.aeEnabled)return null;
  const used=getExcusedDaysInPeriod(w.id,w.aePeriod||'month');
  const allowed=+(w.aeDays||3);
  return{used,allowed,exceeded:used>allowed,remaining:Math.max(0,allowed-used),period:w.aePeriod||'month'};
}

// ── LEAVE CALENDAR ────────────────────────────────────────────────
let calYear=new Date().getFullYear();
let calMonth=new Date().getMonth();

function calNav(dir){
  if(dir===0){calYear=new Date().getFullYear();calMonth=new Date().getMonth();}
  else{calMonth+=dir;if(calMonth>11){calMonth=0;calYear++;}else if(calMonth<0){calMonth=11;calYear--;}}
  renderCalendar();
}

function renderCalendar(){
  const monthNames=['January','February','March','April','May','June','July','August','September','October','November','December'];
  const lbl=document.getElementById('cal-month-label');
  if(lbl)lbl.textContent=`${monthNames[calMonth]} ${calYear}`;
  const daysInMonth=new Date(calYear,calMonth+1,0).getDate();
  const days=[];
  for(let d=1;d<=daysInMonth;d++){
    const dt=`${calYear}-${String(calMonth+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
    const dow=new Date(calYear,calMonth,d).getDay();
    days.push({d,dt,dow,isWeekend:dow===0||dow===6});
  }
  const grid=document.getElementById('cal-grid');
  const aeList=document.getElementById('cal-entitlement-list');
  if(!grid)return;
  if(!W.length){
    grid.innerHTML=`<div style="color:var(--g);font-size:13px;text-align:center;padding:20px;">No workers yet.</div>`;
    if(aeList)aeList.innerHTML='';return;
  }
  const dayNames=['Su','Mo','Tu','We','Th','Fr','Sa'];
  let html=`<div style="display:grid;grid-template-columns:140px repeat(${daysInMonth},minmax(22px,1fr));gap:1px;background:var(--bd);font-size:10px;">`;
  html+=`<div style="background:var(--surf2);padding:4px 6px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;color:var(--g);">Worker</div>`;
  days.forEach(({d,dow,isWeekend})=>{
    html+=`<div style="background:${isWeekend?'rgba(42,42,42,.6)':'var(--surf2)'};padding:2px;text-align:center;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;color:${isWeekend?'var(--g)':'var(--ow)'};">
      <div style="font-size:8px;color:var(--g);">${dayNames[dow]}</div>
      <div style="font-size:10px;">${d}</div>
    </div>`;
  });
  W.forEach(w=>{
    html+=`<div style="background:var(--surf);padding:5px 8px;font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ow);">${w.name}</div>`;
    days.forEach(({dt,isWeekend})=>{
      const exc=Excuses.find(ex=>ex.workerIds.includes(w.id)&&ex.dates.includes(dt));
      let bg=isWeekend?'rgba(20,20,20,.6)':'var(--surf)';
      let border='';let tipText='';
      if(exc){
        const pt=exc.payType||'unpaid';
        if(exc.payOverride)bg='rgba(167,139,250,.2)';
        else bg=pt==='paid'?'rgba(76,175,80,.25)':pt==='halfday'?'rgba(255,205,17,.2)':'rgba(244,67,54,.3)';
        border=exc.affectsReliability===false?';outline:1px dashed rgba(167,139,250,.5)':'';
        tipText=`${w.name}: ${exc.reason||'Excused'} (${pt})`;
      }
      html+=`<div style="background:${bg}${border};min-height:26px;" title="${tipText}"></div>`;
    });
  });
  html+=`</div>`;
  grid.innerHTML=html;
  // Entitlement summary
  if(aeList){
    const rows=W.filter(w=>w.aeEnabled).map(w=>{
      const s=getEntitlementStatus(w);if(!s)return'';
      const pct=Math.min(100,Math.round((s.used/s.allowed)*100));
      const bc=s.exceeded?'var(--r)':pct>=75?'var(--o)':'var(--gr)';
      return`<div style="display:flex;align-items:center;gap:12px;padding:8px 0;border-bottom:1px solid var(--bd);flex-wrap:wrap;">
        <div style="min-width:130px;font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;">${w.name}</div>
        <div style="flex:1;min-width:100px;">
          <div style="height:6px;background:var(--surf2);"><div style="height:100%;width:${pct}%;background:${bc};"></div></div>
          <div style="font-size:10px;color:var(--g);margin-top:2px;">${s.used} / ${s.allowed} days this ${AE_PERIOD_LABELS[s.period]}</div>
        </div>
        <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:15px;color:${bc}">${s.used}/${s.allowed}</div>
        ${s.exceeded?`<span style="font-size:10px;background:rgba(244,67,54,.12);color:var(--r);padding:2px 8px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;">⚠ Exceeded</span>`:''}
      </div>`;
    }).join('');
    aeList.innerHTML=rows||`<div style="color:var(--g);font-size:13px;text-align:center;padding:16px;">No workers have Absence Entitlement enabled. Set it in Edit Worker.</div>`;
  }
}

// ── WORKER ACTIONS DROPDOWN ───────────────────────────────────────
function toggleWorkerActions(){
  const menu=document.getElementById('worker-actions-menu');
  const chevron=document.getElementById('worker-actions-chevron');
  const open=menu.style.display!=='none';
  menu.style.display=open?'none':'block';
  if(chevron)chevron.style.transform=open?'rotate(0deg)':'rotate(180deg)';
}
function closeWorkerActions(){
  const menu=document.getElementById('worker-actions-menu');
  const chevron=document.getElementById('worker-actions-chevron');
  if(menu)menu.style.display='none';
  if(chevron)chevron.style.transform='rotate(0deg)';
}
function toggleWIActions(){
  const menu=document.getElementById('wi-actions-menu');
  const chevron=document.getElementById('wi-actions-chevron');
  const open=menu.style.display!=='none';
  menu.style.display=open?'none':'block';
  if(chevron)chevron.style.transform=open?'rotate(0deg)':'rotate(180deg)';
}
function closeWIActions(){
  const menu=document.getElementById('wi-actions-menu');
  const chevron=document.getElementById('wi-actions-chevron');
  if(menu)menu.style.display='none';
  if(chevron)chevron.style.transform='rotate(0deg)';
}
document.addEventListener('click',e=>{
  const wrap=document.getElementById('worker-actions-wrap');
  if(wrap&&!wrap.contains(e.target))closeWorkerActions();
  const wiwrap=document.getElementById('wi-actions-wrap');
  if(wiwrap&&!wiwrap.contains(e.target))closeWIActions();
});

// ── MAKE-UP SCHEDULE ──────────────────────────────────────────────

function openMakeupModal(){
  if(!W.length){toast('Add workers first');return;}
  _openMakeupModalCore(null);
}
function openMakeupModalFor(wId){
  _openMakeupModalCore(wId);
}
function _openMakeupModalCore(preselectId){
  mkSelectedDates=new Set();
  mkCalYear=new Date().getFullYear();
  mkCalMonth=new Date().getMonth();
  document.getElementById('mk-standard').checked=true;
  document.getElementById('mk-custom-field').style.display='none';
  document.getElementById('mk-note').value='';
  document.getElementById('mk-preview').style.display='none';
  document.getElementById('mk-custom-amount').value='';
  updMkPayBoxes();
  // Worker list
  document.getElementById('mk-worker-list').innerHTML=W.map(w=>`
    <label style="display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--bd);cursor:pointer;transition:background .15s;" onmouseover="this.style.background='rgba(255,255,255,.03)'" onmouseout="this.style.background='transparent'">
      <input type="checkbox" class="mk-chk" data-id="${w.id}" ${preselectId===w.id?'checked':''} style="accent-color:var(--gr);width:15px;height:15px;flex-shrink:0;" onchange="updMkPreview()"/>
      <div style="flex:1;">
        <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;">${w.name}${w.isTest?' <span style="font-size:10px;color:var(--pu)">(Test)</span>':''}</div>
        <div style="font-size:11px;color:var(--g);">${w.role||'Worker'} · ${ptL(w.payType)}</div>
      </div>
      ${getMakeupCount(w.id)?`<span style="font-size:10px;background:rgba(76,175,80,.12);color:var(--gr);padding:2px 8px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;">${getMakeupCount(w.id)} day${getMakeupCount(w.id)!==1?'s':''}</span>`:''}
    </label>`).join('');
  renderMkCal();
  document.getElementById('mmakeup').classList.add('open');
}
function getMakeupCount(wId){
  return Makeups.filter(m=>m.workerIds.includes(wId)).reduce((s,m)=>s+m.dates.length,0);
}
function mkSelectAll(){document.querySelectorAll('.mk-chk').forEach(c=>{c.checked=true;});updMkPreview();}
function mkSelectNone(){document.querySelectorAll('.mk-chk').forEach(c=>{c.checked=false;});updMkPreview();}
function mkCalNav(dir){
  mkCalMonth+=dir;
  if(mkCalMonth>11){mkCalMonth=0;mkCalYear++;}
  else if(mkCalMonth<0){mkCalMonth=11;mkCalYear--;}
  renderMkCal();
}
function renderMkCal(){
  const mNames=['January','February','March','April','May','June','July','August','September','October','November','December'];
  const lbl=document.getElementById('mk-cal-label');
  if(lbl)lbl.textContent=mNames[mkCalMonth]+' '+mkCalYear;
  const dim=new Date(mkCalYear,mkCalMonth+1,0).getDate();
  const firstDow=new Date(mkCalYear,mkCalMonth,1).getDay();
  const dNames=['Su','Mo','Tu','We','Th','Fr','Sa'];
  const td=today();
  let html=`<div style="display:grid;grid-template-columns:repeat(7,1fr);gap:3px;text-align:center;">`;
  dNames.forEach(d=>{html+=`<div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;color:var(--g);padding:3px 0;">${d}</div>`;});
  for(let i=0;i<firstDow;i++)html+=`<div></div>`;
  for(let d=1;d<=dim;d++){
    const dt=`${mkCalYear}-${String(mkCalMonth+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
    const sel=mkSelectedDates.has(dt);
    const dow=new Date(mkCalYear,mkCalMonth,d).getDay();
    const isWe=dow===0||dow===6;
    const isPast=dt<td;
    html+=`<div onclick="${isPast?'':'mkToggleDate(\''+dt+'\')'}" style="padding:6px 2px;cursor:${isPast?'default':'pointer'};font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:600;
      background:${sel?'var(--gr)':isWe?'rgba(42,42,42,.4)':'var(--surf2)'};
      color:${sel?'#fff':isPast?'rgba(136,136,128,.35)':isWe?'var(--g)':'var(--ow)'};
      border:1px solid ${sel?'var(--gr)':'transparent'};transition:all .12s;"
      onmouseover="if(!${isPast})this.style.borderColor='var(--gr)'"
      onmouseout="this.style.borderColor='${sel?'var(--gr)':'transparent'}'">
      ${d}</div>`;
  }
  html+=`</div>`;
  const grid=document.getElementById('mk-cal-grid');
  if(grid)grid.innerHTML=html;
  const sel=[...mkSelectedDates].sort();
  const lbl2=document.getElementById('mk-selected-dates');
  if(lbl2)lbl2.textContent=sel.length?sel.length+' day'+(sel.length!==1?'s':'')+' selected: '+sel.join(', '):'Tap any date to select it. You can pick across multiple months.';
}
function mkToggleDate(dt){
  if(mkSelectedDates.has(dt))mkSelectedDates.delete(dt);else mkSelectedDates.add(dt);
  renderMkCal();updMkPreview();
}
function updMkPayBoxes(){
  const val=document.querySelector('input[name="mk-pay"]:checked')?.value||'standard';
  const cols={standard:'var(--y)',double:'var(--gr)',custom:'var(--pu)'};
  const bgs={standard:'rgba(255,205,17,.08)',double:'rgba(76,175,80,.08)',custom:'rgba(167,139,250,.08)'};
  ['standard','double','custom'].forEach(v=>{
    const box=document.getElementById('mk-'+v+'-box');
    if(!box)return;
    box.style.borderColor=v===val?cols[v]:'var(--bd)';
    box.style.background=v===val?bgs[v]:'transparent';
  });
  const cf=document.getElementById('mk-custom-field');
  if(cf)cf.style.display=val==='custom'?'block':'none';
  updMkPreview();
}
function updMkPayFields(){updMkPayBoxes();}
function updMkPreview(){
  const selected=[...document.querySelectorAll('.mk-chk:checked')].map(c=>c.dataset.id);
  const dates=[...mkSelectedDates].sort();
  const payVal=document.querySelector('input[name="mk-pay"]:checked')?.value||'standard';
  const customAmt=document.getElementById('mk-custom-amount')?.value;
  const preview=document.getElementById('mk-preview');
  if(!preview)return;
  if(!selected.length||!dates.length){preview.style.display='none';return;}
  const payLabel={standard:'Standard pay (normal rate)',double:'Double pay (2× their rate)',custom:customAmt?`Custom R${customAmt} per day`:'Custom (amount not set yet)'};
  const names=selected.map(id=>W.find(w=>w.id===id)?.name).filter(Boolean);
  preview.innerHTML=`<strong style="color:var(--gr)">${names.length} worker${names.length!==1?'s':''}</strong> scheduled for <strong>${dates.length} make-up day${dates.length!==1?'s':''}</strong><br>Dates: ${dates.slice(0,5).join(', ')}${dates.length>5?' + '+(dates.length-5)+' more':''}<br>Pay: <strong style="color:var(--y)">${payLabel[payVal]}</strong>`;
  preview.style.display='block';
}
function saveMakeup(){
  const selected=[...document.querySelectorAll('.mk-chk:checked')].map(c=>c.dataset.id);
  if(!selected.length){toast('Select at least one worker');return;}
  const dates=[...mkSelectedDates].sort();
  if(!dates.length){toast('Select at least one make-up date');return;}
  const payType=document.querySelector('input[name="mk-pay"]:checked')?.value||'standard';
  const customAmount=payType==='custom'?parseFloat(document.getElementById('mk-custom-amount').value)||0:null;
  if(payType==='custom'&&!customAmount){toast('Enter a custom pay amount');return;}
  const note=document.getElementById('mk-note').value.trim();
  Makeups.push({id:uid(),workerIds:selected,dates,payType,customAmount,
    note:note||'Compensation days scheduled',createdBy:EMPLOYER_NAME,createdAt:new Date().toISOString()});
  cm('mmakeup');renderAll();
  toast(`✓ Compensation days saved — ${selected.length} worker${selected.length!==1?'s':''}, ${dates.length} day${dates.length!==1?'s':''}`);
}

// ── OVERTIME / BONUS DAYS ─────────────────────────────────────────
let obCalYear=new Date().getFullYear(),obCalMonth=new Date().getMonth(),obSelectedDates=new Set();

function openOvertimeBonusModal(){
  if(!W.length){toast('Add workers first');return;}
  _openOvertimeBonusCore(null);
}
function openOvertimeBonusFor(wId){_openOvertimeBonusCore(wId);}
function _openOvertimeBonusCore(preselectId){
  obSelectedDates=new Set();
  obCalYear=new Date().getFullYear();obCalMonth=new Date().getMonth();
  document.getElementById('ob-standard').checked=true;
  document.getElementById('ob-bonus-field').style.display='none';
  document.getElementById('ob-note').value='';
  document.getElementById('ob-preview').style.display='none';
  document.getElementById('ob-bonus-amount').value='';
  updObPayBoxes();
  document.getElementById('ob-worker-list').innerHTML=W.map(w=>`
    <label style="display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--bd);cursor:pointer;transition:background .15s;" onmouseover="this.style.background='rgba(255,255,255,.03)'" onmouseout="this.style.background='transparent'">
      <input type="checkbox" class="ob-chk" data-id="${w.id}" ${preselectId===w.id?'checked':''} style="accent-color:var(--pu);width:15px;height:15px;flex-shrink:0;" onchange="updObPreview()"/>
      <div style="flex:1;">
        <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;">${w.name}${w.isTest?' <span style="font-size:10px;color:var(--pu)">(Test)</span>':''}</div>
        <div style="font-size:11px;color:var(--g);">${w.role||'Worker'} · ${ptL(w.payType)}</div>
      </div>
    </label>`).join('');
  renderObCal();
  document.getElementById('movertimebonus').classList.add('open');
}
function obSelectAll(){document.querySelectorAll('.ob-chk').forEach(c=>{c.checked=true;});updObPreview();}
function obSelectNone(){document.querySelectorAll('.ob-chk').forEach(c=>{c.checked=false;});updObPreview();}
function obCalNav(dir){
  obCalMonth+=dir;
  if(obCalMonth>11){obCalMonth=0;obCalYear++;}else if(obCalMonth<0){obCalMonth=11;obCalYear--;}
  renderObCal();
}
function renderObCal(){
  const mNames=['January','February','March','April','May','June','July','August','September','October','November','December'];
  const lbl=document.getElementById('ob-cal-label');
  if(lbl)lbl.textContent=mNames[obCalMonth]+' '+obCalYear;
  const dim=new Date(obCalYear,obCalMonth+1,0).getDate();
  const firstDow=new Date(obCalYear,obCalMonth,1).getDay();
  const dNames=['Su','Mo','Tu','We','Th','Fr','Sa'];
  const td=today();
  let html=`<div style="display:grid;grid-template-columns:repeat(7,1fr);gap:3px;text-align:center;">`;
  dNames.forEach(d=>{html+=`<div style="font-size:9px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;color:var(--g);padding:3px 0;">${d}</div>`;});
  for(let i=0;i<firstDow;i++)html+=`<div></div>`;
  for(let d=1;d<=dim;d++){
    const dt=`${obCalYear}-${String(obCalMonth+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
    const sel=obSelectedDates.has(dt);
    const dow=new Date(obCalYear,obCalMonth,d).getDay();
    const isWe=dow===0||dow===6;
    const isPast=dt<td;
    html+=`<div onclick="${isPast?'':'obToggleDate(\''+dt+'\')'}" style="padding:6px 2px;cursor:${isPast?'default':'pointer'};font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:600;
      background:${sel?'var(--pu)':isWe?'rgba(42,42,42,.4)':'var(--surf2)'};
      color:${sel?'#fff':isPast?'rgba(136,136,128,.35)':isWe?'var(--g)':'var(--ow)'};
      border:1px solid ${sel?'var(--pu)':'transparent'};transition:all .12s;"
      onmouseover="if(!${isPast})this.style.borderColor='var(--pu)'"
      onmouseout="this.style.borderColor='${sel?'var(--pu)':'transparent'}'">
      ${d}</div>`;
  }
  html+=`</div>`;
  const grid=document.getElementById('ob-cal-grid');if(grid)grid.innerHTML=html;
  const sel=[...obSelectedDates].sort();
  const lbl2=document.getElementById('ob-selected-dates');
  if(lbl2)lbl2.textContent=sel.length?sel.length+' day'+(sel.length!==1?'s':'')+' selected: '+sel.join(', '):'Tap any date to select OT or bonus days.';
}
function obToggleDate(dt){
  if(obSelectedDates.has(dt))obSelectedDates.delete(dt);else obSelectedDates.add(dt);
  renderObCal();updObPreview();
}
function updObPayBoxes(){
  const val=document.querySelector('input[name="ob-pay"]:checked')?.value||'standard';
  const cols={standard:'var(--y)',double:'var(--gr)',bonus:'var(--pu)'};
  const bgs={standard:'rgba(255,205,17,.08)',double:'rgba(76,175,80,.08)',bonus:'rgba(167,139,250,.08)'};
  ['standard','double','bonus'].forEach(v=>{
    const box=document.getElementById('ob-'+v+'-box');
    if(!box)return;
    box.style.borderColor=v===val?cols[v]:'var(--bd)';
    box.style.background=v===val?bgs[v]:'transparent';
  });
  const bf=document.getElementById('ob-bonus-field');
  if(bf)bf.style.display=val==='bonus'?'block':'none';
  updObPreview();
}
function updObPreview(){
  const selected=[...document.querySelectorAll('.ob-chk:checked')].map(c=>c.dataset.id);
  const dates=[...obSelectedDates].sort();
  const payVal=document.querySelector('input[name="ob-pay"]:checked')?.value||'standard';
  const bonusAmt=document.getElementById('ob-bonus-amount')?.value;
  const preview=document.getElementById('ob-preview');
  if(!preview)return;
  if(!selected.length||!dates.length){preview.style.display='none';return;}
  const payLabel={standard:'1.5× overtime rate',double:'2× double pay (Sunday/PH)',bonus:bonusAmt?`R${bonusAmt} bonus per day`:'Bonus (amount not set)'};
  const names=selected.map(id=>W.find(w=>w.id===id)?.name).filter(Boolean);
  preview.innerHTML=`<strong style="color:var(--pu)">${names.length} worker${names.length!==1?'s':''}</strong> scheduled for <strong>${dates.length} OT/bonus day${dates.length!==1?'s':''}</strong><br>Dates: ${dates.slice(0,5).join(', ')}${dates.length>5?' + '+(dates.length-5)+' more':''}<br>Pay: <strong style="color:var(--y)">${payLabel[payVal]}</strong>`;
  preview.style.display='block';
}
function saveOvertimeBonus(){
  const selected=[...document.querySelectorAll('.ob-chk:checked')].map(c=>c.dataset.id);
  if(!selected.length){toast('Select at least one worker');return;}
  const dates=[...obSelectedDates].sort();
  if(!dates.length){toast('Select at least one date');return;}
  const payType=document.querySelector('input[name="ob-pay"]:checked')?.value||'standard';
  const bonusAmount=payType==='bonus'?parseFloat(document.getElementById('ob-bonus-amount').value)||0:null;
  if(payType==='bonus'&&!bonusAmount){toast('Enter a bonus amount');return;}
  const note=document.getElementById('ob-note').value.trim();
  OvertimeBonuses.push({id:uid(),workerIds:selected,dates,payType,bonusAmount,
    note:note||'Overtime / bonus days',createdBy:EMPLOYER_NAME,createdAt:new Date().toISOString()});
  cm('movertimebonus');renderAll();
  toast(`✓ OT/Bonus days saved — ${selected.length} worker${selected.length!==1?'s':''}, ${dates.length} day${dates.length!==1?'s':''}`);
}

let globalGeoEnabled=false;

function effectiveGeo(w){
  if(w.geoFence==='enabled')return true;
  if(w.geoFence==='disabled')return false;
  return globalGeoEnabled; // 'default'
}

function toggleGlobalGeo(){
  globalGeoEnabled=!globalGeoEnabled;
  const btn=document.getElementById('global-geo-btn');
  const lbl=document.getElementById('global-geo-label');
  if(globalGeoEnabled){
    btn.style.background='rgba(76,175,80,.1)';btn.style.borderColor='rgba(76,175,80,.3)';
    lbl.textContent='Geo-Fence: ON';lbl.style.color='var(--gr)';
  }else{
    btn.style.background='rgba(244,67,54,.08)';btn.style.borderColor='rgba(244,67,54,.25)';
    lbl.textContent='Geo-Fence: OFF';lbl.style.color='var(--r)';
  }
  renderWorkerGrid();
  toast('Global geo-fence '+(globalGeoEnabled?'enabled — all Default workers now require location':'disabled — Default workers can check in from anywhere'));
}

function updGeoPreview(){
  // Highlight selected option box
  ['enable','default','disable'].forEach(v=>{
    const box=document.getElementById('wgeo-'+v+'-box');
    const radio=document.getElementById('wgeo-'+v);
    if(!box||!radio)return;
    if(radio.checked){
      const c=v==='enable'?'var(--gr)':v==='default'?'var(--y)':'var(--r)';
      box.style.borderColor=c;box.style.background=v==='enable'?'rgba(76,175,80,.08)':v==='default'?'rgba(255,205,17,.06)':'rgba(244,67,54,.06)';
    }else{
      box.style.borderColor='var(--bd)';box.style.background='transparent';
    }
  });
  // Preview text
  const val=document.querySelector('input[name="wgeo"]:checked')?.value||'default';
  const note=document.getElementById('wgeo-global-note');
  const preview=document.getElementById('wgeo-preview');
  const globalStr=globalGeoEnabled?'ON':'OFF';
  if(note)note.textContent=`Global geo-fence is currently ${globalStr}.`;
  if(preview){
    if(val==='enabled')preview.textContent='This worker must always be within the site geo-fence to receive a valid check-in code. Overrides the global setting.';
    else if(val==='disabled')preview.textContent='This worker can check in from any location — geo-fence is never required for them. Overrides the global setting.';
    else preview.textContent=`This worker follows the global setting. Currently: geo-fence ${globalStr}. Changes when the employer toggles the global switch.`;
  }
}

// Check if a worker passes geo requirement (in demo, simulated)
function geoCheck(w){
  const required=effectiveGeo(w);
  if(!required)return{pass:true,msg:''};
  // In demo — simulate: geo always passes unless demo mode simulates failure
  return{pass:true,msg:''};
}

// Simulate a geo failure for a specific worker (for demo purposes)
function demoSimulateGeoFail(wId){
  const w=W.find(x=>x.id===wId);if(!w)return;
  const required=effectiveGeo(w);
  if(!required){toast(w.name+' has geo-fence disabled — no failure possible');return;}
  Susp.push({id:uid(),type:'geofence-fail',workerName:w.name,note:`${w.name} attempted to check in from outside the site geo-fence boundary (simulated: 2.3km away). Geo-fence setting: ${w.geoFence||'default'} (effective: ON).`,code:'',site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy:'System',portal:'Geo-Fence Check'});
  renderSuspicious();toast('⚠ Geo-fence failure simulated for '+w.name);
}

function delW(id){if(!confirm('Remove worker?'))return;W=W.filter(x=>x.id!==id);renderAll();toast('Removed');}

function updWDrops(){
  const opts='<option value="">Select worker...</option>'+W.map(w=>`<option value="${w.id}">${w.name}${w.isTest?' (Test)':''}</option>`).join('');
  document.getElementById('dw').innerHTML=opts;
  const csel=document.getElementById('clerk-worker-sel');
  if(csel)csel.innerHTML='<option value="">Select worker...</option>'+W.map(w=>`<option value="${w.id}">${w.name}${w.isTest?' (Test)':''}</option>`).join('');
}

// ── SITES ─────────────────────────────────────────────────────────
function renderSites(){
  const div=document.getElementById('slist');
  if(!S.length){div.innerHTML=`<div style="color:var(--g);font-size:13px;text-align:center;padding:16px">No sites yet.</div>`;return;}
  div.innerHTML=S.map(s=>`<div style="display:flex;align-items:center;justify-content:space-between;background:var(--surf2);border:1px solid var(--bd);border-left:3px solid var(--y);padding:12px 16px;">
    <div><div style="font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;font-size:13px">${s.name}</div>${s.desc?`<div style="font-size:11px;color:var(--g);margin-top:1px">${s.desc}</div>`:''}</div>
    <button onclick="delSite('${s.id}')" style="background:transparent;border:1px solid var(--bd);color:var(--g);width:28px;height:28px;cursor:pointer;font-size:12px;transition:all .2s;" onmouseover="this.style.borderColor='var(--r)';this.style.color='var(--r)'" onmouseout="this.style.borderColor='var(--bd)';this.style.color='var(--g)'">🗑</button>
  </div>`).join('');
  updEmpDrops();
}

function openAddSite(){document.getElementById('snam').value='';document.getElementById('sdesc').value='';document.getElementById('ms').classList.add('open');}
function saveSite(){const name=document.getElementById('snam').value.trim();if(!name){toast('Enter site name');return;}S.push({id:uid(),name,desc:document.getElementById('sdesc').value.trim(),isTest:false});cm('ms');renderSites();toast('Site added');}
function delSite(id){S=S.filter(x=>x.id!==id);renderSites();toast('Site removed');}

// ── DISPUTES ──────────────────────────────────────────────────────
function renderDisputes(){
  const div=document.getElementById('dlist');
  if(!D.length){div.innerHTML=`<div style="color:var(--g);font-size:13px;text-align:center;padding:16px">No disputes logged.</div>`;return;}
  const TC={dispute:'#F44336',attendance:'#FFCD11',incident:'#FF9800',warning:'#FF9800',note:'#888880'};
  const TL={dispute:'Payroll Dispute',attendance:'Attendance',incident:'Incident',warning:'Warning',note:'Note'};
  div.innerHTML=D.map(d=>{
    const w=W.find(x=>x.id===d.workerId);
    const c=TC[d.type]||'#888880';
    return`<div style="display:flex;gap:12px;padding:12px 16px;border-bottom:1px solid var(--bd);align-items:flex-start;">
      <div style="width:8px;height:8px;border-radius:50%;background:${c};margin-top:5px;flex-shrink:0;"></div>
      <div style="flex:1">
        <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:3px">
          <span style="font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;font-size:13px">${w?w.name:'Unknown'}</span>
          <span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;padding:2px 7px;background:${c}22;color:${c}">${TL[d.type]||d.type}</span>
        </div>
        <div style="font-size:13px;color:var(--ow)">${d.details}</div>
        <div style="font-size:11px;color:var(--g);margin-top:3px;font-family:'Barlow Semi Condensed',sans-serif">${d.time}</div>
      </div>
    </div>`;
  }).join('');
}

function openAddDispute(){updWDrops();document.getElementById('ddet').value='';document.getElementById('mdisp').classList.add('open');}
function saveDispute(){const det=document.getElementById('ddet').value.trim();if(!det){toast('Enter details');return;}const wId=document.getElementById('dw').value;const w=W.find(x=>x.id===wId);D.push({id:uid(),workerId:wId,workerName:w?w.name:'',type:document.getElementById('dtype').value,details:det,status:'open',time:new Date().toLocaleString('en-ZA')});cm('mdisp');renderDisputes();calcHS();toast('Dispute logged');}

// ── EXPORT ────────────────────────────────────────────────────────
function renderExport(){
  const realW=W.filter(w=>!w.isTest);
  const div=document.getElementById('exprev');
  if(!realW.length){div.innerHTML=`<div style="padding:24px;text-align:center;color:var(--g);font-size:13px;">No real workers yet.</div>`;return;}
  const td=today();
  const rows=realW.map(w=>{
    const wE=E.filter(x=>x.workerId===w.id&&x.date===td&&!x.isTest);
    const tH=wE.reduce((s,x)=>s+(+x.hours||0),0);
    const pay=tH?calcPay(w,tH):null;
    const ci=Checkins.find(c=>c.workerId===w.id&&c.date===td);
    return{w,tH,pay,ci};
  });
  div.innerHTML=`<div class="tw"><table>
    <thead><tr><th>Worker</th><th>Role</th><th>Pay Type</th><th>Rate</th><th>Check-In</th><th>Site</th><th>Hours</th><th>Est. Pay</th></tr></thead>
    <tbody>${rows.map(r=>{
      const hasHours=r.tH>0;
      const site=E.find(e=>e.workerId===r.w.id&&e.date===td)?.site||'—';
      return`<tr style="${!hasHours?'opacity:.5':''}">
        <td><span class="wn">${r.w.name}</span></td>
        <td style="font-size:12px;color:var(--g)">${r.w.role||'—'}</td>
        <td><span class="ptag">${ptL(r.w.payType)}</span></td>
        <td style="font-size:12px;color:var(--g)">${ptF(r.w)}</td>
        <td style="font-size:12px;">${r.ci?`<span style="color:var(--gr)">✓ ${r.ci.time}</span>`:`<span style="color:var(--g)">—</span>`}</td>
        <td style="font-size:12px;color:var(--g)">${site}</td>
        <td><span class="hv" style="font-size:16px;${!hasHours?'color:var(--g)':''}">${r.tH||'—'}</span></td>
        <td style="color:var(--y);font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:16px;">${r.pay!=null?'R'+r.pay.toFixed(0):'—'}</td>
      </tr>`;
    }).join('')}</tbody>
  </table></div>`;
}

// ── EXCEL EXPORT (today) ──────────────────────────────────────────
function exportXl(){
  const td=today();
  const data=buildPaysheetData({from:td,to:td,site:'',paytype:'',absent:false});
  downloadExcel(data,`VEE-Industrial-Payroll-${td}.xlsx`,'Today\'s Payroll',td);
}

// ── PDF EXPORT (today) ───────────────────────────────────────────
function exportPdf(){
  const td=today();
  const data=buildPaysheetData({from:td,to:td,site:'',paytype:'',absent:false});
  openPdfWindow(data,'VEE Industrial — Daily Payroll',td);
}

// ── PAYSHEET DATA BUILDER ─────────────────────────────────────────
// ── PAYSHEET FILTER ───────────────────────────────────────────────
let psRange='week';

function openPaysheetFilter(){
  const sel=document.getElementById('ps-site');
  sel.innerHTML='<option value="">All Sites</option>'+S.map(s=>`<option value="${s.name}">${s.name}</option>`).join('');
  const td=today();
  const d=new Date();
  const mon=new Date(d);mon.setDate(d.getDate()-d.getDay()+1);
  const sun=new Date(mon);sun.setDate(mon.getDate()+6);
  document.getElementById('ps-from').value=mon.toISOString().slice(0,10);
  document.getElementById('ps-to').value=sun.toISOString().slice(0,10);
  document.getElementById('ps-absent').checked=false;
  psRange='week';
  // Reset range buttons
  document.getElementById('psrange-week').style.cssText='flex:1;background:var(--y);color:var(--bg);border:none;';
  document.getElementById('psrange-month').style.cssText='flex:1;';
  document.getElementById('psrange-custom').style.cssText='flex:1;';
  document.getElementById('ps-custom-dates').style.display='none';
  updPsPreview();
  document.getElementById('mps').classList.add('open');
}

function setPsRange(range,btn){
  psRange=range;
  ['psrange-week','psrange-month','psrange-custom'].forEach(id=>{
    const b=document.getElementById(id);
    if(b)b.style.cssText=b.id===btn.id?'flex:1;background:var(--y);color:var(--bg);border:none;':'flex:1;';
  });
  document.getElementById('ps-custom-dates').style.display=range==='custom'?'flex':'none';
  const d=new Date();const td=today();
  if(range==='week'){
    const mon=new Date(d);mon.setDate(d.getDate()-d.getDay()+1);
    const sun=new Date(mon);sun.setDate(mon.getDate()+6);
    document.getElementById('ps-from').value=mon.toISOString().slice(0,10);
    document.getElementById('ps-to').value=sun.toISOString().slice(0,10);
  }else if(range==='month'){
    document.getElementById('ps-from').value=td.slice(0,7)+'-01';
    document.getElementById('ps-to').value=td;
  }
  updPsPreview();
}

function updPsPreview(){
  const from=document.getElementById('ps-from').value;
  const to=document.getElementById('ps-to').value;
  const site=document.getElementById('ps-site').value;
  const paytype=document.getElementById('ps-paytype').value;
  const absent=document.getElementById('ps-absent').checked;
  const data=buildPaysheetData({from,to,site,paytype,absent});
  const el=document.getElementById('ps-preview-count');
  if(el)el.textContent=`${data.length} worker${data.length!==1?'s':''} will appear — ${data.filter(r=>!r.absent).length} with hours, ${data.filter(r=>r.absent).length} absent`;
  const rangeLabel=psRange==='week'?'This Week':psRange==='month'?'This Month':(from&&to?`${from} to ${to}`:'Custom');
  const rd=document.getElementById('ps-range-display');if(rd)rd.textContent=rangeLabel;
  const sd=document.getElementById('ps-site-display');if(sd)sd.textContent=site||'All Sites';
  const td2=document.getElementById('ps-type-display');if(td2)td2.textContent=paytype?ptL(paytype):'All Types';
  const ad=document.getElementById('ps-absent-display');if(ad)ad.textContent=absent?'Included':'Excluded';
}

function runPaysheetExport(fmt){
  const from=document.getElementById('ps-from').value;
  const to=document.getElementById('ps-to').value;
  const site=document.getElementById('ps-site').value;
  const paytype=document.getElementById('ps-paytype').value;
  const absent=document.getElementById('ps-absent').checked;
  if(!from||!to){toast('Set a date range first');return;}
  const data=buildPaysheetData({from,to,site,paytype,absent});
  if(!data.length){toast('No workers match these filters');return;}
  const period=from===to?from:`${from} to ${to}`;
  const fname=`VEE-Industrial-Paysheet-${from}-${to}`;
  cm('mps');
  if(fmt==='excel')downloadExcel(data,fname+'.xlsx','Paysheet Export',period);
  else openPdfWindow(data,'VEE Industrial — Paysheet Export',period);
}

function buildPaysheetData({from,to,site,paytype,absent}){
  const realW=W.filter(w=>!w.isTest&&(!paytype||w.payType===paytype));
  const rows=[];
  realW.forEach(w=>{
    const wE=E.filter(e=>{
      if(e.workerId!==w.id||e.isTest)return false;
      if(e.date<from||e.date>to)return false;
      if(site&&e.site!==site)return false;
      return true;
    });
    const tH=wE.reduce((s,e)=>s+(+e.hours||0),0);
    if(!absent&&tH===0)return;
    const pay=tH?calcPay(w,tH):null;
    const sites=[...new Set(wE.map(e=>e.site).filter(Boolean))].join(', ')||'—';
    const ci=Checkins.find(c=>c.workerId===w.id&&c.date>=from&&c.date<=to);
    const pct=rel(w.id);
    rows.push({name:w.name,role:w.role||'',payType:ptL(w.payType),rate:ptF(w),checkin:ci?ci.time:'Not checked in',site:sites,hours:tH||0,pay:pay!=null?pay.toFixed(0):'—',reliability:pct+'%',absent:tH===0});
  });
  return rows;
}

// ── EXCEL DOWNLOAD ───────────────────────────────────────────────
function downloadExcel(rows,filename,title,period){
  const present=rows.filter(r=>!r.absent).length;
  const absent=rows.filter(r=>r.absent).length;
  const totalHrs=rows.reduce((s,r)=>s+(+r.hours||0),0);
  const gen=new Date().toLocaleDateString('en-ZA',{day:'2-digit',month:'short',year:'numeric'});

  const allRows=[
    // ── TITLE BLOCK ──────────────────────────────────────────────
    ['VEE INDUSTRIAL  —  PAYROLL EXPORT','','','','','','','','',''],
    ['Period:  '+period,'','','','','Generated:',''+gen,'','',''],
    ['','','','','','','','','',''],
    // ── SUMMARY ──────────────────────────────────────────────────
    ['SUMMARY','','','','','','','','',''],
    ['──────────','','','','','','','','',''],
    ['Total Workers',''+rows.length,'','Workers Present',''+present,'','Absent',''+absent,'','Total Hours: '+totalHrs],
    ['','','','','','','','','',''],
    // ── COLUMN HEADERS ───────────────────────────────────────────
    ['══════════════════════','══════════════','══════════════','══════════════','══════════════','══════════════════════','══════','════════════','════════════','══════'],
    ['WORKER','ROLE','PAY TYPE','RATE','CHECK-IN TIME','SITE(S)','HOURS','EST. PAY (R)','RELIABILITY','STATUS'],
    ['──────────────────────','──────────────','──────────────','──────────────','──────────────','──────────────────────','──────','────────────','────────────','──────'],
    // ── DATA ─────────────────────────────────────────────────────
    ...rows.map(r=>[
      r.name,
      r.role||'—',
      r.payType,
      r.rate,
      r.checkin,
      r.site||'—',
      r.hours||0,
      r.pay==='—'||!r.pay?0:Number(r.pay)||0,
      r.reliability,
      r.absent?'ABSENT':'PRESENT'
    ]),
    // ── FOOTER ───────────────────────────────────────────────────
    ['──────────────────────','──────────────','──────────────','──────────────','──────────────','──────────────────────','──────','────────────','────────────','──────'],
    ['TOTAL','','','','','',''+totalHrs+' hrs','','',''],
  ];

  const ws=XLSX.utils.aoa_to_sheet(allRows);

  ws['!cols']=[
    {wch:26},{wch:16},{wch:15},{wch:14},
    {wch:16},{wch:24},{wch:8},{wch:14},{wch:13},{wch:10}
  ];

  ws['!rows']=[
    {hpt:28},  // title
    {hpt:16},  // period/generated
    {hpt:8},   // blank
    {hpt:16},  // SUMMARY label
    {hpt:4},   // divider
    {hpt:18},  // summary values
    {hpt:8},   // blank
    {hpt:6},   // top border row
    {hpt:20},  // column headers
    {hpt:4},   // bottom border row
  ];

  ws['!merges']=[
    {s:{r:0,c:0},e:{r:0,c:9}},
    {s:{r:1,c:0},e:{r:1,c:4}},
    {s:{r:1,c:6},e:{r:1,c:9}},
  ];

  // Number format for pay column (column H = index 7)
  const dataStart=10;
  rows.forEach((r,i)=>{
    const ref=XLSX.utils.encode_cell({r:dataStart+i,c:7});
    if(ws[ref]&&typeof ws[ref].v==='number'&&ws[ref].v>0){
      ws[ref].z='#,##0';
    }
  });

  const wb=XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb,ws,'Payroll');
  XLSX.writeFile(wb,filename);
  toast('✓ Excel downloaded — '+rows.length+' workers');
}

// ── WORKER INFO MODAL ─────────────────────────────────────────────
let currentWIid=null;

function openWorkerInfo(id){
  const w=W.find(x=>x.id===id);if(!w)return;
  currentWIid=id;

  // Avatar + name
  document.getElementById('wi-avatar').textContent=w.name.charAt(0).toUpperCase();
  document.getElementById('wi-name').textContent=w.name;
  document.getElementById('wi-role').textContent=w.role||'Worker';

  // Badges
  const badges=[];
  if(w.isTest)badges.push(`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(167,139,250,.15);color:var(--pu);padding:2px 8px;">Test</span>`);
  if(w.isClerk)badges.push(`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(255,152,0,.15);color:var(--o);padding:2px 8px;">🔐 Clerk</span>`);
  if(w.isManager)badges.push(`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:rgba(167,139,250,.15);color:var(--pu);padding:2px 8px;">🔧 Manager</span>`);
  const geoEff=effectiveGeo(w);
  badges.push(`<span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:${geoEff?'rgba(76,175,80,.12)':'rgba(244,67,54,.1)'};color:${geoEff?'var(--gr)':'var(--r)'};padding:2px 8px;">🛰 Geo ${geoEff?'ON':'OFF'}</span>`);
  document.getElementById('wi-badges').innerHTML=badges.join('');

  // Contact + pay
  document.getElementById('wi-phone').textContent=w.phone||'No phone on file';
  document.getElementById('wi-expected').textContent=`Expected ${w.expectedDays||5} days/week`;
  document.getElementById('wi-paytype').textContent=ptL(w.payType);
  document.getElementById('wi-rate').textContent=ptF(w);

  // Shift rules
  const geoLabel=w.geoFence==='enabled'?'Always ON':w.geoFence==='disabled'?'Always OFF':'Default (follows global)';
  document.getElementById('wi-shift').innerHTML=`
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:4px 16px;">
      <div><span style="color:var(--g)">Shift hours:</span> ${w.shiftStart||'06:00'} – ${w.shiftEnd||'17:00'}</div>
      <div><span style="color:var(--g)">Geo:</span> ${geoLabel}</div>
      <div><span style="color:var(--g)">Check-in window:</span> ${w.loginFrom||'05:00'} – ${w.loginEarliest||'08:00'} <span style="font-size:10px;padding:1px 6px;background:${w.loginRule==='mandatory'?'rgba(244,67,54,.15)':'rgba(255,205,17,.12)'};color:${w.loginRule==='mandatory'?'var(--r)':'var(--y)'}">${(w.loginRule||'recommended').toUpperCase()}</span></div>
      <div><span style="color:var(--g)">Checkout window:</span> ${w.logoutFrom||'17:00'} – ${w.logoutLatest||'18:00'} <span style="font-size:10px;padding:1px 6px;background:${w.logoutRule==='mandatory'?'rgba(244,67,54,.15)':'rgba(255,205,17,.12)'};color:${w.logoutRule==='mandatory'?'var(--r)':'var(--y)'}">${(w.logoutRule||'recommended').toUpperCase()}</span></div>
    </div>`;

  // Reliability
  const pct=rel(id);
  const rc=pct>=85?'var(--gr)':pct>=60?'var(--y)':'var(--r)';
  document.getElementById('wi-reliability').innerHTML=`<span style="color:${rc}">${pct}%</span> <span style="font-size:11px;color:var(--g);font-family:'Barlow Semi Condensed',sans-serif;">reliability</span>`;

  // Check-in history
  const wCi=Checkins.filter(c=>c.workerId===id).slice(-10).reverse();
  const wEnt=E.filter(e=>e.workerId===id).slice(-10).reverse();
  document.getElementById('wi-checkins').innerHTML=wCi.length
    ?wCi.map(c=>{
        const e=wEnt.find(x=>x.date===c.date);
        return`<div style="display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid rgba(42,42,42,.3);font-family:'Barlow Semi Condensed',sans-serif;gap:8px;">
          <span style="color:var(--g);min-width:80px;">${c.date}</span>
          <span style="color:var(--gr);">✓ ${c.time}</span>
          <span style="font-family:'Barlow Condensed',sans-serif;font-weight:900;color:var(--y)">${e?e.hours+'hrs':'—'}</span>
          <span style="color:var(--g);font-size:11px;flex:1;text-align:right;">${e?.site||'—'}</span>
        </div>`;
      }).join('')
    :`<div style="color:var(--g);font-size:12px;text-align:center;padding:16px;">No check-in history yet.<br>Generate hours using Demo Controls.</div>`;

  // Excuse history
  const wExcuses=Excuses.filter(ex=>ex.workerIds.includes(id));
  const excDiv=document.getElementById('wi-excuses');
  if(excDiv){
    const payLbl={unpaid:'Unpaid',paid:'Paid Leave',halfday:'Half-Day'};
    const payCol={unpaid:'var(--r)',paid:'var(--gr)',halfday:'var(--y)'};
    excDiv.innerHTML=wExcuses.length
      ?wExcuses.slice().reverse().map(ex=>`
        <div style="padding:8px 0;border-bottom:1px solid rgba(42,42,42,.3);font-family:'Barlow Semi Condensed',sans-serif;">
          <div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px;flex-wrap:wrap;">
            <div>
              <span style="font-size:12px;font-weight:600;">${ex.fromDate===ex.toDate?ex.fromDate:`${ex.fromDate} → ${ex.toDate}`}</span>
              ${ex.recurring?`<span style="font-size:10px;color:var(--pu);margin-left:6px;">↻ Recurring</span>`:''}
              <span style="font-size:10px;color:${payCol[ex.payType]};padding:1px 6px;margin-left:6px;background:rgba(255,255,255,.05);">${payLbl[ex.payType]}</span>
            </div>
            <span style="font-size:10px;color:var(--g);">${ex.dates.length} day${ex.dates.length!==1?'s':''}</span>
          </div>
          <div style="font-size:11px;color:var(--g);margin-top:2px;">${ex.reason} · Excused by ${ex.excusedBy}</div>
        </div>`).join('')
      :`<div style="color:var(--g);font-size:12px;text-align:center;padding:12px;">No excuses on record.</div>`;
  }

  // Make-Up Schedule history
  const wMakeups=Makeups.filter(m=>m.workerIds.includes(id));
  const mkDiv=document.getElementById('wi-makeup');
  if(mkDiv){
    const mkPayLbl={standard:'Standard pay',double:'Double pay (2×)',custom:'Custom pay'};
    const mkPayCol={standard:'var(--y)',double:'var(--gr)',custom:'var(--pu)'};
    mkDiv.innerHTML=wMakeups.length
      ?wMakeups.slice().reverse().map(m=>`
        <div style="padding:8px 0;border-bottom:1px solid rgba(42,42,42,.3);font-family:'Barlow Semi Condensed',sans-serif;">
          <div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px;flex-wrap:wrap;">
            <div>
              <span style="font-size:12px;font-weight:600;">${m.dates.length} make-up day${m.dates.length!==1?'s':''}</span>
              <span style="font-size:10px;color:${mkPayCol[m.payType]||'var(--y)'};padding:1px 6px;margin-left:6px;background:rgba(255,255,255,.05);">${mkPayLbl[m.payType]||m.payType}${m.payType==='custom'&&m.customAmount?' (R'+m.customAmount+'/day)':''}</span>
            </div>
            <span style="font-size:10px;color:var(--g);">${m.dates.slice(0,3).join(', ')}${m.dates.length>3?' + '+(m.dates.length-3)+' more':''}</span>
          </div>
          <div style="font-size:11px;color:var(--g);margin-top:2px;">${m.note} · Scheduled by ${m.createdBy}</div>
        </div>`).join('')
      :`<div style="color:var(--g);font-size:12px;text-align:center;padding:12px;">No compensation days scheduled yet.</div>`;
  }

  // OT / Bonus Days history
  const wOTB=OvertimeBonuses.filter(ob=>ob.workerIds.includes(id));
  const obDiv=document.getElementById('wi-otbonus');
  if(obDiv){
    const obPayLbl={standard:'1.5× OT rate',double:'2× double pay',bonus:'Bonus pay'};
    const obPayCol={standard:'var(--y)',double:'var(--gr)',bonus:'var(--pu)'};
    obDiv.innerHTML=wOTB.length
      ?wOTB.slice().reverse().map(ob=>`
        <div style="padding:8px 0;border-bottom:1px solid rgba(42,42,42,.3);font-family:'Barlow Semi Condensed',sans-serif;">
          <div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px;flex-wrap:wrap;">
            <div>
              <span style="font-size:12px;font-weight:600;">${ob.dates.length} OT/bonus day${ob.dates.length!==1?'s':''}</span>
              <span style="font-size:10px;color:${obPayCol[ob.payType]||'var(--y)'};padding:1px 6px;margin-left:6px;background:rgba(255,255,255,.05);">${obPayLbl[ob.payType]||ob.payType}${ob.payType==='bonus'&&ob.bonusAmount?' (R'+ob.bonusAmount+'/day)':''}</span>
            </div>
            <span style="font-size:10px;color:var(--g);">${ob.dates.slice(0,3).join(', ')}${ob.dates.length>3?' + '+(ob.dates.length-3)+' more':''}</span>
          </div>
          <div style="font-size:11px;color:var(--g);margin-top:2px;">${ob.note} · Logged by ${ob.createdBy}</div>
        </div>`).join('')
      :`<div style="color:var(--g);font-size:12px;text-align:center;padding:12px;">No OT or bonus days recorded yet.</div>`;
  }

  // Absence Entitlement status
  const aeBadge=document.getElementById('wi-ae-badge');
  const aeContent=document.getElementById('wi-ae-content');
  if(aeBadge&&aeContent){
    if(w.aeEnabled){
      const s=getEntitlementStatus(w);
      const barPct=s?Math.min(100,Math.round((s.used/s.allowed)*100)):0;
      const bc=s?.exceeded?'var(--r)':barPct>=75?'var(--o)':'var(--gr)';
      aeBadge.textContent=s?.exceeded?'⚠ Exceeded':'✓ Active';
      aeBadge.style.background=s?.exceeded?'rgba(244,67,54,.12)':'rgba(76,175,80,.1)';
      aeBadge.style.color=s?.exceeded?'var(--r)':'var(--gr)';
      const typeLabels={permanent:'Permanent',contract:'Contract',daylabourer:'Day Labourer'};
      const exceedLabels={flag:'Flag only',unpaid:'Flag + unpaid',notify:'Flag + SMS'};
      aeContent.innerHTML=`
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px;">
          <div><span style="color:var(--g);">Days allowed:</span> <strong>${w.aeDays} per ${AE_PERIOD_LABELS[w.aePeriod]}</strong></div>
          <div><span style="color:var(--g);">Worker type:</span> <strong>${typeLabels[w.aeType]||w.aeType}</strong></div>
          <div><span style="color:var(--g);">When exceeded:</span> <strong>${exceedLabels[w.aeExceed]||w.aeExceed}</strong></div>
          <div><span style="color:var(--g);">Used this ${AE_PERIOD_LABELS[w.aePeriod]}:</span> <strong style="color:${bc}">${s?.used||0} / ${w.aeDays} days</strong></div>
        </div>
        <div style="height:6px;background:var(--bg);"><div style="height:100%;width:${barPct}%;background:${bc};transition:width .4s;"></div></div>
        <div style="font-size:10px;color:${bc};margin-top:3px;">${s?.exceeded?`⚠ Exceeded by ${(s.used-s.allowed)} day${s.used-s.allowed!==1?'s':''}`:s?.remaining?`${s.remaining} day${s.remaining!==1?'s':''} remaining this ${AE_PERIOD_LABELS[w.aePeriod]}`:'Entitlement fully used'}</div>`;
    }else{
      aeBadge.textContent='Disabled';
      aeBadge.style.background='rgba(136,136,128,.1)';
      aeBadge.style.color='var(--g)';
      aeContent.innerHTML=`<div style="color:var(--g);font-size:12px;">Absence Entitlement is not configured for this worker. Enable it in Edit Worker.</div>`;
    }
  }

  document.getElementById('mwi').classList.add('open');
  renderWorkerNotes(id);
}

// ── PDF WINDOW ────────────────────────────────────────────────────
function openPdfWindow(rows,title,period){
  const present=rows.filter(r=>!r.absent);
  const absent=rows.filter(r=>r.absent);
  const totalHours=rows.reduce((s,r)=>s+(+r.hours||0),0);
  const bodyRows=rows.map(r=>`<tr class="${r.absent?'absent':''}">
    <td>${r.name}</td><td style="color:#666">${r.role}</td>
    <td><span class="tag">${r.payType}</span></td><td>${r.rate}</td>
    <td>${r.checkin}</td><td>${r.site}</td>
    <td style="text-align:center;font-weight:700">${r.hours||'—'}</td>
    <td style="text-align:right;font-weight:900;color:#111">${r.pay!=='—'?'R'+r.pay:''}</td>
    <td style="text-align:center">${r.reliability}</td>
    <td style="text-align:center"><span style="padding:2px 8px;font-size:10px;font-weight:700;background:${r.absent?'#fee2e2':'#dcfce7'};color:${r.absent?'#991b1b':'#166534'}">${r.absent?'ABSENT':'PRESENT'}</span></td>
  </tr>`).join('');
  const w=window.open('','_blank');
  w.document.write(`<!DOCTYPE html><html><head><meta charset="UTF-8">
<title>${title}</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{font-family:'Arial',sans-serif;padding:32px;font-size:12px;color:#111;background:#fff;}
.header{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:28px;border-bottom:3px solid #FFCD11;padding-bottom:16px;}
.logo{font-size:28px;font-weight:900;letter-spacing:.04em;}
.logo span{background:#FFCD11;color:#000;padding:2px 10px;margin-left:4px;font-size:18px;letter-spacing:.15em;}
.meta{text-align:right;font-size:11px;color:#555;line-height:1.8;}
.summary{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:24px;}
.sc{background:#f9f9f7;border:1px solid #eee;padding:10px 14px;}
.sl{font-size:9px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:#888;margin-bottom:4px;}
.sv{font-size:20px;font-weight:900;}
table{width:100%;border-collapse:collapse;margin-bottom:24px;}
th{background:#111;color:#FFCD11;padding:8px 10px;text-align:left;font-size:10px;letter-spacing:.08em;text-transform:uppercase;font-weight:700;}
td{padding:7px 10px;border-bottom:1px solid #f0f0f0;font-size:11px;vertical-align:middle;}
tr.absent td{background:#fff8f8;color:#aaa;}
.tag{background:#f0f0f0;padding:1px 7px;font-size:10px;font-weight:700;color:#333;}
@media print{body{padding:16px;}button{display:none;}}
</style>
</head><body>
<div class="header">
  <div>
    <div class="logo">VEE<span>INDUSTRIAL</span></div>
    <div style="font-size:11px;color:#666;margin-top:6px;">Hours. Tracked. Paid.</div>
  </div>
  <div class="meta">
    <div><strong>${title}</strong></div>
    <div>Period: ${period}</div>
    <div>Generated: ${new Date().toLocaleDateString('en-ZA',{weekday:'long',day:'numeric',month:'long',year:'numeric'})}</div>
  </div>
</div>
<div class="summary">
  <div class="sc"><div class="sl">Total Workers</div><div class="sv">${rows.length}</div></div>
  <div class="sc"><div class="sl">Present</div><div class="sv" style="color:#166534">${present.length}</div></div>
  <div class="sc"><div class="sl">Absent</div><div class="sv" style="color:#991b1b">${absent.length}</div></div>
  <div class="sc"><div class="sl">Total Hours</div><div class="sv">${totalHours}</div></div>
</div>
<table>
  <thead><tr><th>Worker</th><th>Role</th><th>Pay Type</th><th>Rate</th><th>Check-In</th><th>Site</th><th>Hours</th><th>Est. Pay</th><th>Reliability</th><th>Status</th></tr></thead>
  <tbody>${bodyRows}</tbody>
</table>
<script>window.onload=function(){window.print();}<\/script>
</body></html>`);
  w.document.close();
}

// ── WORKER-SPECIFIC EXPORTS ───────────────────────────────────────
function exportWorkerXl(id){
  const w=W.find(x=>x.id===id);if(!w)return;
  const wE=E.filter(e=>e.workerId===id).sort((a,b)=>a.date.localeCompare(b.date));
  const totalH=wE.reduce((s,e)=>s+(+e.hours||0),0);
  const pct=rel(id);
  const gen=new Date().toLocaleDateString('en-ZA',{day:'2-digit',month:'short',year:'numeric'});

  const allRows=[
    // ── TITLE ────────────────────────────────────────────────────
    ['VEE INDUSTRIAL  —  WORKER PAYROLL REPORT','','','','',''],
    ['Generated:  '+gen,'','','','',''],
    ['','','','','',''],
    // ── WORKER PROFILE ───────────────────────────────────────────
    ['WORKER PROFILE','','','','',''],
    ['──────────────','','','','',''],
    ['Name',w.name,'','Role',w.role||'Worker',''],
    ['Phone',w.phone||'—','','Pay Type',ptL(w.payType),''],
    ['Rate',ptF(w),'','Expected Days / Week',''+( w.expectedDays||5),''],
    ['Reliability',''+pct+'%','','Geo-Fence',w.geoFence||'Default',''],
    ['Shift',( w.shiftStart||'06:00')+' – '+(w.shiftEnd||'17:00'),'','Check-in window',(w.loginFrom||'05:00')+' – '+(w.loginEarliest||'08:00')+' ('+(w.loginRule||'recommended')+')',''],['',' ','','Checkout window',(w.logoutFrom||'17:00')+' – '+(w.logoutLatest||'18:00')+' ('+(w.logoutRule||'recommended')+')',''],
    ['','','','','',''],
    // ── HOURS LOG ────────────────────────────────────────────────
    ['HOURS LOG','','','','',''],
    ['══════════════','══════════════','════════════════════════','══════','════════════','══════════════════'],
    ['DATE','CHECK-IN TIME','SITE','HOURS','EST. PAY (R)','LOGGED BY'],
    ['──────────────','──────────────','────────────────────────','──────','────────────','──────────────────'],
    ...wE.map(e=>{
      const ci=Checkins.find(c=>c.workerId===id&&c.date===e.date);
      const pay=calcPay(w,+e.hours||0);
      return[e.date,ci?ci.time:'—',e.site||'—',+e.hours||0,pay?Number(pay.toFixed(0)):0,e.loggedBy||'—'];
    }),
    // ── TOTAL ────────────────────────────────────────────────────
    ['──────────────','──────────────','────────────────────────','──────','────────────','──────────────────'],
    ['TOTAL HOURS','','',''+totalH,'',''],
    ['RECORDS','','',''+wE.length,'',''],
  ];

  const ws=XLSX.utils.aoa_to_sheet(allRows);

  ws['!cols']=[{wch:18},{wch:16},{wch:26},{wch:8},{wch:14},{wch:20}];

  ws['!rows']=[
    {hpt:26},  // title
    {hpt:14},  // generated
    {hpt:8},   // blank
    {hpt:16},  // WORKER PROFILE label
    {hpt:4},   // divider
  ];

  ws['!merges']=[
    {s:{r:0,c:0},e:{r:0,c:5}},
    {s:{r:1,c:0},e:{r:1,c:5}},
    {s:{r:3,c:0},e:{r:3,c:5}},
  ];

  // Number format for pay column (col index 4) in data rows
  const dataStart=14; // row index of first data row
  wE.forEach((e,i)=>{
    const ref=XLSX.utils.encode_cell({r:dataStart+i,c:4});
    if(ws[ref]&&typeof ws[ref].v==='number'&&ws[ref].v>0){
      ws[ref].z='#,##0';
    }
  });

  const wb=XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(wb,ws,w.name.slice(0,31));
  XLSX.writeFile(wb,`VEE-${w.name.replace(/\s+/g,'-')}-Report.xlsx`,{});
  toast('✓ Worker Excel downloaded');
}

function exportWorkerPdf(id){
  // TODO: Per-worker payslip does not include PAYE/UIF deductions
  // TODO: Add deduction breakdown section once tax engine is implemented
  const w=W.find(x=>x.id===id);if(!w)return;
  const wE=E.filter(e=>e.workerId===id).reverse();
  const totalH=wE.reduce((s,e)=>s+(+e.hours||0),0);
  const pct=rel(id);
  const rows=wE.map(e=>{
    const ci=Checkins.find(c=>c.workerId===id&&c.date===e.date);
    const pay=calcPay(w,+e.hours||0);
    return`<tr><td>${e.date}</td><td>${ci?ci.time:'—'}</td><td>${e.site||'—'}</td><td style="text-align:center;font-weight:700">${e.hours}</td><td style="text-align:right;font-weight:900">${pay?'R'+pay.toFixed(0):'—'}</td><td style="color:#888">${e.loggedBy||'—'}</td></tr>`;
  }).join('');
  const pw=window.open('','_blank');
  pw.document.write(`<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Worker Report — ${w.name}</title>
<style>*{margin:0;padding:0;box-sizing:border-box;}body{font-family:Arial,sans-serif;padding:32px;font-size:12px;color:#111;}
.logo{font-size:24px;font-weight:900;letter-spacing:.04em;border-bottom:3px solid #FFCD11;padding-bottom:12px;margin-bottom:20px;}
.logo span{background:#FFCD11;color:#000;padding:2px 10px;margin-left:4px;font-size:16px;}
.profile{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:24px;}
.pc{background:#f9f9f7;border:1px solid #eee;padding:12px 14px;}
.pl{font-size:9px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:#888;margin-bottom:4px;}
.pv{font-size:14px;font-weight:700;}
table{width:100%;border-collapse:collapse;}
th{background:#111;color:#FFCD11;padding:7px 10px;font-size:10px;letter-spacing:.08em;text-transform:uppercase;text-align:left;}
td{padding:6px 10px;border-bottom:1px solid #f0f0f0;}
.footer{margin-top:20px;font-size:10px;color:#999;border-top:1px solid #eee;padding-top:12px;display:flex;justify-content:space-between;}
@media print{body{padding:16px;}}</style></head><body>
<div class="logo">VEE<span>INDUSTRIAL</span></div>
<div style="margin-bottom:20px;"><div style="font-size:18px;font-weight:900;">${w.name}</div><div style="color:#666;font-size:12px;">${w.role||'Worker'} · Individual Payroll Report</div></div>
<div class="profile">
  <div class="pc"><div class="pl">Phone</div><div class="pv">${w.phone||'—'}</div></div>
  <div class="pc"><div class="pl">Pay Type</div><div class="pv">${ptL(w.payType)}</div></div>
  <div class="pc"><div class="pl">Rate</div><div class="pv">${ptF(w)}</div></div>
  <div class="pc"><div class="pl">Expected Days/Week</div><div class="pv">${w.expectedDays||5}</div></div>
  <div class="pc"><div class="pl">Total Hours Logged</div><div class="pv" style="color:#FFCD11">${totalH} hrs</div></div>
  <div class="pc"><div class="pl">Reliability Score</div><div class="pv" style="color:${pct>=85?'#166534':pct>=60?'#92400e':'#991b1b'}">${pct}%</div></div>
</div>
<table><thead><tr><th>Date</th><th>Check-In</th><th>Site</th><th>Hours</th><th>Est. Pay</th><th>Logged By</th></tr></thead>
<tbody>${rows}</tbody></table>
<div class="footer"><div>VEE Industrial · vee-app-ff35c.web.app</div><div>Confidential — Individual Worker Report</div></div>
<script>window.onload=function(){window.print();}<\/script></body></html>`);
  pw.document.close();
}

// ── SUSPICIOUS ────────────────────────────────────────────────────
function renderSuspicious(){
  const div=document.getElementById('susplist');
  const badge=document.getElementById('susp-badge');
  const active=Susp.filter(s=>!s.mgrDismissed);
  const dismissed=Susp.filter(s=>s.mgrDismissed);
  if(active.length){badge.style.display='inline';badge.textContent=active.length;}else{badge.style.display='none';}
  if(!Susp.length){div.innerHTML=`<div style="padding:30px;text-align:center;color:var(--g);font-size:13px">No suspicious activity. System is clean.</div>`;return;}
  const TL={'invalid-code':'Invalid Code','geofence-fail':'Outside Geo-Fence','duplicate-code':'Code Reused','early-login-blocked':'Early Login Blocked','early-login-noted':'Early Login Noted','outside-window':'Outside Window','bypass-mandatory-checkin':'Mandatory Bypass — In','bypass-recommended-checkin':'Bypass — In','bypass-mandatory-checkout':'Mandatory Bypass — Out','bypass-recommended-checkout':'Bypass — Out','late-checkout-noted':'Late Checkout','mgr-checkin-flagged':'Manager Flagged','invalid-checkout-code':'Invalid Checkout Code','duplicate-checkout':'Duplicate Checkout','checkout-blocked':'Checkout Blocked'};
  const TC={'invalid-code':'#F44336','geofence-fail':'#FF9800','duplicate-code':'#FFCD11','early-login-blocked':'#F44336','outside-window':'#FF9800','bypass-mandatory-checkin':'#F44336','bypass-mandatory-checkout':'#F44336'};

  const renderRow=(s,greyedOut)=>{
    const c=TC[s.type]||'#888880';
    const dimStyle=greyedOut?'opacity:.4;':'';
    const dismissBadge=greyedOut?`
      <div class="dismiss-badge" style="pointer-events:auto;cursor:help;">
        🗂 Archived by ${s.mgrDismissedBy}
        <div class="dismiss-tooltip">
          <div style="font-weight:600;margin-bottom:4px;">Dismissed at ${s.mgrDismissedAt}</div>
          <div>Manager: ${s.mgrDismissedBy}</div>
          <div style="margin-top:4px;color:var(--g);">"${s.mgrDismissNote}"</div>
        </div>
      </div>`:'';
    return`<div style="display:flex;gap:12px;padding:12px 16px;border-bottom:1px solid var(--bd);align-items:flex-start;${dimStyle}${greyedOut?'background:rgba(0,0,0,.15);':''}">
      <div style="width:8px;height:8px;border-radius:50%;background:${c};margin-top:5px;flex-shrink:0;"></div>
      <div style="flex:1">
        <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:3px">
          <span style="font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;font-size:13px">${s.workerName||'Unknown'}</span>
          <span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;padding:2px 7px;background:${c}22;color:${c}">${TL[s.type]||s.type}</span>
          ${dismissBadge}
        </div>
        <div style="font-size:13px;color:var(--ow)">${s.note}</div>
        <div style="font-size:11px;color:var(--g);margin-top:3px;font-family:'Barlow Semi Condensed',sans-serif">🕐 ${s.time}${s.site?` · 📍 ${s.site}`:''}${s.code?` · Code: <strong style="color:var(--ow)">${s.code}</strong>`:''}</div>
        <div style="font-size:11px;color:rgba(167,139,250,.8);margin-top:2px;font-family:'Barlow Semi Condensed',sans-serif">Logged by: <strong style="color:var(--pu)">${s.loggedBy||'System'}</strong>${s.portal?` · ${s.portal}`:''}</div>
      </div>
    </div>`;
  };

  let html='';
  // Active flags first
  if(active.length)html+=active.map(s=>renderRow(s,false)).join('');
  // Archived (dismissed) section
  if(dismissed.length){
    html+=`<div style="padding:8px 16px;background:var(--surf2);border-bottom:1px solid var(--bd);display:flex;align-items:center;justify-content:space-between;">
      <span style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--g);">🗂 Archived by Manager (${dismissed.length})</span>
      <button onclick="toggleSuspArchive()" id="susp-archive-btn" style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;background:transparent;border:1px solid var(--bd);color:var(--g);padding:3px 10px;cursor:pointer;">Show ▼</button>
    </div>
    <div id="susp-archive-list" style="display:none;">${dismissed.map(s=>renderRow(s,true)).join('')}</div>`;
  }
  div.innerHTML=html||`<div style="padding:30px;text-align:center;color:var(--g);font-size:13px">No suspicious activity. System is clean.</div>`;
}

let suspArchiveOpen=false;
function toggleSuspArchive(){
  suspArchiveOpen=!suspArchiveOpen;
  const list=document.getElementById('susp-archive-list');
  const btn=document.getElementById('susp-archive-toggle-btn');
  if(list)list.style.display=suspArchiveOpen?'block':'none';
  if(btn)btn.textContent=suspArchiveOpen?'Hide Archived ▲':'Show Archived ▼';
}

function clearSusp(){if(!confirm('Clear all suspicious records?'))return;Susp=[];renderSuspicious();toast('Cleared');}

// ── LIVE CHECK-IN / CHECKOUT ──────────────────────────────────────
let ciBypassPending=null; // stores pending action when mandatory modal shows

function genCheckoutCodeFor(wId){
  // Different salt from check-in code — separate secure code per direction
  const str=wId+today()+'vee-checkout-2025';
  let h=0;for(let i=0;i<str.length;i++){h=Math.imul(31,h)+str.charCodeAt(i)|0;}
  return String(Math.abs(h)).slice(0,6).padStart(6,'0');
}

function switchCITab(tab){
  const ciTab=document.getElementById('ci-tab');
  const coTab=document.getElementById('co-tab');
  const ciBtn=document.getElementById('ci-tab-btn');
  const coBtn=document.getElementById('co-tab-btn');
  if(tab==='checkin'){
    ciTab.style.display='flex';coTab.style.display='none';
    ciBtn.style.background='var(--gr)';ciBtn.style.color='#fff';
    coBtn.style.background='var(--surf2)';coBtn.style.color='var(--g)';
  }else{
    ciTab.style.display='none';coTab.style.display='flex';
    coBtn.style.background='var(--o)';coBtn.style.color='#fff';
    ciBtn.style.background='var(--surf2)';ciBtn.style.color='var(--g)';
  }
}

function updCISel(){
  const sel=document.getElementById('ci-sel');
  sel.innerHTML='<option value="">Choose a worker...</option>'+W.map(w=>`<option value="${w.id}">${w.name}${w.isTest?' (Test)':''}</option>`).join('');
}

function genCode(){
  const wId=document.getElementById('ci-sel').value;
  const w=W.find(x=>x.id===wId);
  const disp=document.getElementById('ci-display');
  const info=document.getElementById('ci-winfo');
  if(!w){disp.style.display='none';info.style.display='none';return;}
  // Check-in code
  document.getElementById('ci-code').textContent=genCodeFor(w.id);
  document.getElementById('ci-wname').textContent=w.name;
  // Checkout code
  document.getElementById('co-code').textContent=genCheckoutCodeFor(w.id);
  document.getElementById('co-wname').textContent=w.name;
  disp.style.display='block';
  // Worker info
  const pct=rel(w.id);
  const rc=pct>=85?'var(--gr)':pct>=60?'var(--y)':'var(--r)';
  document.getElementById('ci-pt').textContent=ptL(w.payType);
  document.getElementById('ci-rel').innerHTML=`<span style="color:${rc}">${pct}%</span>`;
  document.getElementById('ci-window').textContent=`${w.loginFrom||'05:00'} – ${w.loginEarliest||'08:00'} (${w.loginRule||'recommended'})`;
  document.getElementById('co-window').textContent=`${w.logoutFrom||'17:00'} – ${w.logoutLatest||'18:00'} (${w.logoutRule||'recommended'})`;
  info.style.display='block';
  // Reset bypass checkboxes
  document.getElementById('ci-bypass').checked=false;
  document.getElementById('co-bypass').checked=false;
  updBypassState();
}

function updBypassState(){
  const wId=document.getElementById('ci-sel').value;
  const w=W.find(x=>x.id===wId);
  if(!w)return;
  const ciByp=document.getElementById('ci-bypass');
  const coByp=document.getElementById('co-bypass');
  const ciLbl=document.getElementById('ci-bypass-label');
  const coLbl=document.getElementById('co-bypass-label');
  if(ciByp.checked){
    ciLbl.textContent=w.loginRule==='mandatory'?'⚠ MANDATORY — acknowledgement required':'Will bypass — logged as suspicious';
    ciLbl.style.color=w.loginRule==='mandatory'?'var(--r)':'var(--o)';
  }else{ciLbl.textContent='';ciLbl.style.color='';}
  if(coByp.checked){
    coLbl.textContent=w.logoutRule==='mandatory'?'⚠ MANDATORY — acknowledgement required':'Will bypass — logged as suspicious';
    coLbl.style.color=w.logoutRule==='mandatory'?'var(--r)':'var(--o)';
  }else{coLbl.textContent='';coLbl.style.color='';}
}

function showResult(el,icon,name,msg,tag,borderCol,bgCol,nameCol){
  const res=document.getElementById(el+'-res');
  res.style.cssText=`display:block;padding:16px;text-align:center;border:2px solid ${borderCol};background:${bgCol};`;
  document.getElementById(el+'-ric').textContent=icon;
  document.getElementById(el+'-rn').style.color=nameCol||'var(--ow)';
  document.getElementById(el+'-rn').textContent=name;
  document.getElementById(el+'-rm').textContent=msg;
  document.getElementById(el+'-rt').style.cssText=`background:${borderCol.replace(',.4)','.15)')};color:${nameCol||'var(--ow)'};`;
  document.getElementById(el+'-rt').textContent=tag;
}

// ── CHECK-IN ──────────────────────────────────────────────────────
function _doCheckin(w,input,flagged,suspType){
  const td=today();
  const entry={id:uid(),workerId:w.id,workerName:w.name,date:td,time:now(),status:'ok',type:'checkin',codeUsed:input,loggedBy:EMPLOYER_NAME,flagged};
  Checkins.push(entry);
  E.push({id:uid(),workerId:w.id,workerName:w.name,hours:8,site:S[0]?.name||'',date:td,time:now(),loggedBy:'clerk-checkin',payType:w.payType,isTest:w.isTest});
  if(suspType)Susp.push({id:uid(),type:suspType,workerName:w.name,note:`Check-in bypassed/flagged: ${suspType}`,code:input,site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Check-In'});
  const bc=flagged?'rgba(255,205,17,.4)':'rgba(76,175,80,.4)';
  const bg=flagged?'rgba(255,205,17,.06)':'rgba(76,175,80,.06)';
  const nc=flagged?'var(--y)':'var(--gr)';
  showResult('ci',flagged?'⚠️':'✅',w.name,flagged?'Check-in approved — time window flagged':ptL(w.payType)+' · Check-in approved',flagged?'Approved — Flagged':'Entry Approved',bc,bg,nc);
  renderCILog();renderDash();updBanner();updDemoState();renderSuspicious();
  if(empWorker?.id===w.id)empSelect();
  toast((flagged?'⚠ ':' ✓ ')+w.name+' checked in'+(flagged?' (flagged)':''));
}

// ── CHECK-OUT ─────────────────────────────────────────────────────
function coCheck(){
  const input=document.getElementById('co-inp').value.trim();
  if(input.length<4){toast('Enter the full 6-digit checkout code');return;}
  const td=today();
  const bypass=document.getElementById('co-bypass')?.checked||false;
  let matched=null;
  for(const w of W){if(genCheckoutCodeFor(w.id)===input){matched=w;break;}}
  if(!matched){
    showResult('co','🚫','Invalid Checkout Code',`"${input}" does not match any worker today`,'Blocked — Logged','rgba(244,67,54,.4)','rgba(244,67,54,.06)','var(--r)');
    Susp.push({id:uid(),type:'invalid-checkout-code',workerName:'Unknown',note:'Invalid checkout code entered',code:input,site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Checkout'});
    renderSuspicious();renderCILog();toast('⚠ Invalid checkout code — logged');return;
  }
  const checkedIn=Checkins.find(c=>c.workerId===matched.id&&c.date===td&&c.status==='ok'&&c.type!=='checkout');
  if(!checkedIn){
    showResult('co','⚠️',matched.name,'No check-in found for today — cannot checkout without checking in first','Not Checked In','rgba(255,205,17,.4)','rgba(255,205,17,.06)','var(--y)');
    renderCILog();toast('⚠ '+matched.name+' has no check-in today');return;
  }
  const alreadyOut=Checkins.find(c=>c.workerId===matched.id&&c.date===td&&c.type==='checkout');
  if(alreadyOut){
    showResult('co','⚠️',matched.name,'Already checked out at '+alreadyOut.time,'Already Checked Out','rgba(255,205,17,.4)','rgba(255,205,17,.06)','var(--y)');
    Susp.push({id:uid(),type:'duplicate-checkout',workerName:matched.name,note:'Checkout code reused — already out at '+alreadyOut.time,code:input,site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Checkout'});
    renderSuspicious();renderCILog();toast('⚠ Already checked out');return;
  }
  // Evaluate logout rule
  const logoutEval=evalLogoutRule(matched);
  if(bypass){
    if(matched.logoutRule==='mandatory'){
      ciBypassPending={type:'checkout',worker:matched,input};
      document.getElementById('ci-mandatory-msg').textContent=`${matched.name} has a MANDATORY checkout window set (${matched.logoutFrom||'17:00'} – ${matched.logoutLatest||'18:00'}). The current time is ${demoNowStr()}. Proceeding will override this mandatory rule and will be logged to suspicious activity.`;
      document.getElementById('ci-mandatory-modal').style.display='block';
      return;
    }else{
      _doCheckout(matched,input,true,'bypass-checkout-recommended');return;
    }
  }
  if(!logoutEval.ok&&logoutEval.mandatory){
    showResult('co','🚫','Checkout Blocked — '+matched.name,logoutEval.msg,'Checkout Blocked (Mandatory)','rgba(244,67,54,.4)','rgba(244,67,54,.06)','var(--r)');
    Susp.push({id:uid(),type:'checkout-blocked',workerName:matched.name,note:logoutEval.msg,code:input,site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Checkout'});
    renderSuspicious();renderCILog();toast('🚫 Checkout blocked — '+matched.name);return;
  }
  _doCheckout(matched,input,logoutEval.warn,'late-checkout-noted');
}

function _doCheckout(w,input,flagged,suspType){
  const td=today();
  // Calculate actual hours from check-in time
  const ciEntry=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.type!=='checkout');
  let hoursWorked=8;
  if(ciEntry){
    const [ch,cm]=ciEntry.time.split(':').map(Number);
    const [nh,nm]=now().split(':').map(Number);
    const mins=(nh*60+nm)-(ch*60+cm);
    hoursWorked=Math.max(0,Math.round(mins/60*10)/10);
  }
  Checkins.push({id:uid(),workerId:w.id,workerName:w.name,date:td,time:now(),status:'ok',type:'checkout',codeUsed:input,loggedBy:EMPLOYER_NAME,hoursWorked,flagged});
  // Update hours entry
  const eIdx=E.findIndex(e=>e.workerId===w.id&&e.date===td);
  if(eIdx>-1)E[eIdx].hours=hoursWorked;
  if(suspType&&flagged)Susp.push({id:uid(),type:suspType,workerName:w.name,note:`Checkout flagged: ${suspType}. Hours: ${hoursWorked}`,code:input,site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Checkout'});
  const bc=flagged?'rgba(255,152,0,.4)':'rgba(76,175,80,.4)';
  const bg=flagged?'rgba(255,152,0,.06)':'rgba(76,175,80,.06)';
  const nc=flagged?'var(--o)':'var(--gr)';
  showResult('co',flagged?'⚠️':'✅',w.name,`Checked out · ${hoursWorked} hrs logged${flagged?' — time window noted':''}`,flagged?'Checkout Approved — Flagged':'Checkout Approved',bc,bg,nc);
  renderCILog();renderDash();updBanner();renderSuspicious();
  toast((flagged?'⚠ ':' ✓ ')+w.name+` checked out · ${hoursWorked}h`);
}

function coReset(){document.getElementById('co-inp').value='';document.getElementById('co-res').style.display='none';}
function cod(k){const i=document.getElementById('co-inp');if(k==='⌫')i.value=i.value.slice(0,-1);else if(i.value.length<6)i.value+=k;}

// ── MANDATORY BYPASS MODAL ────────────────────────────────────────
function dismissMandatoryModal(){
  document.getElementById('ci-mandatory-modal').style.display='none';
  ciBypassPending=null;
  // Uncheck bypass
  const cb=document.getElementById(ciBypassPending?.type==='checkout'?'co-bypass':'ci-bypass');
  if(cb)cb.checked=false;
  updBypassState();
}
function proceedMandatoryBypass(){
  document.getElementById('ci-mandatory-modal').style.display='none';
  if(!ciBypassPending)return;
  const{type,worker,input}=ciBypassPending;
  ciBypassPending=null;
  if(type==='checkin')_doCheckin(worker,input,true,'bypass-mandatory-checkin');
  else _doCheckout(worker,input,true,'bypass-mandatory-checkout');
}

// ── WORKER HEALTH ALERTS ──────────────────────────────────────────
const ALERT_THRESHOLD=60; // below this % triggers alert
let alertPanelOpen=false;
let flaggedWorkers=[];

function checkWorkerAlerts(){
  flaggedWorkers=W.filter(w=>rel(w.id)<ALERT_THRESHOLD);
  const panel=document.getElementById('worker-alerts-panel');
  const sub=document.getElementById('alert-sub');
  if(!panel)return;
  if(!flaggedWorkers.length){panel.style.display='none';return;}
  panel.style.display='block';
  if(sub)sub.textContent=`${flaggedWorkers.length} worker${flaggedWorkers.length!==1?'s':''} below ${ALERT_THRESHOLD}% reliability — action may be needed`;
  const list=document.getElementById('alert-list');
  if(list){
    list.innerHTML=flaggedWorkers.map(w=>{
      const pct=rel(w.id);
      const rc=pct>=60?'var(--o)':'var(--r)';
      const exp=(+w.expectedDays||5)*4;
      const act=E.filter(e=>e.workerId===w.id).length;
      const missed=Math.max(0,exp-act);
      return`<div style="display:flex;align-items:center;gap:12px;padding:6px 0;border-bottom:1px solid rgba(244,67,54,.15);flex-wrap:wrap;">
        <div style="width:36px;height:36px;background:var(--surf);border:2px solid ${rc};display:flex;align-items:center;justify-content:center;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:14px;flex-shrink:0;">${w.name.charAt(0)}</div>
        <div style="flex:1;min-width:100px;">
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;">${w.name}</div>
          <div style="font-size:11px;color:var(--g);">${w.role||'Worker'} · ${ptL(w.payType)}</div>
        </div>
        <div style="text-align:center;">
          <div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:20px;color:${rc}">${pct}%</div>
          <div style="font-size:10px;color:var(--g);">${missed} day${missed!==1?'s':''} missed</div>
        </div>
        <button onclick="openWorkerAlertAction('${w.id}')" style="background:transparent;border:1px solid ${rc};color:${rc};font-family:'Barlow Semi Condensed',sans-serif;font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;padding:5px 12px;cursor:pointer;">Take Action</button>
      </div>`;
    }).join('');
  }
}

function toggleAlertPanel(){
  alertPanelOpen=!alertPanelOpen;
  const body=document.getElementById('alert-body');
  const chevron=document.getElementById('alert-chevron');
  if(body)body.style.display=alertPanelOpen?'block':'none';
  if(chevron)chevron.style.transform=alertPanelOpen?'rotate(180deg)':'rotate(0deg)';
  if(alertPanelOpen)checkWorkerAlerts();
}

function openWorkerAlertAction(preselectId){
  const list=document.getElementById('walert-worker-list');
  if(list){
    list.innerHTML=flaggedWorkers.map(w=>`
      <label style="display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--bd);cursor:pointer;" onmouseover="this.style.background='rgba(255,255,255,.03)'" onmouseout="this.style.background='transparent'">
        <input type="checkbox" class="walert-chk" data-id="${w.id}" ${preselectId===w.id||!preselectId?'checked':''} style="accent-color:var(--r);width:15px;height:15px;flex-shrink:0;"/>
        <div style="flex:1;">
          <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;">${w.name}</div>
          <div style="font-size:11px;color:var(--r);">${rel(w.id)}% reliability</div>
        </div>
      </label>`).join('');
  }
  document.getElementById('walert-note').value='';
  document.getElementById('walert-action').value='warn';
  document.getElementById('mworkeralert').classList.add('open');
}
function walertSelectAll(){document.querySelectorAll('.walert-chk').forEach(c=>{c.checked=true;});}
function walertSelectNone(){document.querySelectorAll('.walert-chk').forEach(c=>{c.checked=false;});}
function saveWorkerAlertAction(){
  const selected=[...document.querySelectorAll('.walert-chk:checked')].map(c=>c.dataset.id);
  if(!selected.length){toast('Select at least one worker');return;}
  const action=document.getElementById('walert-action').value;
  const note=document.getElementById('walert-note').value.trim()||'Reliability alert action taken by employer';
  selected.forEach(wId=>{
    const w=W.find(x=>x.id===wId);if(!w)return;
    if(action==='warn'){
      D.push({id:uid(),workerId:wId,workerName:w.name,type:'attendance',details:`Reliability alert: ${rel(wId)}% — ${note}`,status:'open',time:new Date().toLocaleString('en-ZA'),auto:false});
    }else if(action==='excuse-unpaid'||action==='excuse-paid'){
      const td=today();
      Excuses.push({id:uid(),workerIds:[wId],fromDate:td,toDate:td,payType:action==='excuse-paid'?'paid':'unpaid',reason:note,excusedBy:EMPLOYER_NAME,dates:[td],recurring:false,affectsReliability:true,payOverride:false,createdAt:new Date().toISOString()});
    }else if(action==='note'){
      D.push({id:uid(),workerId:wId,workerName:w.name,type:'note',details:`Employer note: ${note}`,status:'open',time:new Date().toLocaleString('en-ZA'),auto:false});
    }
  });
  cm('mworkeralert');renderAll();
  toast(`✓ Action applied to ${selected.length} worker${selected.length!==1?'s':''}`);
}

function ciCheck(){
  // TODO: Geo-fence is currently simulated (random pass/fail)
  // TODO: Replace with real navigator.geolocation check against site coordinates
  const input=document.getElementById('ci-inp').value.trim();
  if(input.length<4){toast('Enter the full code');return;}
  const td=today();
  // TIME WINDOW CHECK
  const {within,msg}=isWithinWindow();
  if(!within){
    Susp.push({id:uid(),type:'outside-window',workerName:'Unknown',note:'Check-in attempted outside allowed hours: '+msg,code:input,site:'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Check-In'});
    renderSuspicious();
    showResult('ci',null,'outside-window',`⏰`,`Outside Check-In Hours`,msg,'var(--y)','rgba(255,205,17,.4)','rgba(255,205,17,.06)');
    toast('⚠ Outside check-in window — logged');return;
  }
  let matched=null;
  for(const w of W){if(genCodeFor(w.id)===input){matched=w;break;}}
  const alreadyIn=matched?Checkins.find(c=>c.workerId===matched.id&&c.date===td&&c.status==='ok'):null;
  const res=document.getElementById('ci-res');res.style.display='block';
  if(matched&&!alreadyIn){
    // EVALUATE LOGIN RULE
    const loginEval=evalLoginRule(matched);
    if(!loginEval.ok&&loginEval.block){
      // MANDATORY — blocked
      res.style.cssText='display:block;padding:16px;text-align:center;border:2px solid rgba(244,67,54,.4);background:rgba(244,67,54,.06);';
      document.getElementById('ci-ric').textContent='🚫';document.getElementById('ci-rn').style.color='var(--r)';document.getElementById('ci-rn').textContent='Too Early — '+matched.name;
      document.getElementById('ci-rm').textContent=loginEval.msg;
      document.getElementById('ci-rt').style.cssText='background:rgba(244,67,54,.15);color:var(--r);';document.getElementById('ci-rt').textContent='Login Blocked (Mandatory Rule)';
      Susp.push({id:uid(),type:'early-login-blocked',workerName:matched.name,note:loginEval.msg,code:input,site:'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Check-In'});
      renderSuspicious();toast('🚫 Early login blocked for '+matched.name);
    }else{
      // Approved (with optional recommended warning)
      const approvedColor=loginEval.warn?'rgba(255,205,17,.4)':'rgba(76,175,80,.4)';
      const approvedBg=loginEval.warn?'rgba(255,205,17,.06)':'rgba(76,175,80,.06)';
      res.style.cssText=`display:block;padding:16px;text-align:center;border:2px solid ${approvedColor};background:${approvedBg};`;
      document.getElementById('ci-ric').textContent=loginEval.warn?'⚠️':'✅';
      document.getElementById('ci-rn').style.color=loginEval.warn?'var(--y)':'var(--gr)';
      document.getElementById('ci-rn').textContent=matched.name;
      document.getElementById('ci-rm').textContent=loginEval.warn?loginEval.msg:ptL(matched.payType)+' · Code valid for today';
      document.getElementById('ci-rt').style.cssText=loginEval.warn?'background:rgba(255,205,17,.15);color:var(--y);':'background:rgba(76,175,80,.15);color:var(--gr);';
      document.getElementById('ci-rt').textContent=loginEval.warn?'Entry Approved — Early Login Noted':'Entry Approved';
      Checkins.push({id:uid(),workerId:matched.id,workerName:matched.name,date:td,time:now(),status:'ok',codeUsed:input,earlyLogin:!!loginEval.warn});
      E.push({id:uid(),workerId:matched.id,workerName:matched.name,hours:8,site:S[0]?.name||'',date:td,time:now(),loggedBy:'clerk-checkin',payType:matched.payType,isTest:matched.isTest,earlyLogin:!!loginEval.warn});
      if(loginEval.warn)Susp.push({id:uid(),type:'early-login-noted',workerName:matched.name,note:loginEval.msg,code:input,site:'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Check-In'});
      renderCILog();renderDash();updBanner();updDemoState();renderSuspicious();
      if(empWorker?.id===matched.id)empSelect();
      toast((loginEval.warn?'⚠ ':' ✓ ')+matched.name+' checked in'+(loginEval.warn?' (early login noted)':''));
    }
  }else if(matched&&alreadyIn){
    res.style.cssText='display:block;padding:16px;text-align:center;border:2px solid rgba(255,205,17,.4);background:rgba(255,205,17,.06);';
    document.getElementById('ci-ric').textContent='⚠️';document.getElementById('ci-rn').style.color='var(--y)';document.getElementById('ci-rn').textContent=matched.name;
    document.getElementById('ci-rm').textContent='Code already used — checked in at '+alreadyIn.time;
    document.getElementById('ci-rt').style.cssText='background:rgba(255,205,17,.15);color:var(--y);';document.getElementById('ci-rt').textContent='Code Already Used';
    Susp.push({id:uid(),type:'duplicate-code',workerName:matched.name,note:'Code reused — already checked in at '+alreadyIn.time,code:input,site:'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Check-In'});
    renderSuspicious();toast('⚠ Code already used — logged suspicious');
  }else{
    res.style.cssText='display:block;padding:16px;text-align:center;border:2px solid rgba(244,67,54,.4);background:rgba(244,67,54,.06);';
    document.getElementById('ci-ric').textContent='🚫';document.getElementById('ci-rn').style.color='var(--r)';document.getElementById('ci-rn').textContent='Invalid Code';
    document.getElementById('ci-rm').textContent=`"${input}" does not match any worker today`;
    document.getElementById('ci-rt').style.cssText='background:rgba(244,67,54,.15);color:var(--r);';document.getElementById('ci-rt').textContent='Blocked — Logged';
    Susp.push({id:uid(),type:'invalid-code',workerName:'Unknown',note:'Invalid code entered on Live Check-In screen',code:input,site:'',time:new Date().toLocaleString('en-ZA'),loggedBy:EMPLOYER_NAME,portal:'Employer — Live Check-In'});
    renderSuspicious();toast('⚠ Invalid — logged as suspicious');
  }
  renderCILog();
}

function ciReset(){document.getElementById('ci-inp').value='';document.getElementById('ci-res').style.display='none';}
function npd(k){const i=document.getElementById('ci-inp');if(k==='⌫')i.value=i.value.slice(0,-1);else if(i.value.length<6)i.value+=k;}

function renderCILog(){
  const td=today();const items=Checkins.filter(c=>c.date===td).slice().reverse();
  document.getElementById('ci-log-cnt').textContent=`${items.length} entr${items.length===1?'y':'ies'}`;
  const tb=document.getElementById('ci-log-tb');
  const cl=document.getElementById('cl-tb');
  const cnt=document.getElementById('cl-cnt');
  if(cnt)cnt.textContent=`${items.length} entr${items.length===1?'y':'ies'}`;
  if(!items.length){const e=`<tr><td colspan="4" style="padding:16px;text-align:center;color:var(--g);font-size:13px">No check-ins yet.</td></tr>`;tb.innerHTML=e;if(cl)cl.innerHTML=e;return;}
  const rows=items.map(c=>{
    const badge=c.status==='ok'?`<span class="badge bgr">✓ Approved</span>`:`<span class="badge brd">✗ Blocked</span>`;
    return`<tr><td><span class="wn">${c.workerName}</span></td><td style="font-size:12px;color:var(--g)">${c.time}</td><td style="font-family:'Barlow Condensed',sans-serif;font-weight:900;letter-spacing:.12em;color:var(--y);font-size:16px">${c.codeUsed}</td><td>${badge}</td></tr>`;
  }).join('');
  tb.innerHTML=rows;if(cl)cl.innerHTML=rows;
}


// ── updClerkSelects: populates the worker dropdown inside the clerk dashboard
// TODO: once clerkSite is saved per-worker, filter to site workers only
function updClerkSelects(){
  const sel=document.getElementById('clerk-worker-sel');
  if(!sel)return;
  const workers=clerkWorker&&clerkWorker.clerkSite
    ? W.filter(w=>!w.isSkeeper&&!w.isTest||(w.managerSite&&w.managerSite===clerkWorker.clerkSite))
    : W.filter(w=>!w.isSkeeper);
  sel.innerHTML='<option value="">Select worker...</option>'+
    workers.map(w=>`<option value="${w.id}">${w.name}</option>`).join('');
}

// ── CLERK PORTAL ──────────────────────────────────────────────────
// ── EMPLOYEE PORTAL ───────────────────────────────────────────────
function updEmpDrops(){
  const sel=document.getElementById('emp-who');
  sel.innerHTML='<option value="">Select your name...</option>'+W.map(w=>`<option value="${w.id}">${w.name}${w.isTest?' (Test)':''}</option>`).join('');
  // emp-site removed — hours are logged via check-in flow
}

function empSelect(){
  const wId=document.getElementById('emp-who').value;
  empWorker=W.find(x=>x.id===wId)||null;
  const form=document.getElementById('emp-form');
  const clerkBanner=document.getElementById('clerk-access-banner');
  const clerkPin=document.getElementById('clerk-pin-entry');
  const clerkActive=document.getElementById('clerk-active-mode');
  clerkPin.style.display='none';
  clerkActive.style.display='none';
  clerkWorker=null;
  if(!empWorker){form.style.display='none';clerkBanner.style.display='none';const mb=document.getElementById('mgr-access-banner');if(mb)mb.style.display='none';const sb=document.getElementById('sk-access-banner');if(sb)sb.style.display='none';return;}
  form.style.display='flex';
  document.getElementById('emp-greeting').textContent=`Good morning, ${empWorker.name.split(' ')[0]}`;
  document.getElementById('emp-date').textContent=fmtD();
  clerkBanner.style.display=empWorker.isClerk?'block':'none';
  const mgrBanner=document.getElementById('mgr-access-banner');
  if(mgrBanner)mgrBanner.style.display=empWorker.isManager?'block':'none';
  const skBanner=document.getElementById('sk-access-banner');
  if(skBanner)skBanner.style.display=empWorker.isSkeeper?'block':'none';
  // Show their daily code
  const code=genCodeFor(empWorker.id);
  document.getElementById('emp-code-val').textContent=code;
  // Check if already used today
  const td=today();
  const checkedIn=Checkins.find(c=>c.workerId===empWorker.id&&c.date===td&&c.status==='ok');
  const statusCard=document.getElementById('emp-status-card');

  // Excuse notice
  const excuseNotice=document.getElementById('emp-excuse-notice');
  const excuseText=document.getElementById('emp-excuse-text');
  const activeExcuse=Excuses.find(ex=>ex.workerIds.includes(empWorker.id)&&ex.dates.includes(td));
  if(activeExcuse){
    const payLbl={unpaid:'This is unpaid leave.',paid:'You will receive full pay for this period.',halfday:'You will receive half-day pay for this period.'};
    excuseNotice.style.display='block';
    excuseText.innerHTML=`You have been excused from <strong>${activeExcuse.fromDate}</strong>${activeExcuse.fromDate!==activeExcuse.toDate?` to <strong>${activeExcuse.toDate}</strong>`:''}.${activeExcuse.reason?' Reason: '+activeExcuse.reason+'.':''} ${payLbl[activeExcuse.payType]||''} Excused by: ${activeExcuse.excusedBy}.`;
  }else{
    excuseNotice.style.display='none';
  }

  if(checkedIn){
    statusCard.style.borderColor='rgba(76,175,80,.3)';statusCard.style.background='rgba(76,175,80,.05)';
    document.getElementById('emp-status-icon').textContent='✅';
    document.getElementById('emp-status-title').textContent='Checked In — '+checkedIn.time;
    document.getElementById('emp-status-sub').textContent='You are logged in for today. Your hours will be recorded by the employer.';
    document.getElementById('emp-code-status').textContent='Code already used today — resets at midnight.';
    document.getElementById('emp-code-val').style.color='var(--g)';
    document.getElementById('emp-code-val').style.textDecoration='line-through';
  } else {
    statusCard.style.borderColor='var(--bd)';statusCard.style.background='var(--surf2)';
    document.getElementById('emp-status-icon').textContent=activeExcuse?'📋':'⏳';
    document.getElementById('emp-status-title').textContent=activeExcuse?'You Are Excused Today':'Not Checked In Yet';
    document.getElementById('emp-status-sub').textContent=activeExcuse?'No check-in required. Your employer has excused you.':'Show your daily code to the site clerk when you arrive at work.';
    document.getElementById('emp-code-status').textContent='Show this to the security guard at the gate. Valid today only.';
    document.getElementById('emp-code-val').style.color='var(--y)';
    document.getElementById('emp-code-val').style.textDecoration='none';
  }
  // Time window warning
  const {within,msg}=isWithinWindow();
  const tw=document.getElementById('emp-time-warn');
  if(!within){tw.style.display='block';tw.textContent='⏰ '+msg;}
  else{
    const logoutEval=evalLogoutRule(empWorker);
    if(logoutEval.warn){
      tw.style.display='block';
      tw.style.borderColor=logoutEval.mandatory?'rgba(244,67,54,.4)':'rgba(255,152,0,.4)';
      tw.style.background=logoutEval.mandatory?'rgba(244,67,54,.08)':'rgba(255,152,0,.08)';
      tw.style.color=logoutEval.mandatory?'var(--r)':'var(--o)';
      tw.textContent=logoutEval.msg;
    }else{tw.style.display='none';}
  }
  renderEmpHistory();
}

function openClerkPIN(){
  document.getElementById('clerk-pin-entry').style.display='block';
  document.getElementById('clerk-pin-input').value='';
  document.getElementById('clerk-pin-err').style.display='none';
  setTimeout(()=>document.getElementById('clerk-pin-input').focus(),50);
}

function cancelClerkPIN(){
  document.getElementById('clerk-pin-entry').style.display='none';
}

function verifyClerkPIN(){
  const entered=document.getElementById('clerk-pin-input').value.trim();
  if(!empWorker||!empWorker.isClerk){return;}
  if(entered===empWorker.clerkPin){
    clerkWorker=empWorker;
    document.getElementById('clerk-pin-entry').style.display='none';
    document.getElementById('clerk-access-banner').style.display='none';
    const cam=document.getElementById('clerk-active-mode');
    cam.style.display='flex';cam.style.flexDirection='column';cam.style.gap='12px';
    document.getElementById('clerk-active-name').textContent=clerkWorker.name+' — Clerk mode active';
    // Populate clerk worker selector
    const sel=document.getElementById('clerk-worker-sel');
    sel.innerHTML='<option value="">Select worker...</option>'+W.map(w=>`<option value="${w.id}">${w.name}${w.isTest?' (Test)':''}</option>`).join('');
    // clerk code display removed — new smart flow doesn't show codes
    // clerk reset handled by clerkNextWorker
    renderCILog();
    toast('✓ Clerk mode activated');
  }else{
    document.getElementById('clerk-pin-err').style.display='block';
  }
}

// ── DEMO TIME OVERRIDE ────────────────────────────────────────────
let demoTimeOverride=null; // null = real time, else {h,m} object

function demoNow(){
  if(demoTimeOverride)return demoTimeOverride;
  const d=new Date();
  return{h:d.getHours(),m:d.getMinutes()};
}

function demoNowStr(){
  const {h,m}=demoNow();
  return String(h).padStart(2,'0')+':'+String(m).padStart(2,'0');
}

function demoNowMinutes(){
  const {h,m}=demoNow();return h*60+m;
}

function setDemoTime(){
  const val=document.getElementById('demo-time-input').value;
  if(!val){toast('Pick a time first');return;}
  const [h,m]=val.split(':').map(Number);
  demoTimeOverride={h,m};
  const label=`${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}`;
  document.getElementById('demo-time-banner').style.display='flex';
  document.getElementById('demo-time-banner-val').textContent=label;
  document.getElementById('demo-time-display').textContent=label;
  // Update time window status
  const {within,msg}=isWithinWindow();
  const st=document.getElementById('tw-status');
  if(st){st.textContent=within?'✓ Within window at this time':'⚠ Outside window at this time';st.style.color=within?'var(--gr)':'var(--r)';}
  // Refresh employee view if open
  if(empWorker)empSelect();
  toast('🕐 Demo time set to '+label);
}

function clearDemoTime(){
  demoTimeOverride=null;
  document.getElementById('demo-time-banner').style.display='none';
  document.getElementById('demo-time-display').textContent='Real time';
  const st=document.getElementById('tw-status');
  if(st){st.textContent='';} 
  if(empWorker)empSelect();
  toast('Back to real time');
}

function quickTime(t){
  document.getElementById('demo-time-input').value=t;
  setDemoTime();
}

// ── SHIFT RULE HELPERS ────────────────────────────────────────────
// Live preview in modal
function updShiftPreview(){
  const s=document.getElementById('wshift-start').value||'06:00';
  const e=document.getElementById('wshift-end').value||'17:00';
  const [sh,sm]=s.split(':').map(Number);
  const [eh,em]=e.split(':').map(Number);
  const dur=((eh*60+em)-(sh*60+sm));
  const prev=document.getElementById('shift-window-preview');
  const valid=document.getElementById('shift-validity');
  if(dur<=0){
    if(prev)prev.textContent='⚠ Shift end must be after shift start.';
    if(valid){valid.textContent='Invalid';valid.style.color='var(--r)';}
  }else{
    const h=Math.floor(dur/60),m=dur%60;
    const durStr=h>0?(h+'h'+(m>0?' '+m+'m':'')):(m+'m');
    if(prev)prev.textContent=`Worker's shift runs ${s} – ${e} (${durStr})`;
    if(valid){valid.textContent='✓ Valid';valid.style.color='var(--gr)';}
  }
  // Also re-validate login/logout against new shift
  updRulePreviews();
}

function updRulePreviews(){
  const loginFrom=document.getElementById('wlogin-from')?.value||'05:00';
  const loginTo=document.getElementById('wlogin-earliest')?.value||'08:00';
  const logoutFrom=document.getElementById('wlogout-from')?.value||'17:00';
  const logoutTo=document.getElementById('wlogout-latest')?.value||'18:00';
  const loginR=document.querySelector('input[name="login-rule-radio"]:checked')?.value||'recommended';
  const logoutR=document.querySelector('input[name="logout-rule-radio"]:checked')?.value||'recommended';
  const loginMand=loginR==='mandatory';
  const logoutMand=logoutR==='mandatory';

  // Style radio boxes
  const mb=document.getElementById('wlogin-mandatory-box');
  const rb=document.getElementById('wlogin-recommended-box');
  const mb2=document.getElementById('wlogout-mandatory-box');
  const rb2=document.getElementById('wlogout-recommended-box');
  if(mb){mb.style.borderColor=loginMand?'var(--r)':'var(--bd)';mb.style.background=loginMand?'rgba(244,67,54,.08)':'transparent';}
  if(rb){rb.style.borderColor=!loginMand?'var(--y)':'var(--bd)';rb.style.background=!loginMand?'rgba(255,205,17,.06)':'transparent';}
  if(mb2){mb2.style.borderColor=logoutMand?'var(--r)':'var(--bd)';mb2.style.background=logoutMand?'rgba(244,67,54,.08)':'transparent';}
  if(rb2){rb2.style.borderColor=!logoutMand?'var(--y)':'var(--bd)';rb2.style.background=!logoutMand?'rgba(255,205,17,.06)':'transparent';}

  // Badges
  const lb=document.getElementById('login-rule-badge');
  const ob=document.getElementById('logout-rule-badge');
  if(lb){lb.textContent=loginMand?'Mandatory':'Recommended';lb.style.background=loginMand?'rgba(244,67,54,.15)':'rgba(255,205,17,.12)';lb.style.color=loginMand?'var(--r)':'var(--y)';}
  if(ob){ob.textContent=logoutMand?'Mandatory':'Recommended';ob.style.background=logoutMand?'rgba(244,67,54,.15)':'rgba(255,205,17,.12)';ob.style.color=logoutMand?'var(--r)':'var(--y)';}

  // Previews
  const lp=document.getElementById('wlogin-preview');
  if(lp){
    lp.textContent=loginMand
      ?`Mandatory: Worker must check in between ${loginFrom} and ${loginTo}. Arriving before ${loginFrom} or after ${loginTo} is flagged and blocked.`
      :`Recommended: Expected check-in between ${loginFrom} – ${loginTo}. Outside this window is logged and flagged but not blocked.`;
    lp.style.borderLeftColor=loginMand?'rgba(244,67,54,.5)':'rgba(255,205,17,.5)';
  }
  const op=document.getElementById('wlogout-preview');
  if(op){
    op.textContent=logoutMand
      ?`Mandatory: Worker must checkout between ${logoutFrom} and ${logoutTo}. Leaving before ${logoutFrom} or staying past ${logoutTo} is flagged.`
      :`Recommended: Expected checkout between ${logoutFrom} – ${logoutTo}. A reminder is shown outside this window but no hard block.`;
    op.style.borderLeftColor=logoutMand?'rgba(244,67,54,.5)':'rgba(255,205,17,.5)';
    op.style.color='var(--g)';
  }
}

// Evaluate login rule for a worker at current demo time
function evalLoginRule(w){
  const fromStr=w.loginFrom||'05:00';
  const toStr=w.loginEarliest||'08:00';
  const [fh,fm]=fromStr.split(':').map(Number);
  const [th,tm]=toStr.split(':').map(Number);
  const earliest=fh*60+fm;
  const latest=th*60+tm;
  const cur=demoNowMinutes();
  if(cur>=earliest&&cur<=latest)return{ok:true};
  const tooEarly=cur<earliest;
  const waitStr=tooEarly?(earliest-cur)+'m early':(cur-latest)+'m late';
  const msg=tooEarly
    ?`${w.loginRule==='mandatory'?'Blocked':'Flagged'}: ${w.name}'s check-in window opens at ${fromStr}. Currently ${waitStr}.`
    :`${w.loginRule==='mandatory'?'Blocked':'Flagged'}: ${w.name}'s check-in window closed at ${toStr}. Currently ${waitStr}.`;
  if(w.loginRule==='mandatory'){
    return{ok:false,block:true,msg,type:'login-window-blocked'};
  }
  return{ok:true,warn:true,msg,type:'login-window-noted'};
}

// Evaluate logout rule for a worker at current demo time
function evalLogoutRule(w){
  const fromStr=w.logoutFrom||'17:00';
  const toStr=w.logoutLatest||'18:00';
  const [fh,fm]=fromStr.split(':').map(Number);
  const [th,tm]=toStr.split(':').map(Number);
  const earliest=fh*60+fm;
  const latest=th*60+tm;
  const cur=demoNowMinutes();
  if(cur>=earliest&&cur<=latest)return{ok:true};
  if(cur<earliest)return{ok:true}; // too early — no action yet
  // Past the latest checkout time
  const over=cur-latest;
  const overStr=over>=60?Math.floor(over/60)+'h '+(over%60)+'m':over+'m';
  if(w.logoutRule==='mandatory'){
    return{ok:false,warn:true,mandatory:true,msg:`⚠ ${w.name}'s checkout window was ${fromStr}–${toStr} (mandatory). It is ${demoNowStr()} — ${overStr} past. Worker must log out now.`,type:'late-logout-mandatory'};
  }else{
    return{ok:true,warn:true,msg:`Reminder: ${w.name}'s checkout window was ${fromStr}–${toStr}. It is ${demoNowStr()} — ${overStr} past. Employer will review.`,type:'late-logout-recommended'};
  }
}

// ── TIME WINDOW ───────────────────────────────────────────────────
let twStart='05:00',twEnd='10:00';

function saveTimeWindow(){
  twStart=document.getElementById('tw-start').value||'05:00';
  twEnd=document.getElementById('tw-end').value||'10:00';
  const {within,msg}=isWithinWindow();
  const st=document.getElementById('tw-status');
  st.textContent=within?'✓ Currently within window':'⚠ Currently outside window';
  st.style.color=within?'var(--gr)':'var(--r)';
  toast('Time window updated: '+twStart+' – '+twEnd);
}

function isWithinWindow(){
  const cur=demoNowMinutes();
  const [sh,sm]=twStart.split(':').map(Number);
  const [eh,em]=twEnd.split(':').map(Number);
  const start=sh*60+sm,end=eh*60+em;
  if(start===0&&end===23*60+59)return{within:true,msg:''};
  const within=cur>=start&&cur<=end;
  const msg=within?'':
    cur<start?`Check-in window opens at ${twStart}. Come back then.`:
    `Check-in window closed at ${twEnd}. Contact your employer.`;
  return{within,msg};
}

// ── MANAGER PORTAL ────────────────────────────────────────────────

function updMgrDrops(){
  const sel=document.getElementById('mgr-who');
  if(!sel)return;
  const managers=W.filter(w=>w.isManager);
  sel.innerHTML='<option value="">Select your name...</option>'+managers.map(w=>`<option value="${w.id}">${w.name}</option>`).join('');
}

function mgrWhoChange(){
  const wId=document.getElementById('mgr-who').value;
  const pinWrap=document.getElementById('mgr-pin-wrap');
  const pinErr=document.getElementById('mgr-pin-err');
  if(pinErr)pinErr.style.display='none';
  if(wId){pinWrap.style.display='block';document.getElementById('mgr-pin-input').value='';}
  else pinWrap.style.display='none';
}

function verifyMgrPIN(){
  const wId=document.getElementById('mgr-who').value;
  const entered=document.getElementById('mgr-pin-input').value.trim();
  const w=W.find(x=>x.id===wId);
  const err=document.getElementById('mgr-pin-err');
  if(!w||!w.isManager){if(err)err.style.display='block';return;}
  if(entered===w.managerPin){
    managerWorker=w;
    document.getElementById('mgr-gate').style.display='none';
    document.getElementById('mgr-dashboard').style.display='flex';
    document.getElementById('mgr-name-display').textContent=w.name;
    const site=w.managerSite?S.find(s=>s.id===w.managerSite)?.name||'All Sites':'All Sites';
    document.getElementById('mgr-site-display').textContent=site;
    // Show payroll card if enabled
    const pc=document.getElementById('mgr-payroll-card');
    if(pc)pc.style.display=w.managerShowPayroll?'block':'none';
    renderMgrDashboard();
    updMgrCISel();
  }else{
    if(err)err.style.display='block';
    document.getElementById('mgr-pin-input').value='';
  }
}

function exitMgrMode(){
  managerWorker=null;
  document.getElementById('mgr-gate').style.display='flex';
  document.getElementById('mgr-dashboard').style.display='none';
  document.getElementById('mgr-who').value='';
  document.getElementById('mgr-pin-wrap').style.display='none';
  document.getElementById('mgr-checkin-panel').style.display='none';
}

function getMgrSiteWorkers(){
  if(!managerWorker)return[];
  if(!managerWorker.managerSite)return W;
  // Workers assigned to this site — workers who have logged hours at the site OR all workers if site not tracked per-worker
  const siteName=S.find(s=>s.id===managerWorker.managerSite)?.name||'';
  const td=today();
  const siteWorkerIds=new Set(E.filter(e=>e.site===siteName||!siteName).map(e=>e.workerId));
  // Also include workers who haven't logged but are expected
  return W.filter(w=>siteWorkerIds.has(w.id)||!managerWorker.managerSite);
}

function getMgrSiteName(){
  if(!managerWorker)return'';
  if(!managerWorker.managerSite)return'All Sites';
  return S.find(s=>s.id===managerWorker.managerSite)?.name||'All Sites';
}

function renderMgrDashboard(){
  if(!managerWorker)return;
  const td=today();
  const siteName=getMgrSiteName();
  const siteWorkers=getMgrSiteWorkers();
  const siteIds=new Set(siteWorkers.map(w=>w.id));

  // Stats
  const todayE=E.filter(e=>e.date===td&&(siteIds.has(e.workerId)));
  const checked=new Set(Checkins.filter(c=>c.date===td&&c.type!=='checkout'&&c.status==='ok'&&siteIds.has(c.workerId)).map(c=>c.workerId));
  const excused=new Set(siteWorkers.filter(w=>isExcusedOn(w.id,td)).map(w=>w.id));
  const notLogged=siteWorkers.filter(w=>!checked.has(w.id)&&!excused.has(w.id));
  const totalHours=todayE.reduce((s,e)=>s+Number(e.hours||0),0);
  const suspToday=Susp.filter(s=>s.date===td||s.time?.includes(td)||true).filter(s=>!s.mgrDismissed).filter(s=>!siteName||siteName==='All Sites'||s.site===siteName);
  let estPay=0;
  todayE.forEach(e=>{const w=W.find(x=>x.id===e.workerId);if(w)estPay+=calcPay(w,e.hours)||0;});

  document.getElementById('mgr-st0').textContent=checked.size;
  document.getElementById('mgr-st1').textContent=notLogged.length;
  document.getElementById('mgr-st2').textContent=Math.round(totalHours*10)/10;
  document.getElementById('mgr-st3').textContent=suspToday.length;
  if(managerWorker.managerShowPayroll)document.getElementById('mgr-st4').textContent='R'+Math.round(estPay);

  // Worker list
  const wList=document.getElementById('mgr-worker-list');
  const wcnt=document.getElementById('mgr-worker-cnt');
  if(wcnt)wcnt.textContent=siteWorkers.length+' workers';
  if(wList){
    if(!siteWorkers.length){wList.innerHTML=`<div style="padding:20px;text-align:center;color:var(--g);font-size:13px;">No workers found for this site. Run Demo Step 1 and 3 first.</div>`;
    }else{
      wList.innerHTML=siteWorkers.map(w=>{
        const pct=rel(w.id);
        const rc=pct>=85?'var(--gr)':pct>=60?'var(--y)':'var(--r)';
        const isIn=checked.has(w.id);
        const isOut=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.type==='checkout');
        const isEx=excused.has(w.id);
        const hrs=todayE.find(e=>e.workerId===w.id)?.hours||0;
        let badge='';
        if(isOut)badge=`<span class="badge" style="background:rgba(255,152,0,.15);color:var(--o);">← Out</span>`;
        else if(isIn)badge=`<span class="badge bgr">✓ In</span>`;
        else if(isEx)badge=`<span class="badge" style="background:rgba(255,205,17,.12);color:var(--y);">📋 Excused</span>`;
        else badge=`<span class="badge brd">✗ Not In</span>`;
        return`<div class="mgr-worker-row">
          <div style="width:34px;height:34px;background:var(--surf2);border:1px solid var(--bd);display:flex;align-items:center;justify-content:center;font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:14px;flex-shrink:0;">${w.name.charAt(0)}</div>
          <div style="flex:1;min-width:100px;">
            <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:13px;font-weight:600;">${w.name}</div>
            <div style="font-size:11px;color:var(--g);">${w.role||'Worker'} · <span style="color:${rc}">${pct}% reliable</span>${hrs?` · ${hrs}h today`:''}</div>
          </div>
          ${badge}
        </div>`;
      }).join('');
    }
  }

  // Suspicious list for manager
  const sList=document.getElementById('mgr-susp-list');
  const scnt=document.getElementById('mgr-susp-cnt');
  if(scnt)scnt.textContent=suspToday.length+' active flag'+(suspToday.length!==1?'s':'');
  if(sList){
    if(!suspToday.length){
      sList.innerHTML=`<div style="padding:20px;text-align:center;color:var(--g);font-size:13px;">No active suspicious flags for your site.</div>`;
    }else{
      sList.innerHTML=suspToday.map(s=>`
        <div style="padding:12px 16px;border-bottom:1px solid var(--bd);display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap;">
          <div style="flex:1;min-width:160px;">
            <div style="font-family:'Barlow Semi Condensed',sans-serif;font-size:12px;font-weight:600;color:var(--r);">${s.type?.replace(/-/g,' ').toUpperCase()||'FLAG'}</div>
            <div style="font-size:12px;color:var(--ow);margin-top:2px;">${s.workerName}</div>
            <div style="font-size:11px;color:var(--g);margin-top:2px;">${s.note}</div>
            <div style="font-size:10px;color:var(--g);margin-top:2px;">${s.time} · ${s.loggedBy||'System'}</div>
          </div>
          <button onclick="openMgrDismiss('${s.id}')" style="font-size:10px;font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:transparent;border:1px solid var(--g);color:var(--g);padding:4px 12px;cursor:pointer;white-space:nowrap;" onmouseover="this.style.borderColor='var(--pu)';this.style.color='var(--pu)'" onmouseout="this.style.borderColor='var(--g)';this.style.color='var(--g)'">Dismiss ✓</button>
        </div>`).join('');
    }
  }
}

function openMgrDismiss(suspId){
  const s=Susp.find(x=>x.id===suspId);
  if(!s)return;
  mgrDismissPending=suspId;
  const detail=document.getElementById('mmgr-dismiss-detail');
  if(detail)detail.innerHTML=`<strong>${s.type?.replace(/-/g,' ').toUpperCase()}</strong><br>${s.workerName} · ${s.time}<br><span style="color:var(--g)">${s.note}</span>`;
  document.getElementById('mgr-dismiss-note').value='';
  document.getElementById('mmgr-dismiss').classList.add('open');
}

function confirmMgrDismiss(){
  const note=document.getElementById('mgr-dismiss-note').value.trim();
  if(!note){toast('A summary is required to dismiss this flag');return;}
  const s=Susp.find(x=>x.id===mgrDismissPending);
  if(s){
    s.mgrDismissed=true;
    s.mgrDismissedBy=managerWorker?.name||'Manager';
    s.mgrDismissedAt=new Date().toLocaleString('en-ZA');
    s.mgrDismissNote=note;
  }
  cm('mmgr-dismiss');
  mgrDismissPending=null;
  renderMgrDashboard();
  renderSuspicious(); // update employer view
  toast('✓ Flag dismissed and archived');
}

// Manager quick-actions open employer modals pre-filtered to site
function openMgrExcuse(){openExcuseModal();}
function openMgrDispute(){openAddDispute();}
function openMgrCompDays(){openMakeupModal();}
function openMgrOTDays(){openOvertimeBonusModal();}

function openMgrCheckin(){
  const p=document.getElementById('mgr-checkin-panel');
  if(p)p.style.display=p.style.display==='none'?'block':'none';
  updMgrCISel();
}
function closeMgrCheckin(){
  const p=document.getElementById('mgr-checkin-panel');
  if(p)p.style.display='none';
}

function updMgrCISel(){
  const sel=document.getElementById('mgr-ci-sel');
  if(!sel)return;
  const workers=getMgrSiteWorkers();
  sel.innerHTML='<option value="">Select worker at your site...</option>'+workers.map(w=>`<option value="${w.id}">${w.name}${w.isTest?' (Test)':''}</option>`).join('');
}

function mgrCISelectWorker(){
  const wId=document.getElementById('mgr-ci-sel').value;
  const dirWrap=document.getElementById('mgr-ci-dir-wrap');
  if(!wId){if(dirWrap)dirWrap.style.display='none';return;}
  if(dirWrap)dirWrap.style.display='block';
  mgrSetDir('in');
}

function mgrSetDir(dir){
  mgrDir=dir;
  const inBtn=document.getElementById('mgr-dir-in');
  const outBtn=document.getElementById('mgr-dir-out');
  const btn=document.getElementById('mgr-ci-btn');
  if(dir==='in'){
    if(inBtn){inBtn.style.borderColor='var(--gr)';inBtn.style.background='rgba(76,175,80,.1)';inBtn.style.color='var(--gr)';}
    if(outBtn){outBtn.style.borderColor='var(--bd)';outBtn.style.background='transparent';outBtn.style.color='var(--g)';}
    if(btn){btn.textContent='✓ Confirm Check-In';btn.style.background='var(--gr)';}
  }else{
    if(outBtn){outBtn.style.borderColor='var(--o)';outBtn.style.background='rgba(255,152,0,.1)';outBtn.style.color='var(--o)';}
    if(inBtn){inBtn.style.borderColor='var(--bd)';inBtn.style.background='transparent';inBtn.style.color='var(--g)';}
    if(btn){btn.textContent='← Confirm Checkout';btn.style.background='var(--o)';}
  }
  mgrUpdCIWindow();
}

function mgrUpdCIWindow(){
  const wId=document.getElementById('mgr-ci-sel').value;
  const w=W.find(x=>x.id===wId);
  const win=document.getElementById('mgr-ci-window');
  if(!w||!win)return;
  const cur=demoNowMinutes();
  let from,to,rule;
  if(mgrDir==='in'){
    from=(w.loginFrom||'05:00').split(':').map(Number);
    to=(w.loginEarliest||'08:00').split(':').map(Number);
    rule=w.loginRule||'recommended';
  }else{
    from=(w.logoutFrom||'17:00').split(':').map(Number);
    to=(w.logoutLatest||'18:00').split(':').map(Number);
    rule=w.logoutRule||'recommended';
  }
  const inWin=cur>=(from[0]*60+from[1])&&cur<=(to[0]*60+to[1]);
  const winStr=`${from[0].toString().padStart(2,'0')}:${from[1].toString().padStart(2,'0')} – ${to[0].toString().padStart(2,'0')}:${to[1].toString().padStart(2,'0')}`;
  win.innerHTML=`${inWin?'✅':'❌'} ${mgrDir==='in'?'Check-In':'Checkout'} window: <strong>${winStr}</strong> · Current: ${demoNowStr()} · <span style="color:${rule==='mandatory'?'var(--r)':'var(--y)'}">${rule.toUpperCase()}</span>`;
  win.style.borderLeft=`3px solid ${inWin?'var(--gr)':'var(--r)'}`;
}

function mgrSubmitCI(){
  const wId=document.getElementById('mgr-ci-sel').value;
  const w=W.find(x=>x.id===wId);
  if(!w){toast('Select a worker');return;}
  const td=today();
  const loggedBy=(managerWorker?.name||'Manager')+' (Manager)';
  const res=document.getElementById('mgr-ci-res');
  if(mgrDir==='in'){
    const alreadyIn=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.status==='ok'&&c.type!=='checkout');
    if(alreadyIn){if(res){res.style.cssText='display:block;padding:12px;text-align:center;border:2px solid rgba(255,205,17,.4);background:rgba(255,205,17,.06);font-family:\'Barlow Semi Condensed\',sans-serif;font-size:13px;color:var(--y);';res.textContent='Already checked in at '+alreadyIn.time;}return;}
    const code=genCodeFor(w.id);
    const loginEval=evalLoginRule(w);
    Checkins.push({id:uid(),workerId:w.id,workerName:w.name,date:td,time:now(),status:'ok',type:'checkin',codeUsed:code,loggedBy,flagged:loginEval.warn});
    E.push({id:uid(),workerId:w.id,workerName:w.name,hours:8,site:getMgrSiteName(),date:td,time:now(),loggedBy,payType:w.payType,isTest:w.isTest});
    if(loginEval.warn)Susp.push({id:uid(),type:'mgr-checkin-flagged',workerName:w.name,note:`Manager check-in outside window: ${loginEval.msg}`,code,site:getMgrSiteName(),time:new Date().toLocaleString('en-ZA'),loggedBy,portal:'Manager Portal'});
    if(res){res.style.cssText='display:block;padding:12px;text-align:center;border:2px solid rgba(76,175,80,.4);background:rgba(76,175,80,.06);font-family:\'Barlow Semi Condensed\',sans-serif;font-size:13px;color:var(--gr);';res.textContent='✅ '+w.name+' checked in'+(loginEval.warn?' (flagged)':'');}
  }else{
    const checkedIn=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.status==='ok'&&c.type!=='checkout');
    if(!checkedIn){if(res){res.style.cssText='display:block;padding:12px;text-align:center;border:2px solid rgba(255,205,17,.4);background:rgba(255,205,17,.06);font-family:\'Barlow Semi Condensed\',sans-serif;font-size:13px;color:var(--y);';res.textContent='⚠ Not checked in today — cannot checkout.';}return;}
    let hrs=8;
    const[ch,cm2]=checkedIn.time.split(':').map(Number);const[nh,nm]=now().split(':').map(Number);
    hrs=Math.max(0,Math.round(((nh*60+nm)-(ch*60+cm2))/60*10)/10);
    const code=genCheckoutCodeFor(w.id);
    Checkins.push({id:uid(),workerId:w.id,workerName:w.name,date:td,time:now(),status:'ok',type:'checkout',codeUsed:code,loggedBy,hoursWorked:hrs});
    const ei=E.findIndex(e=>e.workerId===w.id&&e.date===td);if(ei>-1)E[ei].hours=hrs;
    if(res){res.style.cssText='display:block;padding:12px;text-align:center;border:2px solid rgba(76,175,80,.4);background:rgba(76,175,80,.06);font-family:\'Barlow Semi Condensed\',sans-serif;font-size:13px;color:var(--gr);';res.textContent='✅ '+w.name+` checked out · ${hrs}h logged`;}
  }
  renderCILog();renderDash();renderMgrDashboard();renderSuspicious();updBanner();
  toast('✓ Done');
}

// ── CLERK PORTAL (smart flow — clerk never sees the code) ─────────
let clerkDir='in'; // 'in' or 'out'

function clerkSelectWorker(){
  const wId=document.getElementById('clerk-worker-sel').value;
  const dirWrap=document.getElementById('clerk-direction-wrap');
  const statusWrap=document.getElementById('clerk-window-status');
  const submitBtn=document.getElementById('clerk-submit-btn');
  const res=document.getElementById('clerk-submit-res');
  if(res)res.style.display='none';
  if(!wId){dirWrap.style.display='none';statusWrap.style.display='none';if(submitBtn)submitBtn.style.display='none';return;}
  dirWrap.style.display='block';
  clerkDir='in';
  // Reset direction buttons
  document.getElementById('clerk-dir-in').style.cssText='flex:1;padding:10px;font-family:\'Barlow Condensed\',sans-serif;font-weight:900;font-size:13px;letter-spacing:.06em;text-transform:uppercase;border:2px solid var(--gr);background:rgba(76,175,80,.1);color:var(--gr);cursor:pointer;transition:all .2s;';
  document.getElementById('clerk-dir-out').style.cssText='flex:1;padding:10px;font-family:\'Barlow Condensed\',sans-serif;font-weight:900;font-size:13px;letter-spacing:.06em;text-transform:uppercase;border:2px solid var(--bd);background:transparent;color:var(--g);cursor:pointer;transition:all .2s;';
  clerkUpdWindowStatus();
}

function clerkSetDir(dir){
  clerkDir=dir;
  const inBtn=document.getElementById('clerk-dir-in');
  const outBtn=document.getElementById('clerk-dir-out');
  if(dir==='in'){
    inBtn.style.borderColor='var(--gr)';inBtn.style.background='rgba(76,175,80,.1)';inBtn.style.color='var(--gr)';
    outBtn.style.borderColor='var(--bd)';outBtn.style.background='transparent';outBtn.style.color='var(--g)';
  }else{
    outBtn.style.borderColor='var(--o)';outBtn.style.background='rgba(255,152,0,.1)';outBtn.style.color='var(--o)';
    inBtn.style.borderColor='var(--bd)';inBtn.style.background='transparent';inBtn.style.color='var(--g)';
  }
  clerkUpdWindowStatus();
}

function clerkUpdWindowStatus(){
  const wId=document.getElementById('clerk-worker-sel').value;
  const w=W.find(x=>x.id===wId);
  const statusWrap=document.getElementById('clerk-window-status');
  const submitBtn=document.getElementById('clerk-submit-btn');
  if(!w){statusWrap.style.display='none';if(submitBtn)submitBtn.style.display='none';return;}

  statusWrap.style.display='block';
  const bypassWrap=document.getElementById('clerk-bypass-wrap');
  const bypassChk=document.getElementById('clerk-bypass-chk');
  const mandatoryAck=document.getElementById('clerk-mandatory-ack');
  bypassChk.checked=false;
  mandatoryAck.style.display='none';

  let inWindow, windowStr, rule;
  const cur=demoNowMinutes();
  if(clerkDir==='in'){
    const from=(w.loginFrom||'05:00').split(':').map(Number);
    const to=(w.loginEarliest||'08:00').split(':').map(Number);
    inWindow=cur>=(from[0]*60+from[1])&&cur<=(to[0]*60+to[1]);
    windowStr=`${w.loginFrom||'05:00'} – ${w.loginEarliest||'08:00'}`;
    rule=w.loginRule||'recommended';
  }else{
    // For checkout — check they've checked in first
    const td=today();
    const checkedIn=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.status==='ok'&&c.type!=='checkout');
    if(!checkedIn){
      document.getElementById('clerk-window-icon').textContent='⚠️';
      document.getElementById('clerk-window-label').style.color='var(--y)';
      document.getElementById('clerk-window-label').textContent='Not Checked In Today';
      document.getElementById('clerk-window-sub').textContent='This worker has no check-in recorded for today. Cannot checkout without check-in.';
      document.getElementById('clerk-window-rule-badge').textContent='';
      bypassWrap.style.display='none';
      if(submitBtn)submitBtn.style.display='none';
      return;
    }
    const from=(w.logoutFrom||'17:00').split(':').map(Number);
    const to=(w.logoutLatest||'18:00').split(':').map(Number);
    inWindow=cur>=(from[0]*60+from[1])&&cur<=(to[0]*60+to[1]);
    windowStr=`${w.logoutFrom||'17:00'} – ${w.logoutLatest||'18:00'}`;
    rule=w.logoutRule||'recommended';
  }

  const icon=document.getElementById('clerk-window-icon');
  const lbl=document.getElementById('clerk-window-label');
  const sub=document.getElementById('clerk-window-sub');
  const badge=document.getElementById('clerk-window-rule-badge');

  if(inWindow){
    icon.textContent='✅';
    lbl.textContent=`Within ${clerkDir==='in'?'Check-In':'Checkout'} Window`;
    lbl.style.color='var(--gr)';
    sub.textContent=`Window: ${windowStr} · Current: ${demoNowStr()}`;
    badge.textContent=rule.toUpperCase();
    badge.style.background=rule==='mandatory'?'rgba(244,67,54,.15)':'rgba(255,205,17,.12)';
    badge.style.color=rule==='mandatory'?'var(--r)':'var(--y)';
    bypassWrap.style.display='none';
    if(submitBtn){
      submitBtn.style.display='block';
      submitBtn.textContent=clerkDir==='in'?'✓ Confirm & Submit Check-In':'← Confirm & Submit Checkout';
      submitBtn.style.background=clerkDir==='in'?'var(--gr)':'var(--o)';
    }
  }else{
    icon.textContent='❌';
    lbl.textContent=`Outside ${clerkDir==='in'?'Check-In':'Checkout'} Window`;
    lbl.style.color='var(--r)';
    sub.textContent=`Window: ${windowStr} · Current: ${demoNowStr()} · ${rule==='mandatory'?'MANDATORY — blocked unless overridden':'Recommended — can override with reason'}`;
    badge.textContent=rule.toUpperCase();
    badge.style.background='rgba(244,67,54,.15)';badge.style.color='var(--r)';
    bypassWrap.style.display='block';
    if(submitBtn)submitBtn.style.display='none'; // only shown after bypass confirmed
  }
}

function clerkUpdBypass(){
  const chk=document.getElementById('clerk-bypass-chk');
  const wId=document.getElementById('clerk-worker-sel').value;
  const w=W.find(x=>x.id===wId);
  const mandatoryAck=document.getElementById('clerk-mandatory-ack');
  const submitBtn=document.getElementById('clerk-submit-btn');
  if(!w||!chk.checked){
    mandatoryAck.style.display='none';
    if(submitBtn)submitBtn.style.display='none';
    return;
  }
  const rule=clerkDir==='in'?(w.loginRule||'recommended'):(w.logoutRule||'recommended');
  if(rule==='mandatory'){
    document.getElementById('clerk-mandatory-msg').textContent=`⚠ ${w.name} has a MANDATORY ${clerkDir==='in'?'check-in':'checkout'} window. Proceeding will override this rule and will be logged to suspicious activity. The employer will be notified.`;
    mandatoryAck.style.display='block';
    document.getElementById('clerk-mandatory-confirm').checked=false;
    if(submitBtn)submitBtn.style.display='none';
    document.getElementById('clerk-mandatory-confirm').onchange=function(){
      if(submitBtn){
        submitBtn.style.display=this.checked?'block':'none';
        submitBtn.textContent=clerkDir==='in'?'✓ Override & Submit Check-In (Logged)':'← Override & Submit Checkout (Logged)';
        submitBtn.style.background='var(--r)';
      }
    };
  }else{
    mandatoryAck.style.display='none';
    if(submitBtn){
      submitBtn.style.display='block';
      submitBtn.textContent=clerkDir==='in'?'⚠ Submit Check-In (Outside Window)':'⚠ Submit Checkout (Outside Window)';
      submitBtn.style.background='var(--o)';
    }
  }
}

function clerkSubmit(){
  const wId=document.getElementById('clerk-worker-sel').value;
  const w=W.find(x=>x.id===wId);
  if(!w){toast('Select a worker first');return;}
  const td=today();
  const bypass=document.getElementById('clerk-bypass-chk')?.checked||false;
  const rule=clerkDir==='in'?(w.loginRule||'recommended'):(w.logoutRule||'recommended');
  const loggedBy=clerkWorker?clerkWorker.name+' (Site Clerk)':EMPLOYER_NAME+' (Clerk)';

  if(clerkDir==='in'){
    const alreadyIn=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.status==='ok'&&c.type!=='checkout');
    if(alreadyIn){_clerkShowRes('⚠️','Already Checked In','Checked in at '+alreadyIn.time,'Already In','rgba(255,205,17,.4)','rgba(255,205,17,.06)','var(--y)');return;}
    const code=genCodeFor(w.id);
    const flagged=bypass;
    const suspType=bypass?(rule==='mandatory'?'bypass-mandatory-checkin':'bypass-recommended-checkin'):null;
    Checkins.push({id:uid(),workerId:w.id,workerName:w.name,date:td,time:now(),status:'ok',type:'checkin',codeUsed:code,loggedBy,flagged});
    E.push({id:uid(),workerId:w.id,workerName:w.name,hours:8,site:S[0]?.name||'',date:td,time:now(),loggedBy,payType:w.payType,isTest:w.isTest});
    if(suspType)Susp.push({id:uid(),type:suspType,workerName:w.name,note:`Clerk check-in bypass (${rule}): ${w.name} at ${demoNowStr()}`,code,site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy,portal:'Clerk Portal'});
    _clerkShowRes(flagged?'⚠️':'✅',w.name,flagged?'Check-in approved — outside window (logged)':ptL(w.payType)+' · Check-in approved',flagged?'Approved — Flagged':'Entry Approved',flagged?'rgba(255,152,0,.4)':'rgba(76,175,80,.4)',flagged?'rgba(255,152,0,.06)':'rgba(76,175,80,.06)',flagged?'var(--o)':'var(--gr)');
    renderCILog();renderDash();updBanner();renderSuspicious();
    toast((flagged?'⚠ ':' ✓ ')+w.name+' checked in');
  }else{
    // Checkout
    const checkedIn=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.status==='ok'&&c.type!=='checkout');
    const alreadyOut=Checkins.find(c=>c.workerId===w.id&&c.date===td&&c.type==='checkout');
    if(alreadyOut){_clerkShowRes('⚠️','Already Checked Out','Checked out at '+alreadyOut.time,'Already Out','rgba(255,205,17,.4)','rgba(255,205,17,.06)','var(--y)');return;}
    // Calculate hours
    let hoursWorked=8;
    if(checkedIn){const[ch,cm]=checkedIn.time.split(':').map(Number);const[nh,nm]=now().split(':').map(Number);hoursWorked=Math.max(0,Math.round(((nh*60+nm)-(ch*60+cm))/60*10)/10);}
    const code=genCheckoutCodeFor(w.id);
    const flagged=bypass;
    const suspType=bypass?(rule==='mandatory'?'bypass-mandatory-checkout':'bypass-recommended-checkout'):null;
    Checkins.push({id:uid(),workerId:w.id,workerName:w.name,date:td,time:now(),status:'ok',type:'checkout',codeUsed:code,loggedBy,hoursWorked,flagged});
    const eIdx=E.findIndex(e=>e.workerId===w.id&&e.date===td);
    if(eIdx>-1)E[eIdx].hours=hoursWorked;
    if(suspType)Susp.push({id:uid(),type:suspType,workerName:w.name,note:`Clerk checkout bypass (${rule}): ${w.name} at ${demoNowStr()}. Hours: ${hoursWorked}`,code,site:S[0]?.name||'',time:new Date().toLocaleString('en-ZA'),loggedBy,portal:'Clerk Portal'});
    _clerkShowRes(flagged?'⚠️':'✅',w.name,`Checked out · ${hoursWorked} hrs logged${flagged?' — outside window (logged)':''}`,flagged?'Checkout — Flagged':'Checkout Approved',flagged?'rgba(255,152,0,.4)':'rgba(76,175,80,.4)',flagged?'rgba(255,152,0,.06)':'rgba(76,175,80,.06)',flagged?'var(--o)':'var(--gr)');
    renderCILog();renderDash();updBanner();renderSuspicious();
    toast((flagged?'⚠ ':' ✓ ')+w.name+` checked out · ${hoursWorked}h`);
  }
}

function _clerkShowRes(icon,name,msg,tag,borderCol,bgCol,nameCol){
  const res=document.getElementById('clerk-submit-res');
  if(!res)return;
  res.style.cssText=`display:block;padding:14px;text-align:center;border:2px solid ${borderCol};background:${bgCol};`;
  document.getElementById('clerk-submit-ric').textContent=icon;
  document.getElementById('clerk-submit-rn').style.color=nameCol;
  document.getElementById('clerk-submit-rn').textContent=name;
  document.getElementById('clerk-submit-rm').textContent=msg;
  document.getElementById('clerk-submit-rt').style.cssText=`background:${borderCol.replace(',.4)','.15)')};color:${nameCol};`;
  document.getElementById('clerk-submit-rt').textContent=tag;
  const submitBtn=document.getElementById('clerk-submit-btn');
  if(submitBtn)submitBtn.style.display='none';
}

function clerkNextWorker(){
  document.getElementById('clerk-worker-sel').value='';
  document.getElementById('clerk-direction-wrap').style.display='none';
  document.getElementById('clerk-window-status').style.display='none';
  document.getElementById('clerk-submit-btn').style.display='none';
  document.getElementById('clerk-submit-res').style.display='none';
  document.getElementById('clerk-bypass-chk').checked=false;
  document.getElementById('clerk-mandatory-ack').style.display='none';
}

function ecnpd(k){} // kept for compat — no longer used in clerk portal
function empClerkReset(){clerkNextWorker();}
function empClerkCheck(){} // replaced by clerkSubmit
function clerkGenCode(){clerkSelectWorker();} // alias for compat

function exitClerkMode(){
  clerkWorker=null;
  document.getElementById('clerk-active-mode').style.display='none';
  document.getElementById('clerk-access-banner').style.display=empWorker?.isClerk?'block':'none';
  const mgrBanner=document.getElementById('mgr-access-banner');
  if(mgrBanner)mgrBanner.style.display=empWorker?.isManager?'block':'none';
  toast('Exited clerk mode');
}
function renderEmpHistory(){
  const div=document.getElementById('emp-hist');
  const totEl=document.getElementById('emp-week-total');
  if(!empWorker){if(div)div.innerHTML='<div style="color:var(--g);font-size:13px;text-align:center;padding:12px">Select your name above.</div>';return;}
  const myE=E.filter(e=>e.workerId===empWorker.id).slice(-7).reverse();
  const weekTotal=myE.reduce((s,e)=>s+(+e.hours||0),0);
  if(totEl)totEl.textContent=weekTotal?weekTotal+'hrs':'—';
  if(!myE.length){div.innerHTML='<div style="color:var(--g);font-size:13px;text-align:center;padding:12px">No entries this week. Check in via the site clerk to have hours logged.</div>';return;}
  div.innerHTML=myE.map(e=>`<div class="eh"><div><div style="font-family:'Barlow Semi Condensed',sans-serif;font-weight:600;font-size:13px">${e.date}</div><div style="font-size:11px;color:var(--g)">${e.site||'—'}${e.loggedBy?` · logged by ${e.loggedBy}`:''}</div></div><div style="font-family:'Barlow Condensed',sans-serif;font-weight:900;font-size:24px;color:var(--y)">${e.hours}<span style="font-size:13px;font-weight:400;color:var(--g)"> hrs</span></div></div>`).join('');
}

// ── DEMO CONTROLS ─────────────────────────────────────────────────
function demoWorkers(countOverride){
  const count=countOverride||parseInt(document.getElementById('dwc')?.value)||5;
  const pts=Object.keys(PT);
  const ruleSets=[
    {loginRule:'mandatory',logoutRule:'mandatory'},
    {loginRule:'recommended',logoutRule:'mandatory'},
    {loginRule:'mandatory',logoutRule:'recommended'},
    {loginRule:'recommended',logoutRule:'recommended'},
  ];
  for(let i=1;i<=count;i++){
    const pt=pts[(i-1)%pts.length];
    const defaults={hourly:45,daily:380,weekly:1800,monthly:7500,piece:28,'day-overtime':350,shift:420,contract:5000};
    const isClerk=i===1;
    const isManager=i===2;
    const rules=ruleSets[(i-1)%ruleSets.length];
    W.push({id:uid(),name:`Test Worker ${W.length+1}`,role:isClerk?'Site Clerk / Operator':isManager?'Site Manager':'Test Operator',phone:`+27 82 ${String(7000000+W.length*111111).slice(0,7)}`,expectedDays:5,payType:pt,rate:defaults[pt]||350,ot:'9',otMult:'1.5',isTest:true,isClerk,clerkPin:isClerk?'1234':'',isManager,managerPin:isManager?'5678':'',managerSite:'',managerShowPayroll:false,shiftStart:'06:00',shiftEnd:'17:00',loginFrom:'05:00',loginEarliest:'08:00',loginRule:rules.loginRule,logoutFrom:'17:00',logoutLatest:'18:00',logoutRule:rules.logoutRule,geoFence:'default',createdAt:new Date().toISOString()});
  }
  renderAll();toast(`✓ ${count} test workers. Worker 1 = Clerk (PIN:1234) · Worker 2 = Manager (PIN:5678)`);
}

function demoSites(){
  ['Test Site A — Midrand','Test Site B — Centurion','Test Site C — Pretoria'].forEach(name=>{
    if(!S.find(s=>s.name===name))S.push({id:uid(),name,desc:'Demo site',isTest:true});
  });
  renderAll();toast('✓ 3 test sites added');
}

function demoHours(){
  const testW=W.filter(w=>w.isTest);
  if(!testW.length){toast('Generate test workers first');return;}
  const td=today();
  testW.forEach((w,i)=>{
    if(!E.find(e=>e.workerId===w.id&&e.date===td)){
      const hrs=[6,7,8,8,9,10][i%6];
      const site=S[i%Math.max(S.length,1)]?.name||'Test Site';
      E.push({id:uid(),workerId:w.id,workerName:w.name,hours:hrs,site,date:td,time:now(),loggedBy:'demo',payType:w.payType,isTest:true});
    }
  });
  renderAll();toast(`✓ Hours logged for ${testW.length} workers`);
}

function demoFillMonth(){
  const testW=W.filter(w=>w.isTest);
  if(!testW.length){toast('Generate test workers first');return;}
  if(!S.length){toast('Generate test sites first (Step 2)');return;}
  const now=new Date();
  const year=now.getFullYear();
  const month=now.getMonth();
  const lastDay=new Date(year,month+1,0).getDate();
  // Start from today (inclusive)
  let added=0;
  for(let day=now.getDate();day<=lastDay;day++){
    const d=new Date(year,month,day);
    const dow=d.getDay();
    if(dow===0||dow===6)continue; // skip weekends
    const dateStr=`${year}-${String(month+1).padStart(2,'0')}-${String(day).padStart(2,'0')}`;
    testW.forEach((w,i)=>{
      if(E.find(e=>e.workerId===w.id&&e.date===dateStr))return; // don't double-log
      // Vary hours realistically — occasional short day, half day, standard, overtime
      const hrsOptions=[6,7,8,8,8,9,10,4];
      const hrs=hrsOptions[(i+day)%hrsOptions.length];
      // Occasionally skip a worker (simulate absence) — roughly 1 in 8 chance
      if((i*7+day*3)%8===0)return;
      const site=S[(i+day)%S.length]?.name||'Test Site';
      const timeHr=5+Math.floor((i+day)%3);
      const timeMn=String(Math.floor((day*7+i*13)%60)).padStart(2,'0');
      E.push({id:uid(),workerId:w.id,workerName:w.name,hours:hrs,site,date:dateStr,time:`${String(timeHr).padStart(2,'0')}:${timeMn}`,loggedBy:'demo-month-fill',payType:w.payType,isTest:true});
      Checkins.push({id:uid(),workerId:w.id,workerName:w.name,date:dateStr,time:`${String(timeHr).padStart(2,'0')}:${timeMn}`,status:'ok',codeUsed:'demo',loggedBy:'demo'});
    });
    added++;
  }
  renderAll();
  const remaining=lastDay-now.getDate()+1;
  toast(`✓ Filled ${added} working days to end of month (${new Date(year,month+1,0).toLocaleString('en-ZA',{month:'long'})} ${year})`);
}

function demoMakeExportReady(){
  const testW=W.filter(w=>w.isTest);
  if(!testW.length){toast('No test workers to convert');return;}
  const hasHours=testW.filter(w=>E.some(e=>e.workerId===w.id));
  if(!hasHours.length){toast('Log hours first — use Step 3 or 3B');return;}
  // Mark test workers and their entries as non-test
  testW.forEach(w=>{w.isTest=false;});
  E.forEach(e=>{if(testW.find(w=>w.id===e.workerId))e.isTest=false;});
  renderAll();
  toast(`✓ ${testW.length} workers are now export-ready — go to the Export page`);
}

function demoSusp(){
  Susp.push({id:uid(),type:'invalid-code',workerName:'Unknown',note:'Demo: Invalid code "999999" entered at clerk device',code:'999999',site:'Test Site A — Midrand',time:new Date().toLocaleString('en-ZA')});
  Susp.push({id:uid(),type:'geofence-fail',workerName:'Test Worker 2',note:'Demo: Worker attempted to log from outside geo-fence boundary (2.3km away)',code:'',site:'Test Site B — Centurion',time:new Date().toLocaleString('en-ZA')});
  renderSuspicious();toast('⚠ 2 suspicious events simulated');
}

function demoGoCI(){
  const testW=W.find(w=>w.isTest);
  if(!testW){toast('Generate test workers first');return;}
  showPg('checkin',document.querySelector('.ni[onclick*="checkin"]'));
  setTimeout(()=>{const sel=document.getElementById('ci-sel');if(sel){sel.value=testW.id;genCode();}},100);
}

function demoReset(){
  if(!confirm('Reset all demo data?'))return;
  W=[];E=[];S=[];D=[];Checkins=[];Susp=[];Excuses=[];SmsQueue=[];Makeups=[];OvertimeBonuses=[];empWorker=null;
  renderAll();
  document.getElementById('emp-form').style.display='none';
  document.getElementById('emp-who').value='';
  toast('Demo reset — fresh start');
}

function updDemoState(){
  document.getElementById('ds-w').textContent=W.length;
  document.getElementById('ds-s').textContent=S.length;
  document.getElementById('ds-e').textContent=E.length;
  document.getElementById('ds-su').textContent=Susp.length;
}

// ── UTILS ─────────────────────────────────────────────────────────
function cm(id){document.getElementById(id).classList.remove('open');}
document.querySelectorAll('.mo').forEach(o=>o.addEventListener('click',e=>{if(e.target===o)o.classList.remove('open');}));
document.querySelectorAll('.md').forEach(d=>d.addEventListener('click',e=>e.stopPropagation()));
function toast(msg){const t=document.getElementById('toast');t.textContent=msg;t.classList.add('show');setTimeout(()=>t.classList.remove('show'),2800);}


// ── MOBILE HELPERS ─────────────────────────────────────────────
function closeMobileMore(){
  const m=document.getElementById('mobile-more-menu');
  if(m)m.style.display='none';
  const btn=document.getElementById('mn-more');
  if(btn)btn.classList.remove('active');
}

function toggleMobileMore(){
  const m=document.getElementById('mobile-more-menu');
  if(!m)return;
  const open=m.style.display==='block';
  m.style.display=open?'none':'block';
  const btn=document.getElementById('mn-more');
  if(btn)btn.classList.toggle('active',!open);
  // Sync stage buttons
  if(!open) syncMobStage();
}

function syncMobStage(){
  document.querySelectorAll('.mob-stage-btn').forEach(b=>{
    const s=b.getAttribute('onclick')||'';
    const match=s.match(/'([^']+)'/);
    b.classList.toggle('active', match && match[1]===currentStage);
  });
  // Sync portal buttons
  const portals=['employer','manager','storekeeper','clerk','employee'];
  portals.forEach(p=>{
    const el=document.getElementById('mob-p-'+p);
    const pv=document.getElementById('pv-'+p);
    if(el&&pv)el.classList.toggle('active',pv.classList.contains('active'));
  });
}

function applyStageAndSave(stage){
  currentStage=stage;
  localStorage.setItem('vee-stage',stage);
  applyStage(stage);
}

// Close more menu when tapping outside
document.addEventListener('click',function(e){
  const menu=document.getElementById('mobile-more-menu');
  const btn=document.getElementById('mn-more');
  if(menu&&menu.style.display==='block'&&!menu.contains(e.target)&&e.target!==btn&&!btn.contains(e.target)){
    closeMobileMore();
  }
});



// ── END OF DAY REPORT ────────────────────────────────────────────
function openEOD(){
  const td=today();
  const label=new Date().toLocaleDateString('en-ZA',{weekday:'long',day:'2-digit',month:'long',year:'numeric'});
  document.getElementById('eod-date-label').textContent=label;

  // Entries for today
  const todayEntries=E.filter(e=>e.date===td);
  const presentIds=new Set(todayEntries.map(e=>e.wid||e.workerId||e.id));
  const excusedIds=new Set((Excuses||[]).filter(ex=>{
    const d=ex.dates?ex.dates.includes(td):ex.date===td;
    return d;
  }).map(ex=>ex.wid||ex.workerId));
  const realWorkers=W.filter(w=>!w.isTest);
  const present=realWorkers.filter(w=>presentIds.has(w.id));
  const absent=realWorkers.filter(w=>!presentIds.has(w.id));
  const totalHrs=todayEntries.reduce((a,e)=>a+(parseFloat(e.hours)||0),0);
  const todayCheckins=(Checkins||[]).filter(c=>c.date===td||c.ts&&c.ts.startsWith(td));
  const todaySusp=(Susp||[]).filter(s=>s.date===td||s.ts&&s.ts.startsWith(td));

  // Stats strip
  const stats=document.getElementById('eod-stats');
  const statData=[
    {label:'Workers',val:realWorkers.length,color:'var(--ow)'},
    {label:'Present',val:present.length,color:'var(--gr)'},
    {label:'Absent',val:absent.length,color:absent.length?'var(--r)':'var(--g)'},
    {label:'Total Hrs',val:totalHrs.toFixed(1)+'h',color:'var(--y)'},
  ];
  stats.innerHTML=statData.map(s=>`
    <div style="background:var(--surf2);border:1px solid var(--bd);border-radius:10px;padding:12px 14px;text-align:center;">
      <div style="font-family:'Inter',sans-serif;font-size:9px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--g);margin-bottom:4px;">${s.label}</div>
      <div style="font-family:'Inter',sans-serif;font-size:22px;font-weight:800;color:${s.color};line-height:1;">${s.val}</div>
    </div>`).join('');

  // Present list
  const presEl=document.getElementById('eod-present');
  if(!present.length){
    presEl.innerHTML='<div style="font-size:12px;color:var(--g);font-style:italic;padding:4px 0;">No workers checked in yet.</div>';
  } else {
    presEl.innerHTML=present.map(w=>{
      const entry=todayEntries.find(e=>e.wid===w.id||e.workerId===w.id||e.id===w.id);
      const hrs=entry?(parseFloat(entry.hours)||0).toFixed(1)+'h':'—';
      const site=entry&&entry.site?entry.site:'';
      const ex=excusedIds.has(w.id)?'<span style="font-size:9px;background:rgba(255,205,17,.15);color:var(--y);padding:1px 7px;border-radius:20px;margin-left:6px;">Excused</span>':'';
      return `<div style="display:flex;align-items:center;justify-content:space-between;background:var(--surf2);border:1px solid var(--bd);border-left:2px solid var(--gr);border-radius:8px;padding:8px 12px;">
        <div style="font-family:'Inter',sans-serif;font-size:12px;font-weight:600;color:var(--ow);">${w.name}${ex}</div>
        <div style="display:flex;gap:12px;align-items:center;">
          ${site?'<span style="font-size:11px;color:var(--g);">'+site+'</span>':''}
          <span style="font-family:'Inter',sans-serif;font-size:13px;font-weight:700;color:var(--y);">${hrs}</span>
        </div>
      </div>`;
    }).join('');
  }

  // Absent list
  const abEl=document.getElementById('eod-absent');
  if(!absent.length){
    abEl.innerHTML='<div style="font-size:12px;color:var(--g);font-style:italic;padding:4px 0;">All workers accounted for. 🎉</div>';
  } else {
    abEl.innerHTML=absent.map(w=>{
      const isExcused=excusedIds.has(w.id);
      const colour=isExcused?'var(--y)':'var(--r)';
      const tag=isExcused?'Excused':'Absent';
      return `<div style="display:flex;align-items:center;justify-content:space-between;background:var(--surf2);border:1px solid var(--bd);border-left:2px solid ${colour};border-radius:8px;padding:8px 12px;">
        <div style="font-family:'Inter',sans-serif;font-size:12px;font-weight:600;color:var(--ow);">${w.name}</div>
        <span style="font-size:9px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;background:rgba(${isExcused?'255,205,17':'244,67,54'},.12);color:${colour};padding:2px 8px;border-radius:20px;">${tag}</span>
      </div>`;
    }).join('');
  }

  // Suspicious
  const suspSec=document.getElementById('eod-susp-section');
  const suspEl=document.getElementById('eod-susp');
  if(!todaySusp.length){
    suspSec.style.display='none';
  } else {
    suspSec.style.display='block';
    suspEl.innerHTML=todaySusp.map(s=>`
      <div style="background:rgba(244,67,54,.06);border:1px solid rgba(244,67,54,.25);border-left:2px solid var(--r);border-radius:8px;padding:8px 12px;">
        <div style="font-family:'Inter',sans-serif;font-size:12px;font-weight:600;color:var(--ow);">${s.name||s.worker||'Unknown'}</div>
        <div style="font-size:11px;color:var(--g);margin-top:2px;">${s.reason||s.type||'Flagged activity'}</div>
      </div>`).join('');
  }

  document.getElementById('meod').classList.add('open');
}

function printEOD(){
  const label=document.getElementById('eod-date-label').textContent;
  const stats=document.getElementById('eod-stats').innerHTML;
  const present=document.getElementById('eod-present').innerHTML;
  const absent=document.getElementById('eod-absent').innerHTML;
  const suspSec=document.getElementById('eod-susp-section');
  const suspHTML=suspSec.style.display!=='none'?'<h3 style="color:#c00;margin:16px 0 8px;">🚨 Suspicious Flags</h3>'+document.getElementById('eod-susp').innerHTML:'';
  const pw=window.open('','_blank','width=750,height=900');
  pw.document.write(`<!DOCTYPE html><html><head><title>End of Day Report — Vee Industrial</title>
  <style>
    body{font-family:Arial,sans-serif;padding:32px;color:#111;background:#fff;}
    h1{font-size:22px;font-weight:900;margin-bottom:4px;}
    h2{font-size:13px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#666;margin:16px 0 8px;}
    .sub{color:#666;font-size:13px;margin-bottom:20px;}
    .stats{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:20px;}
    .stat{background:#f5f5f2;border-radius:8px;padding:12px;text-align:center;}
    .stat-label{font-size:9px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:#888;margin-bottom:4px;}
    .stat-val{font-size:22px;font-weight:900;color:#111;}
    .row{display:flex;align-items:center;justify-content:space-between;background:#f9f9f7;border-left:3px solid #ccc;border-radius:6px;padding:8px 12px;margin-bottom:4px;}
    .row.present{border-color:#4CAF50;} .row.absent{border-color:#F44336;} .row.excused{border-color:#FFCD11;}
    .name{font-weight:700;font-size:13px;} .tag{font-size:10px;font-weight:700;padding:2px 8px;border-radius:20px;}
    .tag-absent{background:#fde;color:#c00;} .tag-excused{background:#fff8e0;color:#996600;}
    .hrs{font-weight:900;font-size:14px;color:#111;}
    .susp{background:#fde;border-left:3px solid #F44336;border-radius:6px;padding:8px 12px;margin-bottom:4px;}
    @media print{body{padding:16px;}button{display:none;}}
  