<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title><?= isset($pageTitle) ? htmlspecialchars($pageTitle).' - ' : '' ?>EduSmart CBC/CBE</title>
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet">
<meta name="googlebot" content="noindex, nofollow">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<link href="/cbe/sms/public/assets/bootstrap-icons.min.css" rel="stylesheet">
<style>
:root{--primary:#1a7f5a;--primary-dark:#145f44;--primary-light:#e8f5f0;--secondary:#2563eb;--danger:#ef4444;--success:#10b981;--warning:#f59e0b;--dark:#1e293b;--gray:#64748b;--light:#f8fafc;--border:#e2e8f0;--sidebar-w:240px;--topbar-h:60px}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Inter',sans-serif;background:var(--light);color:var(--dark);overflow-x:hidden}

/* ── Sidebar ── */
.sidebar{position:fixed;top:0;left:0;width:var(--sidebar-w);height:100vh;background:#1a7f5a;overflow-y:auto;transition:transform .3s,width .3s;z-index:1000;display:flex;flex-direction:column}
.sidebar.collapsed{width:0;overflow:hidden}
.sb-brand{padding:16px 20px;display:flex;align-items:center;gap:12px;border-bottom:1px solid rgba(255,255,255,.1);flex-shrink:0}
.sb-logo{width:36px;height:36px;background:var(--primary);border-radius:8px;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:16px;flex-shrink:0}
.sb-brand span{color:#fff;font-weight:700;font-size:14px;white-space:nowrap}
.sb-brand small{color:rgba(255,255,255,.4);font-size:10px;display:block;white-space:nowrap}
.sb-nav{padding:8px 0;flex:1}
.nav-item a{display:flex;align-items:center;gap:10px;padding:9px 16px;color:#fff;text-decoration:none;font-size:13px;transition:all .2s;border-left:3px solid transparent;white-space:nowrap}
.nav-item a:hover,.nav-item a.active{color:#fff;background:rgba(0,0,0,.15);border-left-color:#fff}
.nav-section{padding:8px 16px 3px;color:rgba(255,255,255,.6);font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:1px;white-space:nowrap}
.nav-item a i{font-size:16px;width:18px;flex-shrink:0}
.sb-footer{padding:12px 16px;border-top:1px solid rgba(255,255,255,.2);flex-shrink:0}
.sb-footer a{color:#fff;font-size:13px;text-decoration:none;display:flex;align-items:center;gap:8px;padding:8px 10px;border-radius:8px;transition:background .2s}
.sb-footer a:hover{background:rgba(0,0,0,.15)}

/* ── Topbar ── */
.topbar{position:fixed;top:0;left:var(--sidebar-w);right:0;height:var(--topbar-h);background:#fff;border-bottom:1px solid var(--border);display:flex;align-items:center;padding:0 20px;gap:12px;z-index:999;transition:left .3s;min-width:0}
.topbar.full{left:0}
.tb-toggle{background:none;border:none;cursor:pointer;font-size:20px;color:var(--gray);flex-shrink:0;padding:4px}
.tb-title{font-weight:600;font-size:15px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.tb-user{display:flex;align-items:center;gap:8px;flex-shrink:0;position:relative}
.avatar{width:34px;height:34px;border-radius:50%;background:var(--primary);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:13px;flex-shrink:0;cursor:pointer}
.user-dropdown{display:none;position:absolute;top:44px;right:0;background:#fff;border:1px solid var(--border);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.12);min-width:180px;z-index:9999;overflow:hidden}
.user-dropdown.open{display:block}
.user-dropdown-header{padding:12px 16px;border-bottom:1px solid var(--border);font-size:13px}
.user-dropdown-header strong{display:block;font-weight:600}
.user-dropdown-header span{color:var(--gray);font-size:11px}
.user-dropdown a{display:flex;align-items:center;gap:8px;padding:10px 16px;font-size:13px;color:var(--dark);text-decoration:none;transition:background .15s}
.user-dropdown a:hover{background:var(--light)}
.user-dropdown a.logout{color:var(--danger)}

/* ── Main content ── */
.main{margin-left:var(--sidebar-w);margin-top:var(--topbar-h);padding:20px;min-height:calc(100vh - var(--topbar-h));transition:margin-left .3s;min-width:0;overflow-x:hidden}
.main.full{margin-left:0}

/* ── Cards ── */
.card{background:#fff;border-radius:12px;border:1px solid var(--border);overflow:hidden;margin-bottom:20px}
.card-header{padding:14px 18px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}
.card-header h5{font-size:14px;font-weight:600}
.card-body{padding:18px}

/* ── Stat cards ── */
.stat-card{background:#fff;border-radius:12px;padding:16px;border:1px solid var(--border);display:flex;align-items:center;gap:12px;min-width:0}
.stat-icon{width:46px;height:46px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0}
.si-green{background:var(--primary-light);color:var(--primary)}
.si-blue{background:#eff6ff;color:var(--secondary)}
.si-amber{background:#fffbeb;color:var(--warning)}
.si-red{background:#fef2f2;color:var(--danger)}
.stat-info{min-width:0;flex:1}
.stat-info h3{font-size:20px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stat-info p{font-size:12px;color:var(--gray);margin-top:2px}

/* ── Tables ── */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;font-size:13px}
th{background:var(--light);padding:10px 14px;text-align:left;font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--gray);border-bottom:1px solid var(--border);white-space:nowrap}
td{padding:10px 14px;border-bottom:1px solid var(--border)}
tr:last-child td{border-bottom:none}
tr:hover td{background:#fafafa}

/* ── Forms ── */
.form-group{margin-bottom:14px}
label{display:block;font-size:13px;font-weight:500;margin-bottom:4px}
input,select,textarea{width:100%;padding:9px 12px;border:1.5px solid var(--border);border-radius:8px;font-size:13px;font-family:inherit;transition:border-color .2s;background:#fff}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 3px rgba(26,127,90,.1)}
.form-error{color:var(--danger);font-size:12px;margin-top:3px}

/* ── Buttons ── */
.btn{display:inline-flex;align-items:center;gap:6px;padding:8px 15px;border-radius:8px;font-size:13px;font-weight:500;cursor:pointer;border:none;text-decoration:none;transition:all .2s;white-space:nowrap;flex-shrink:0}
.btn-primary{background:var(--primary);color:#fff}.btn-primary:hover{background:var(--primary-dark)}
.btn-secondary{background:var(--light);color:var(--dark);border:1px solid var(--border)}.btn-secondary:hover{background:var(--border)}
.btn-danger{background:var(--danger);color:#fff}
.btn-outline{background:transparent;border:1.5px solid var(--primary);color:var(--primary)}
.btn-sm{padding:5px 10px;font-size:12px}

/* ── Badges ── */
.badge{display:inline-flex;align-items:center;padding:2px 8px;border-radius:20px;font-size:11px;font-weight:500;white-space:nowrap}
.badge-success{background:#d1fae5;color:#065f46}.badge-danger{background:#fee2e2;color:#991b1b}
.badge-warning{background:#fef3c7;color:#92400e}.badge-info{background:#dbeafe;color:#1e40af}
.badge-gray{background:#f1f5f9;color:var(--gray)}

/* ── Alerts ── */
.alert{padding:11px 14px;border-radius:8px;font-size:13px;margin-bottom:14px;display:flex;align-items:flex-start;gap:10px}
.alert-success{background:#d1fae5;color:#065f46;border:1px solid #a7f3d0}
.alert-danger{background:#fee2e2;color:#991b1b;border:1px solid #fecaca}
.alert-warning{background:#fef3c7;color:#92400e;border:1px solid #fde68a}

/* ── Grid system ── */
.grid{display:grid;gap:16px}
.g2{grid-template-columns:repeat(2,minmax(0,1fr))}
.g3{grid-template-columns:repeat(3,minmax(0,1fr))}
.g4{grid-template-columns:repeat(4,minmax(0,1fr))}

/* ── Page header ── */
.page-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px;flex-wrap:wrap;gap:10px}
.page-header h1{font-size:20px;font-weight:700}
.page-header p{color:var(--gray);font-size:12px;margin-top:2px}

/* ── Pagination ── */
.pagination{display:flex;gap:4px;flex-wrap:wrap;margin-top:14px}
.page-btn{padding:6px 11px;border-radius:6px;font-size:12px;text-decoration:none;border:1px solid var(--border);color:var(--dark);background:#fff}
.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary)}

/* ── Modal / Overlay ── */
.overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:998}
.modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:2000;align-items:center;justify-content:center;padding:16px}
.modal.open{display:flex}
.modal-box{background:#fff;border-radius:14px;width:100%;max-width:520px;max-height:92vh;overflow-y:auto}

/* ── Fullscreen restore banner ── */
.fs-restore-banner{
  display:none;position:fixed;top:0;left:0;right:0;z-index:999999;
  background:var(--primary);color:#fff;
  padding:10px 20px;align-items:center;gap:12px;
  font-size:13px;font-weight:500;
  box-shadow:0 2px 12px rgba(0,0,0,.2);
  animation:slideDown .3s ease;
}
@keyframes slideDown{from{transform:translateY(-100%)}to{transform:translateY(0)}}
.fs-restore-banner i{font-size:16px;flex-shrink:0}
.fs-restore-banner span{flex:1}
.fs-restore-banner .fs-restore-click{font-weight:700;text-decoration:underline;cursor:pointer}
.fs-restore-banner button{
  background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.4);
  color:#fff;border-radius:6px;padding:4px 12px;font-size:12px;
  cursor:pointer;white-space:nowrap;flex-shrink:0;
}
.fs-btn{background:none;border:none;cursor:pointer;font-size:18px;color:var(--gray);flex-shrink:0;padding:4px 6px;border-radius:6px;transition:all .2s;display:flex;align-items:center;justify-content:center}
.fs-btn:hover{background:var(--light);color:var(--dark)}
/* native fullscreen: hide sidebar & topbar, expand main */
:fullscreen .sidebar,:-webkit-full-screen .sidebar,:-moz-full-screen .sidebar{display:none!important}
:fullscreen .topbar,:-webkit-full-screen .topbar,:-moz-full-screen .topbar{display:none!important}
:fullscreen .main,:-webkit-full-screen .main,:-moz-full-screen .main{margin:0!important;padding:20px!important;width:100vw!important;min-height:100vh!important;overflow-y:auto!important}
:fullscreen body,:-webkit-full-screen body,:-moz-full-screen body{overflow:auto!important}
/* floating exit hint */
.fs-hint{display:none;position:fixed;bottom:18px;right:18px;background:rgba(0,0,0,.7);color:#fff;padding:7px 14px;border-radius:20px;font-size:12px;z-index:99999;pointer-events:none;gap:6px;align-items:center}
:fullscreen .fs-hint,:-webkit-full-screen .fs-hint,:-moz-full-screen .fs-hint{display:flex}
/* fullscreen topbar strip (page title only) */
.fs-bar{display:none;position:fixed;top:0;left:0;right:0;height:44px;background:var(--dark);color:#fff;align-items:center;padding:0 20px;gap:12px;z-index:99998;font-size:14px;font-weight:600}
.fs-bar .fs-bar-exit{margin-left:auto;background:none;border:1px solid rgba(255,255,255,.3);color:#fff;border-radius:6px;padding:4px 12px;font-size:12px;cursor:pointer}
:fullscreen .fs-bar,:-webkit-full-screen .fs-bar,:-moz-full-screen .fs-bar{display:flex}
:fullscreen .main,:-webkit-full-screen .main,:-moz-full-screen .main{padding-top:60px!important}

/* ── Laptop (1024–1280px): sidebar narrower, grids tighter ── */
@media(max-width:1280px){
  :root{--sidebar-w:220px}
  .g4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .stat-info h3{font-size:18px}
}
@media(max-width:1100px){
  :root{--sidebar-w:200px}
  .g3{grid-template-columns:repeat(2,minmax(0,1fr))}
  .nav-item a{font-size:12px;padding:8px 14px}
}

/* ── Tablet (769–1023px): collapse sidebar by default ── */
@media(max-width:1023px){
  :root{--sidebar-w:240px}
  .sidebar{transform:translateX(-100%)}
  .sidebar.open{transform:translateX(0)}
  .topbar{left:0!important}
  .main{margin-left:0!important;padding:16px}
  .g4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .g3{grid-template-columns:repeat(2,minmax(0,1fr))}
  .page-header{flex-direction:column;align-items:flex-start}
}

/* ── Mobile (≤600px) ── */
@media(max-width:600px){
  .main{padding:12px}
  .g4,.g3,.g2{grid-template-columns:minmax(0,1fr)}
  .stat-card{padding:12px;gap:10px}
  .stat-icon{width:38px;height:38px;font-size:17px}
  .stat-info h3{font-size:16px}
  .card-header{flex-direction:column;align-items:flex-start}
  .card-body{padding:12px}
  .btn{padding:7px 12px;font-size:12px}
  .page-header h1{font-size:17px}
  th,td{padding:8px 10px;font-size:12px}
}
</style>
<?php if(isset($extraStyles)) echo $extraStyles; ?>
</head>
<body>
<div class="overlay" id="overlay" onclick="toggleSidebar()"></div>
<aside class="sidebar" id="sidebar">
  <div class="sb-brand">
    <div class="sb-logo">E</div>
    <div><span>EduSmart</span><small>CBC/CBE Management</small></div>
  </div>
  <nav class="sb-nav">
    <?php if(isset($sidebarNav)) echo $sidebarNav; ?>
  </nav>
  <div class="sb-footer">
    <a href="<?= \Core\View::url('profile') ?>"><i class="bi bi-person-circle"></i> My Profile</a>
    <a href="<?= \Core\View::url('logout') ?>" style="margin-top:4px;color:#fca5a5"><i class="bi bi-box-arrow-left"></i> Logout</a>
  </div>
</aside>
<header class="topbar" id="topbar">
  <button class="tb-toggle" onclick="toggleSidebar()"><i class="bi bi-list"></i></button>
  <span class="tb-title"><?= isset($pageTitle) ? htmlspecialchars($pageTitle) : 'Dashboard' ?></span>
  <div class="tb-user">
    <button class="fs-btn" id="fsBtn" onclick="toggleFullscreen()" title="Toggle fullscreen (F11)"><i class="bi bi-fullscreen" id="fsIcon"></i></button>
    <?php $__user = \Core\Session::get('user'); ?>
    <div class="avatar" onclick="toggleUserDropdown()" title="<?= htmlspecialchars($__user['name'] ?? '') ?>">
      <?= strtoupper(substr($__user['name'] ?? 'U', 0, 1)) ?>
    </div>
    <div class="user-dropdown" id="userDropdown">
      <div class="user-dropdown-header">
        <strong><?= htmlspecialchars($__user['name'] ?? '') ?></strong>
        <span><?= ucfirst(str_replace('-',' ',$__user['role'] ?? '')) ?></span>
      </div>
      <a href="<?= \Core\View::url('profile') ?>"><i class="bi bi-person-circle"></i> My Profile</a>
      <a href="<?= \Core\View::url('admin/settings') ?>"><i class="bi bi-gear"></i> Settings</a>
      <a href="<?= \Core\View::url('logout') ?>" class="logout"><i class="bi bi-box-arrow-left"></i> Logout</a>
    </div>
  </div>
</header>
<main class="main" id="main">
<?php
$success = \Core\View::success();
$error   = \Core\View::error();
if($success): ?><div class="alert alert-success"><i class="bi bi-check-circle"></i> <?= htmlspecialchars($success) ?></div><?php endif;
if($error):   ?><div class="alert alert-danger"><i class="bi bi-exclamation-circle"></i> <?= htmlspecialchars($error) ?></div><?php endif;
$allErrors = \Core\Session::getFlash('errors') ?? [];
if($allErrors):?><div class="alert alert-danger"><i class="bi bi-exclamation-triangle"></i><ul style="margin:0;padding-left:16px"><?php foreach($allErrors as $k=>$errs) foreach((array)$errs as $e): ?><li><?= htmlspecialchars($e) ?></li><?php endforeach; ?></ul></div><?php endif; ?>
<?= $content ?>
</main>

<!-- Fullscreen restore banner (shown after refresh if FS was active) -->
<div class="fs-restore-banner" id="fsRestoreBanner">
  <i class="bi bi-fullscreen"></i>
  <span>Fullscreen was active before refresh. <span class="fs-restore-click">Click anywhere</span> to restore it.</span>
  <button id="fsRestoreDismiss" onclick="dismissFsRestore()">✕ Dismiss</button>
</div>

<!-- Fullscreen top bar (visible only in fullscreen) -->
<div class="fs-bar" id="fsBar">
  <div class="sb-logo" style="width:28px;height:28px;font-size:13px">E</div>
  <span><?= isset($pageTitle) ? htmlspecialchars($pageTitle) : 'EduSmart' ?></span>
  <button class="fs-bar-exit" onclick="toggleFullscreen()"><i class="bi bi-fullscreen-exit"></i> Exit Fullscreen</button>
</div>

<!-- Floating ESC hint -->
<div class="fs-hint" id="fsHint"><i class="bi bi-fullscreen-exit"></i> Press <kbd style="background:rgba(255,255,255,.2);padding:1px 5px;border-radius:3px">Esc</kbd> or click button to exit</div>

<script>
function toggleUserDropdown(){
  document.getElementById('userDropdown').classList.toggle('open');
}
document.addEventListener('click',function(e){
  var dd=document.getElementById('userDropdown');
  if(dd && !dd.closest('.tb-user').contains(e.target)) dd.classList.remove('open');
});
function toggleSidebar(){
  var sb=document.getElementById('sidebar');
  var ov=document.getElementById('overlay');
  var m=document.getElementById('main');
  var tb=document.getElementById('topbar');
  if(window.innerWidth<=1023){
    var isOpen=sb.classList.toggle('open');
    ov.style.display=isOpen?'block':'none';
  } else {
    var isCollapsed=sb.classList.toggle('collapsed');
    m.classList.toggle('full',isCollapsed);
    tb.classList.toggle('full',isCollapsed);
  }
}
document.getElementById('overlay').addEventListener('click',function(){
  document.getElementById('sidebar').classList.remove('open');
  this.style.display='none';
});
document.querySelectorAll('.nav-item a').forEach(function(a){
  if(a.href===location.href) a.classList.add('active');
  a.addEventListener('click',function(){
    if(window.innerWidth<=1023){
      document.getElementById('sidebar').classList.remove('open');
      document.getElementById('overlay').style.display='none';
    }
  });
});
function openModal(id){document.getElementById(id).classList.add('open');}
function closeModal(id){document.getElementById(id).classList.remove('open');}
document.querySelectorAll('.modal').forEach(function(m){
  m.addEventListener('click',function(e){if(e.target===this)this.classList.remove('open');});
});
var fsIcon=document.getElementById('fsIcon');
var fsBtn=document.getElementById('fsBtn');
function toggleFullscreen(){
  var el=document.documentElement;
  var isFs=!!(document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement);
  if(!isFs){
    var req=el.requestFullscreen||el.webkitRequestFullscreen||el.mozRequestFullScreen;
    if(req) req.call(el);
  } else {
    var ex=document.exitFullscreen||document.webkitExitFullscreen||document.mozCancelFullScreen;
    if(ex) ex.call(document);
  }
}
function onFsChange(){
  var isFs=!!(document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement);
  if(fsIcon) fsIcon.className=isFs?'bi bi-fullscreen-exit':'bi bi-fullscreen';
  if(fsBtn) fsBtn.title=isFs?'Exit fullscreen (Esc)':'Toggle fullscreen (F11)';
  try{localStorage.setItem('edusmart_fs',isFs?'1':'0');}catch(e){}
  var b=document.getElementById('fsRestoreBanner');
  if(b) b.style.display='none';
}
document.addEventListener('fullscreenchange',onFsChange);
document.addEventListener('webkitfullscreenchange',onFsChange);
document.addEventListener('mozfullscreenchange',onFsChange);
document.addEventListener('keydown',function(e){
  if(e.key==='F11'){e.preventDefault();toggleFullscreen();}
});
function dismissFsRestore(){
  try{localStorage.setItem('edusmart_fs','0');}catch(e){}
  document.getElementById('fsRestoreBanner').style.display='none';
  document.removeEventListener('click',restoreFs);
  document.removeEventListener('keydown',restoreFs);
}
try{
  if(localStorage.getItem('edusmart_fs')==='1'){
    var banner=document.getElementById('fsRestoreBanner');
    if(banner) banner.style.display='flex';
    function restoreFs(e){
      if(e.target&&e.target.id==='fsRestoreDismiss') return;
      document.removeEventListener('click',restoreFs);
      document.removeEventListener('keydown',restoreFs);
      if(banner) banner.style.display='none';
      var el=document.documentElement;
      var req=el.requestFullscreen||el.webkitRequestFullscreen||el.mozRequestFullScreen;
      if(req) req.call(el);
    }
    document.addEventListener('click',restoreFs);
    document.addEventListener('keydown',restoreFs);
  }
}catch(e){}
</script>
<?php if(isset($extraScripts)) echo $extraScripts; ?>

<!-- ── Inactivity Timeout ─────────────────────────────── -->
<div id="inactivityModal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:99999;align-items:center;justify-content:center">
  <div style="background:#fff;border-radius:16px;padding:32px 28px;max-width:380px;width:90%;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,.3)">
    <div style="width:64px;height:64px;background:#fef3c7;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 16px;font-size:28px">⏱️</div>
    <h3 style="font-size:18px;font-weight:700;color:#1e293b;margin-bottom:8px">Session Expiring Soon</h3>
    <p style="color:#64748b;font-size:14px;margin-bottom:6px">You have been inactive. Your session will expire in:</p>
    <div id="inactivityCountdown" style="font-size:42px;font-weight:800;color:#f59e0b;margin:12px 0">60</div>
    <p style="color:#94a3b8;font-size:12px;margin-bottom:20px">seconds</p>
    <div style="display:flex;gap:10px;justify-content:center">
      <button onclick="renewSession()" style="background:#1a7f5a;color:#fff;border:none;padding:11px 24px;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer">Stay Logged In</button>
      <a href="<?= \Core\View::url('logout') ?>" style="background:#f1f5f9;color:#64748b;border:1px solid #e2e8f0;padding:11px 24px;border-radius:8px;font-size:14px;font-weight:600;text-decoration:none">Logout Now</a>
    </div>
  </div>
</div>

<!-- Session timed out popup (shown on login page after timeout) -->
<script>
(function(){
  var TIMEOUT    = 900;  // 15 min in seconds — must match server
  var WARN_AT    = 60;   // show warning 60s before expiry
  var pingUrl    = '<?= \Core\View::url('session/ping') ?>';
  var logoutUrl  = '<?= \Core\View::url('logout') ?>';
  var modal      = document.getElementById('inactivityModal');
  var countdown  = document.getElementById('inactivityCountdown');
  var remaining  = TIMEOUT;
  var warnShown  = false;
  var countTimer = null;

  // Ping server every 4 minutes if user is active
  var lastActivity = Date.now();
  ['mousemove','keydown','click','scroll','touchstart'].forEach(function(ev){
    document.addEventListener(ev, function(){ lastActivity = Date.now(); }, {passive:true});
  });

  // Heartbeat: ping every 60s, only if user was active in last 4 min
  setInterval(function(){
    var idleMs = Date.now() - lastActivity;
    if (idleMs < 240000) { // active in last 4 min
      fetch(pingUrl, {method:'POST', headers:{'X-CSRF-TOKEN':'<?= \Core\Session::csrf() ?>','Content-Type':'application/json'}})
        .then(function(r){ return r.json(); })
        .then(function(d){
          if (!d.ok) { forceLogout(); return; }
          remaining = d.remaining;
          if (remaining > WARN_AT && warnShown) hideWarning();
        })
        .catch(function(){});
    }
  }, 60000);

  // Countdown ticker every second
  setInterval(function(){
    var idleMs = Date.now() - lastActivity;
    if (idleMs >= (TIMEOUT - WARN_AT) * 1000) {
      remaining = Math.max(0, TIMEOUT - Math.floor(idleMs / 1000));
      if (remaining <= WARN_AT && !warnShown) showWarning();
      if (warnShown) {
        countdown.textContent = remaining;
        if (remaining <= 0) forceLogout();
      }
    } else {
      if (warnShown) hideWarning();
    }
  }, 1000);

  function showWarning(){
    warnShown = true;
    modal.style.display = 'flex';
    countdown.textContent = remaining;
  }
  function hideWarning(){
    warnShown = false;
    modal.style.display = 'none';
  }
  function forceLogout(){
    modal.style.display = 'none';
    window.location.href = logoutUrl + '?reason=timeout';
  }
  window.renewSession = function(){
    lastActivity = Date.now();
    fetch(pingUrl, {method:'POST', headers:{'X-CSRF-TOKEN':'<?= \Core\Session::csrf() ?>','Content-Type':'application/json'}})
      .then(function(r){ return r.json(); })
      .then(function(d){ if(d.ok){ remaining=d.remaining; hideWarning(); } else forceLogout(); })
      .catch(function(){ hideWarning(); });
  };
})();
</script>
</body>
</html>
