*{box-sizing:border-box;margin:0;padding:0}
html{scrollbar-color:rgba(0,229,255,0.28) #0b1015}
body{background:
  radial-gradient(circle at top left,rgba(0,229,255,0.08),transparent 28%),
  radial-gradient(circle at top right,rgba(0,255,157,0.06),transparent 24%),
  linear-gradient(180deg,var(--surface-0) 0%,var(--surface-0) 100%);
  color:var(--text-primary);font-family:'Segoe UI',sans-serif;min-height:100vh}
/* Login screen — single centered card with the animated banner INSIDE the
   card, above the form. Compact + self-contained. */
#login-screen{position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;background:var(--surface-0);z-index:100;transition:opacity 0.5s,transform 0.5s;overflow:hidden}
/* Animated background canvas — absolutely positioned so it never participates in flex layout */
#login-bg-canvas{position:absolute !important;top:0;left:0;width:100% !important;height:100% !important;pointer-events:none;z-index:0;opacity:0.55;flex-shrink:0}
/* Banner lives inside .login-box now. Bleed it to the card edges (negative
   margins absorb the box padding) so it can be visually impactful without
   breaking the card boundary. */
.login-box .login-banner{margin:-32px -28px 18px;padding:14px 14px 6px;text-align:center;border-radius:16px 16px 0 0;background:linear-gradient(180deg,rgba(0,229,255,0.05),transparent 80%);border-bottom:1px solid var(--border-1)}
.login-box .login-banner img{display:block;width:100%;max-width:340px;height:auto;max-height:96px;object-fit:contain;margin:0 auto;filter:drop-shadow(0 4px 14px rgba(0,229,255,0.18))}
#login-screen.hidden{opacity:0;transform:scale(1.04);pointer-events:none}
.login-box{background:var(--surface-1);border:1px solid var(--border-1);border-radius:16px;padding:32px 28px;width:100%;max-width:380px;position:relative;z-index:1;box-shadow:0 0 80px rgba(0,229,255,0.06);box-sizing:border-box}
@media(max-width:440px){.login-box{padding:24px 18px;border-radius:12px;max-width:100%}}
@media(max-width:440px){#login-screen{padding:16px}}
.login-box::before{content:'';position:absolute;top:0;left:24px;right:24px;height:1px;background:linear-gradient(90deg,transparent,#00e5ff,transparent)}
.brand{display:flex;align-items:center;gap:10px;margin-bottom:32px}
.brand-icon{width:36px;height:36px;background:var(--action);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:18px}
.brand-name{font-size:1.3rem;font-weight:700}.brand-name span{color:var(--action)}
.lbl{font-size:0.68rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.12em;margin-bottom:6px;display:block}
.inp{width:100%;background:var(--surface-2);border:1px solid var(--border-1);border-radius:8px;padding:11px 14px;color:var(--text-primary);font-size:16px;outline:none;transition:border-color 0.2s;margin-bottom:16px}
.inp:focus{border-color:var(--action)}
.login-btn{width:100%;background:var(--action);color:var(--surface-0);border:none;border-radius:8px;padding:13px;font-size:0.9rem;font-weight:700;cursor:pointer}
.login-btn:hover{background:#33eaff}
.login-err{font-size:0.75rem;text-align:center;margin-top:12px;display:none;padding:8px 12px;border-radius:8px;background:rgba(255,59,59,0.08);border:1px solid rgba(255,59,59,0.25);color:#ff6b6b;line-height:1.5}
.login-err.warn{background:rgba(255,157,0,0.08);border-color:rgba(255,157,0,0.3);color:var(--warn)}
.login-hint{font-size:0.68rem;color:var(--text-muted);text-align:center;margin-top:16px}
/* Forgot password link below the sign-in button */
.login-forgot{display:block;text-align:center;font-size:0.72rem;color:var(--text-muted);margin-top:10px;cursor:pointer;transition:color 0.2s}
.login-forgot:hover{color:var(--action);text-decoration:none}
/* Forgot password modal */
.forgot-modal{display:none;position:fixed;inset:0;z-index:200;align-items:center;justify-content:center;padding:24px;background:rgba(0,0,0,0.6);backdrop-filter:blur(6px)}
.forgot-modal.open{display:flex}
.forgot-card{background:var(--surface-1);border:1px solid var(--border-1);border-radius:16px;padding:32px 28px;width:100%;max-width:360px;position:relative;box-shadow:0 0 60px rgba(0,229,255,0.08)}
.forgot-card h3{font-size:1rem;font-weight:700;color:var(--text-primary);margin-bottom:6px}
.forgot-card p{font-size:0.78rem;color:var(--text-muted);margin-bottom:18px;line-height:1.5}
.forgot-card .inp{margin-bottom:12px}
.forgot-close{position:absolute;top:14px;right:16px;background:none;border:none;color:var(--text-muted);font-size:1.2rem;cursor:pointer;line-height:1;padding:4px}
.forgot-close:hover{color:var(--text-primary)}
.forgot-msg{font-size:0.75rem;text-align:center;margin-top:8px;display:none;padding:7px 10px;border-radius:7px}
#app{display:none;min-height:100vh;flex-direction:column}
#app.visible{display:flex}
.topnav{height:56px;background:var(--surface-1);border-bottom:1px solid var(--border-1);display:flex;align-items:center;padding:0 24px;gap:16px;position:sticky;top:0;z-index:50}
.hamburger-btn{display:none;background:transparent;border:1px solid var(--border-2);color:var(--text-primary);font-size:1.2rem;line-height:1;padding:6px 10px;border-radius:8px;cursor:pointer;min-width:40px;min-height:40px;align-items:center;justify-content:center}
.hamburger-btn:active{background:var(--border-1)}
.sidebar-backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.55);z-index:90;backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}
.sidebar-backdrop.open{display:block}
.nav-brand{font-size:1.1rem;font-weight:700;color:var(--action)}
.site-badge{font-size:0.65rem;background:rgba(0,229,255,0.1);color:var(--action);border:1px solid rgba(0,229,255,0.2);border-radius:4px;padding:2px 8px;text-transform:uppercase;letter-spacing:0.1em}
.admin-badge{font-size:0.65rem;background:rgba(255,107,53,0.1);color:#ff6b35;border:1px solid rgba(255,107,53,0.2);border-radius:4px;padding:2px 8px}
.nav-right{margin-left:auto;display:flex;align-items:center;gap:12px}
.pulse{width:7px;height:7px;background:var(--ok);border-radius:50%;animation:pulse 1.6s infinite}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(0,255,157,0.6)}50%{box-shadow:0 0 0 6px rgba(0,255,157,0)}}
.live-txt{font-size:0.7rem;color:var(--ok)}
.user-chip{display:flex;align-items:center;gap:8px;background:var(--surface-2);border:1px solid var(--border-1);border-radius:20px;padding:5px 12px 5px 8px;color:var(--text-primary)}
.avatar{width:26px;height:26px;background:linear-gradient(135deg,#00e5ff,#00ff9d);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:0.65rem;font-weight:700;color:var(--surface-0)}
.logout-btn{background:none;border:1px solid var(--border-1);border-radius:6px;color:var(--text-muted);padding:5px 10px;font-size:0.72rem;cursor:pointer;transition:all 0.2s}
.logout-btn:hover{color:#ff3b3b;border-color:#ff3b3b}
.main{display:flex;flex:1;min-height:0}
.sidebar{width:230px;background:linear-gradient(180deg,rgba(14,19,24,0.98),rgba(10,14,18,0.96));border-right:1px solid var(--border-1);padding:14px 10px 18px;display:flex;flex-direction:column;gap:2px;flex-shrink:0;position:sticky;top:56px;height:calc(100vh - 56px);min-height:0;overflow-y:auto;scrollbar-width:thin}
/* Sidebar children must not shrink — keep their natural height so the
   parent's overflow:auto actually engages instead of cramming items. */
.sidebar > *{flex-shrink:0}
/* Sticky search bar inside the sidebar — kept on desktop where the
   sidebar is itself sticky, but switched to static on mobile so it doesn't
   trap touch events near the top of the drawer. */
.sidebar-tools{position:sticky;top:0;z-index:2;padding:4px 4px 10px;background:linear-gradient(180deg,rgba(14,19,24,0.98),rgba(14,19,24,0.88) 78%,rgba(14,19,24,0))}
@media (max-width:768px){
  .sidebar-tools{position:static!important;background:transparent!important}
}
.nav-filter-inp{width:100%;background:var(--surface-2);border:1px solid var(--border-1);border-radius:10px;padding:10px 12px;color:var(--text-primary);font-size:0.78rem;outline:none;transition:border-color 0.18s,box-shadow 0.18s}
.nav-filter-inp::placeholder{color:#7e8a96}
.nav-filter-inp:focus{border-color:rgba(0,229,255,0.45);box-shadow:0 0 0 3px rgba(0,229,255,0.12)}
.nav-section{font-size:0.6rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.12em;padding:10px 12px 4px;margin-top:6px;transition:opacity 0.18s ease}
.nav-item{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:10px;cursor:pointer;font-size:0.8rem;font-weight:500;color:var(--text-primary);transition:all 0.15s;border:1px solid transparent}
.nav-item:hover{background:var(--surface-2);color:#ffffff}
.nav-item.active{background:rgba(0,229,255,0.08);color:var(--action);border-color:rgba(0,229,255,0.15)}
.nav-item.hidden-by-filter,.nav-section.hidden-by-filter{display:none !important}
#live-tl-overlay,#tl-only-overlay,#tl-timestamp-overlay{display:none !important}
body.is-client .admin-only{display:none !important}
body.is-client .client-hide{display:none !important}
body.is-client #live-archive-source,
body.is-client #archive-source,
body.is-client #tl-source-group{display:none !important}
/* Admin-only nav items: never show to clients no matter what the Layout
   Editor does. Class stays on the element itself so reparenting via
   applyLayoutSection doesn't matter. */
body:not(.is-admin) .admin-item{display:none !important}
/* Admin-only nav items get a subtle orange edge so it's obvious which
   surfaces are operator-only vs client-visible. Sprint 2.2. */
body.is-admin .nav-item.admin-item{border-left:2px solid rgba(255,107,53,0.22);padding-left:10px}
body.is-admin .nav-item.admin-item:hover{border-left-color:rgba(255,107,53,0.55)}
body.is-admin .nav-item.admin-item.active{border-left-color:#ff6b35}
/* Section kicker support — rendered by showNavSectionHeaders() from
   data-section attributes. Sprint 2.3. */
.nav-section-kicker{font-size:10px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.1em;padding:10px 12px 4px;pointer-events:none}
body.is-client .client-help{display:block !important}
body.is-admin .client-help{display:none !important}
/* Permission-based CSS gates for button-level controls. The per-nav gates
   are generated dynamically from FEATURE_CATALOG at boot — see the
   injectFeatureNavGates() IIFE. Hand-maintaining a second list here is
   what caused the original drift bug, so don't add nav rules here. */
body.no-perm-canControlPTZ        #btn-ptz,
body.no-perm-canControlPTZ        #btn-presets,
body.no-perm-canControlPTZ        #btn-panorama { display:none !important }
.nav-item.admin-item.active{background:rgba(255,107,53,0.08);color:#ff6b35;border-color:rgba(255,107,53,0.15)}
.content{flex:1;padding:24px 24px 32px;overflow-y:auto;overflow-x:hidden}
.content-shell{max-width:1320px;margin:0 auto}
.page-header{
  display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap;
  margin-bottom:18px;padding:18px 20px;border-radius:16px;
  background:linear-gradient(135deg,rgba(0,229,255,0.12),rgba(0,229,255,0.04) 45%,rgba(255,255,255,0.02));
  border:1px solid var(--border-1);
  box-shadow:0 16px 30px rgba(0,0,0,0.18)
}
.page-header-copy{min-width:0}
.page-kicker{font-size:0.64rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.14em;margin-bottom:6px}
.page-title{font-size:1.35rem;font-weight:700;color:var(--text-primary);line-height:1.1}
.page-subtitle{font-size:0.78rem;color:var(--text-secondary);margin-top:6px;max-width:760px;line-height:1.5}
.page-chip{
  display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border-radius:999px;
  background:var(--surface-2);border:1px solid var(--border-1);font-size:0.7rem;color:var(--text-secondary)
}
.page-chip-dot{width:8px;height:8px;border-radius:50%;background:var(--action);box-shadow:0 0 0 4px rgba(0,229,255,0.14)}
.page{display:none;opacity:0;transform:translateY(10px)}
.page.active{display:block;opacity:1;transform:none;animation:pageFadeIn 0.22s ease}/* page-stacking-context-marker (2026-05-19): transform:none avoids creating a stacking context that trapped modal z-index below the topnav */
@keyframes pageFadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:20px}
.stat{background:var(--surface-1);border:1px solid var(--border-1);border-radius:10px;padding:14px;position:relative;overflow:hidden}
.stat::after{content:'';position:absolute;bottom:0;left:0;right:0;height:2px}
.stat.s1::after{background:var(--ok)}.stat.s2::after{background:#ff3b3b}.stat.s3::after{background:#ff6b35}.stat.s4::after{background:var(--action)}
.stat-lbl{font-size:0.62rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:4px}
.stat-val{font-size:1rem;font-weight:700;margin-top:4px}.stat-sub{font-size:0.65rem;color:var(--text-muted);margin-top:2px}
.cam-card{background:var(--surface-1);border:1px solid var(--border-1);border-radius:12px;overflow:hidden;max-width:960px}
.cam-header{padding:12px 16px;display:flex;align-items:center;gap:10px;border-bottom:1px solid var(--border-1)}
.cam-title{font-size:0.88rem;font-weight:600}.cam-sub{font-size:0.65rem;color:var(--text-muted);margin-top:2px}
.rec-badge{background:rgba(255,59,59,0.15);color:#ff3b3b;border:1px solid rgba(255,59,59,0.3);border-radius:4px;padding:2px 8px;font-size:0.62rem;display:flex;align-items:center;gap:4px;margin-left:auto}
.rec-dot{width:5px;height:5px;background:#ff3b3b;border-radius:50%;animation:pulse 1s infinite}
/* ── Dynamic stream-state badge (replaces the always-on REC) ─────── */
.state-badge{display:flex;align-items:center;gap:5px;padding:3px 9px;border-radius:5px;font-size:0.62rem;font-weight:700;letter-spacing:0.04em;font-family:var(--font-mono,ui-monospace,monospace);text-transform:uppercase;margin-left:auto;white-space:nowrap;border:1px solid transparent;transition:background 0.18s,color 0.18s,border-color 0.18s}
.state-badge .state-dot{width:6px;height:6px;border-radius:50%}
/* Connecting — yellow pulse */
.state-badge[data-state="connecting"]{background:rgba(255,200,0,0.10);color:#ffd066;border-color:rgba(255,200,0,0.35)}
.state-badge[data-state="connecting"] .state-dot{background:#ffd066;animation:pulse 1s infinite}
/* Live + recording — red pulse */
.state-badge[data-state="live-rec"]{background:rgba(255,59,59,0.13);color:#ff3b3b;border-color:rgba(255,59,59,0.35)}
.state-badge[data-state="live-rec"] .state-dot{background:#ff3b3b;animation:pulse 1s infinite;box-shadow:0 0 0 0 rgba(255,59,59,0.6)}
/* Live (no recording) — green pulse */
.state-badge[data-state="live"]{background:rgba(0,255,157,0.10);color:#00ff9d;border-color:rgba(0,255,157,0.35)}
.state-badge[data-state="live"] .state-dot{background:#00ff9d;animation:pulse 1.2s infinite}
/* Offline — solid red, no pulse */
.state-badge[data-state="offline"]{background:rgba(120,120,120,0.10);color:#9aa4b2;border-color:rgba(120,120,120,0.4)}
.state-badge[data-state="offline"] .state-dot{background:#6b7280;animation:none}
/* Paused — amber, no pulse */
.state-badge[data-state="paused"]{background:rgba(255,200,0,0.08);color:#ffd066;border-color:rgba(255,200,0,0.35)}
.state-badge[data-state="paused"] .state-dot{background:#ffd066;animation:none}
video{width:100%;aspect-ratio:16/9;background:var(--surface-0);display:block}
.cam-footer{padding:10px 16px;display:flex;gap:6px;flex-wrap:wrap;align-items:center;border-top:1px solid var(--border-1)}
/* ── Player toolbar polish (the bar under the live video) ──────────
   Constrain button height, group spacing, divider styling so the toolbar
   doesn't look like loose buttons floating around. */
#player-bar{padding:8px 12px;gap:6px;background:linear-gradient(180deg,var(--surface-1) 0%,var(--surface-0) 100%)}
#player-bar [role="group"]{display:inline-flex;gap:4px;align-items:center;flex-wrap:nowrap;padding:0 2px}
#player-bar .btn{padding:6px 11px;font-size:0.72rem;line-height:1.2;height:30px;display:inline-flex;align-items:center;gap:5px}
#player-bar select,#player-bar input[type="time"],#player-bar input[type="date"]{height:30px;padding:0 8px;font-size:0.72rem;line-height:30px}
#player-bar .btn .icon{font-size:0.95em;flex-shrink:0}
/* Inline group dividers — subtle vertical lines between role="group" sections */
#player-bar > [role="group"] + [role="group"]::before,
#player-bar > [role="group"] + #btn-player-more::before{
  content:"";display:inline-block;width:1px;height:18px;background:var(--border-1);margin:0 4px 0 -2px;align-self:center}
/* "More" overflow toggle — give it a clear hit target + active state */
#btn-player-more{padding:6px 9px;width:34px;justify-content:center;color:var(--text-muted)}
#btn-player-more:hover{color:var(--action)}
#btn-player-more.active{background:rgba(0,229,255,0.10);border-color:rgba(0,229,255,0.30);color:var(--action)}
/* Latency chip — make it look intentionally "info" (not a button) */
#live-latency{height:30px;display:inline-flex;align-items:center;font-variant-numeric:tabular-nums;letter-spacing:.02em}
/* Right-side flex spacer that pushes archive/mode to the far right */
#player-bar > [style*="flex:1"]{min-width:8px}
/* Mobile / narrow: reduce padding so the toolbar doesn't wrap into 4 rows */
@media (max-width:720px){
  #player-bar{padding:6px 8px;gap:4px}
  #player-bar .btn{padding:6px 9px;font-size:0.68rem}
  #player-bar > [role="group"] + [role="group"]::before{display:none}
}
.btn{background:var(--surface-2);border:1px solid var(--border-2);color:var(--text-primary);padding:7px 14px;border-radius:6px;font-size:0.72rem;cursor:pointer;transition:all 0.15s;white-space:nowrap}
.btn:hover:not(:disabled){border-color:rgba(0,229,255,0.4);color:var(--action);background:rgba(0,229,255,0.05)}
.btn:disabled{opacity:0.5;cursor:not-allowed}
.btn:focus-visible{outline:2px solid rgba(0,229,255,0.5);outline-offset:2px}
.btn.active{background:rgba(0,229,255,0.08);border-color:rgba(0,229,255,0.2);color:var(--action)}
.btn-green{background:rgba(0,255,157,0.1);border-color:rgba(0,255,157,0.3);color:var(--ok)}
.btn-green:hover{background:rgba(0,255,157,0.2)}
.btn-red{background:rgba(255,59,59,0.1);border-color:rgba(255,59,59,0.3);color:#ff3b3b}
.btn-red:hover{background:rgba(255,59,59,0.2)}
.btn-orange{background:rgba(255,107,53,0.1);border-color:rgba(255,107,53,0.3);color:#ff6b35}
.stream-status{font-size:0.68rem;font-family:monospace;margin-left:auto}
.stream-status.ok{color:var(--ok)}.stream-status.err{color:#ff3b3b}.stream-status.connecting{color:#ff6b35}
.panel{display:none;padding:16px;border-top:1px solid var(--border-1);background:var(--surface-0)}
.panel.open{display:block}
.panel-title{font-size:0.65rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:12px;font-family:monospace}
.ptz-grid{display:grid;grid-template-columns:repeat(3,50px);gap:6px;margin-bottom:12px}
.ptz-key{background:var(--surface-2);border:1px solid var(--border-2);color:var(--text-primary);width:50px;height:50px;border-radius:8px;font-size:1.1rem;cursor:pointer;transition:all 0.15s;display:flex;align-items:center;justify-content:center;user-select:none}
.ptz-key:hover{background:rgba(0,229,255,0.1);border-color:rgba(0,229,255,0.3);color:var(--action)}
.ptz-key:active{transform:scale(0.9)}
.zoom-row{display:flex;gap:6px;align-items:center}
.zoom-lbl{font-size:0.65rem;color:var(--text-muted);width:44px;text-transform:uppercase}
.preset-grid{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:14px;min-height:36px}
.preset-btn{background:var(--surface-2);border:1px solid var(--border-2);color:var(--text-primary);padding:6px 14px;border-radius:6px;font-size:0.75rem;cursor:pointer;transition:all 0.15s;display:flex;align-items:center;gap:6px}
.preset-btn:hover{background:rgba(0,229,255,0.1);border-color:rgba(0,229,255,0.3);color:var(--action)}
.preset-btn.active{background:rgba(0,229,255,0.15);border-color:var(--action);color:var(--action)}
.preset-num{font-size:0.6rem;color:var(--text-muted);font-family:monospace}
.preset-save-row{display:flex;gap:8px;margin-top:4px;padding-top:12px;border-top:1px solid var(--border-1)}
.preset-inp{background:var(--surface-2);border:1px solid var(--border-2);color:var(--text-primary);padding:7px 12px;border-radius:6px;font-size:0.75rem;outline:none;flex:1;transition:border-color 0.2s}
.preset-inp:focus{border-color:var(--action)}
.preset-save-btn{background:rgba(0,255,157,0.1);border:1px solid rgba(0,255,157,0.3);color:var(--ok);padding:7px 14px;border-radius:6px;font-size:0.72rem;cursor:pointer;white-space:nowrap}
.preset-loading{font-size:0.72rem;color:var(--text-muted);font-family:monospace;padding:6px 0}

.rec-grid{display:flex;flex-direction:column;gap:8px;max-width:960px}
.rec-item{background:var(--surface-1);border:1px solid var(--border-1);border-radius:10px;padding:14px 16px;display:flex;align-items:center;gap:14px;cursor:pointer;transition:all 0.15s}
/* Smart-thumbnail slot — holds either the emoji fallback or an <img> picked
   by the server from detection snapshots. Fixed aspect so row heights stay
   stable regardless of image load timing. */
.rec-thumb-slot{position:relative;width:64px;height:40px;border-radius:6px;background:var(--surface-0);overflow:hidden;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.rec-thumb-slot .rec-thumb-img{width:100%;height:100%;object-fit:cover;display:block;animation:rec-thumb-fade 0.3s ease-out}
@keyframes rec-thumb-fade{from{opacity:0}to{opacity:1}}
.rec-thumb-slot .rec-thumb-badge{position:absolute;bottom:2px;right:2px;background:rgba(0,0,0,0.72);color:#fff;font-size:0.6rem;line-height:1;padding:2px 4px;border-radius:4px;pointer-events:none}
.rec-item:hover{border-color:rgba(0,229,255,0.3);background:var(--surface-2)}
.rec-item.playing{border-color:var(--action);background:rgba(0,229,255,0.05)}
.rec-icon{width:40px;height:40px;background:var(--surface-2);border:1px solid var(--border-1);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0}
.rec-info{flex:1}
.rec-name{font-size:0.82rem;font-weight:600;margin-bottom:3px}
.rec-meta{display:flex;gap:12px;font-size:0.68rem;color:var(--text-muted)}
.rec-actions{display:flex;gap:6px}
.rec-play-btn{background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.2);color:var(--action);padding:6px 14px;border-radius:6px;font-size:0.72rem;cursor:pointer;transition:all 0.15s;white-space:nowrap}
.rec-play-btn:hover{background:rgba(0,229,255,0.2)}
.rec-play-btn.active{background:rgba(0,229,255,0.2)}
.rec-dl-btn{background:var(--surface-2);border:1px solid var(--border-1);color:var(--text-muted);padding:6px 10px;border-radius:6px;font-size:0.72rem;cursor:pointer;transition:all 0.15s}
.rec-dl-btn:hover{color:var(--ok);border-color:rgba(0,255,157,0.3)}
.rec-player-card{background:var(--surface-1);border:1px solid rgba(0,229,255,0.2);border-radius:12px;overflow:hidden;margin-bottom:16px;max-width:960px;display:none}
.rec-player-card.open{display:block}
.rec-player-header{padding:10px 16px;display:flex;align-items:center;gap:10px;border-bottom:1px solid var(--border-1)}
.rec-player-title{font-size:0.82rem;font-weight:600;color:var(--action)}
.rec-player-sub{font-size:0.65rem;color:var(--text-muted)}
.rec-filter-row{display:flex;gap:8px;margin-bottom:14px;max-width:960px;flex-wrap:wrap}
.rec-filter-btn{background:var(--surface-2);border:1px solid var(--border-1);color:var(--text-muted);padding:6px 14px;border-radius:6px;font-size:0.72rem;cursor:pointer;transition:all 0.15s}
.rec-filter-btn:hover{color:var(--text-primary);background:var(--surface-3)}
.rec-filter-btn.active{background:rgba(0,229,255,0.08);border-color:rgba(0,229,255,0.2);color:var(--action)}
.rec-stats{display:flex;gap:16px;margin-bottom:14px;max-width:960px}
.rec-stat{font-size:0.72rem;color:var(--text-muted)}
.rec-stat strong{color:var(--text-primary)}
.rec-empty{text-align:center;padding:48px;color:var(--text-muted);font-size:0.82rem}
.rec-empty-icon{font-size:2rem;margin-bottom:8px;opacity:0.4}

/* ═══ Command Palette (Cmd+K / Ctrl+K) ═══ */
.cmdk-backdrop{
  position:fixed;inset:0;background:rgba(5,9,14,0.72);z-index:9999;
  backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  display:none;align-items:flex-start;justify-content:center;padding-top:12vh;
  animation:cmdk-fade .12s ease-out;
}
.cmdk-backdrop.open{display:flex}
@keyframes cmdk-fade{from{opacity:0}to{opacity:1}}
@keyframes cmdk-slide{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}
.cmdk-modal{
  width:640px;max-width:92vw;background:var(--surface-1);border:1px solid rgba(0,229,255,0.2);
  border-radius:14px;box-shadow:0 20px 60px rgba(0,0,0,0.7),0 0 0 1px rgba(0,229,255,0.08);
  overflow:hidden;animation:cmdk-slide .15s ease-out;
  display:flex;flex-direction:column;max-height:70vh;
}
.cmdk-input-row{
  display:flex;align-items:center;gap:10px;padding:12px 16px;
  border-bottom:1px solid var(--border-1);
}
.cmdk-input-row .cmdk-icon{color:var(--action);font-size:1.1rem;flex-shrink:0}
.cmdk-input{
  flex:1;background:none;border:none;outline:none;color:var(--text-primary);
  font-size:0.95rem;font-family:'DM Sans',system-ui,sans-serif;font-weight:500;
}
.cmdk-input::placeholder{color:var(--text-muted)}
.cmdk-kbd{
  font-family:'JetBrains Mono',ui-monospace,monospace;font-size:0.62rem;
  color:#7a90b0;background:var(--border-1);border:1px solid var(--border-2);
  border-radius:4px;padding:2px 6px;
}
.cmdk-results{
  overflow-y:auto;padding:6px;
}
.cmdk-results::-webkit-scrollbar{width:6px}
.cmdk-group{padding:4px 0}
.cmdk-group-label{
  font-size:0.58rem;text-transform:uppercase;letter-spacing:0.1em;
  color:var(--text-muted);padding:6px 12px 4px;font-weight:600;
}
.cmdk-item{
  display:flex;align-items:center;gap:10px;padding:8px 12px;border-radius:7px;
  cursor:pointer;font-size:0.82rem;color:var(--text-secondary);transition:background .08s;
  border:1px solid transparent;
}
.cmdk-item:hover,.cmdk-item.selected{
  background:rgba(0,229,255,0.08);color:var(--text-primary);
  border-color:rgba(0,229,255,0.18);
}
.cmdk-item-icon{
  width:22px;height:22px;display:flex;align-items:center;justify-content:center;
  font-size:1rem;flex-shrink:0;
}
.cmdk-item-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.cmdk-item-title{
  font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.cmdk-item-hint{
  font-size:0.65rem;color:var(--text-muted);font-family:'JetBrains Mono',ui-monospace,monospace;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.cmdk-item-badge{
  font-size:0.58rem;padding:2px 6px;border-radius:4px;
  background:var(--border-1);color:#7a90b0;
  font-family:'JetBrains Mono',monospace;text-transform:uppercase;letter-spacing:0.04em;
}
.cmdk-item-badge.admin{background:rgba(255,209,102,0.1);color:#ffd166}
.cmdk-item-arrow{color:var(--text-muted);font-size:0.7rem;opacity:0;transition:opacity .1s}
.cmdk-item:hover .cmdk-item-arrow,.cmdk-item.selected .cmdk-item-arrow{opacity:1;color:var(--action)}
.cmdk-empty{
  text-align:center;padding:28px 16px;color:var(--text-muted);font-size:0.78rem;
}
.cmdk-footer{
  display:flex;align-items:center;gap:14px;padding:8px 14px;
  border-top:1px solid var(--border-1);background:rgba(255,255,255,0.01);
  font-size:0.62rem;color:var(--text-muted);
}
.cmdk-footer .sep{color:#2a3344}

/* Hint in topbar */
.cmdk-trigger{
  display:inline-flex;align-items:center;gap:6px;padding:5px 10px;
  background:var(--border-1);border:1px solid var(--border-1);
  border-radius:7px;font-size:0.72rem;color:var(--text-muted);cursor:pointer;
  transition:all .12s;margin-left:8px;
}
.cmdk-trigger:hover{background:rgba(0,229,255,0.06);border-color:rgba(0,229,255,0.25);color:var(--text-primary)}
@media (max-width:768px){.cmdk-trigger{display:none}}

/* ═══ Empty State Component (April 2026) ═══ */
.empty-state{
  text-align:center;padding:40px 24px;max-width:420px;margin:0 auto;
  display:flex;flex-direction:column;align-items:center;gap:8px;
}
.empty-state-icon{
  font-size:3rem;line-height:1;margin-bottom:6px;
  filter:drop-shadow(0 2px 8px rgba(0,229,255,0.12));
  animation:empty-float 3s ease-in-out infinite;
}
@keyframes empty-float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
.empty-state-title{
  font-size:0.95rem;font-weight:600;color:var(--text-primary);letter-spacing:-0.01em;
}
.empty-state-desc{
  font-size:0.78rem;color:var(--text-muted);line-height:1.6;max-width:360px;
}
.empty-state-desc strong{color:var(--text-secondary);font-weight:600}
.empty-state-hint{
  margin-top:4px;font-size:0.68rem;color:var(--text-muted);font-family:ui-monospace,Menlo,Consolas,monospace;
  padding:4px 10px;background:var(--border-1);border:1px solid var(--border-1);
  border-radius:999px;
}
.empty-state-cta{
  margin-top:8px;display:inline-flex;align-items:center;gap:6px;
  padding:8px 16px;font-size:0.78rem;font-weight:600;
  background:rgba(0,229,255,0.1);border:1px solid rgba(0,229,255,0.3);
  color:var(--action);border-radius:8px;cursor:pointer;
  transition:all .15s;text-decoration:none;
}
.empty-state-cta:hover{background:rgba(0,229,255,0.18);transform:translateY(-1px)}
.empty-state-cta.secondary{
  background:var(--border-1);border-color:var(--border-2);color:var(--text-secondary);
}
.empty-state-cta.secondary:hover{background:var(--border-1)}
.empty-state-actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin-top:4px}
/* Flash highlight for elements that an empty-state CTA wants to draw attention to. */
.pulse-highlight{animation:cs-pulse-highlight 0.6s ease-in-out 3;box-shadow:0 0 0 0 rgba(0,229,255,0.55)}
@keyframes cs-pulse-highlight{
  0%,100%{box-shadow:0 0 0 0 rgba(0,229,255,0.0)}
  50%{box-shadow:0 0 0 8px rgba(0,229,255,0.35)}
}
/* Compact variant (for inline/sidebar empty states) */
.empty-state.compact{padding:20px 14px;gap:4px}
.empty-state.compact .empty-state-icon{font-size:1.6rem;animation:none}
.empty-state.compact .empty-state-title{font-size:0.82rem}
.empty-state.compact .empty-state-desc{font-size:0.7rem}

/* ═══ Toast System (April 2026) — replaces alert() ═══ */
.toast-stack{position:fixed;bottom:20px;right:20px;z-index:10000;display:flex;flex-direction:column-reverse;gap:10px;pointer-events:none;max-width:calc(100vw - 40px)}
.toast{pointer-events:auto;min-width:280px;max-width:420px;padding:12px 16px 12px 14px;border-radius:10px;background:rgba(14,19,24,0.97);backdrop-filter:blur(12px);border:1px solid var(--border-1);box-shadow:0 12px 32px rgba(0,0,0,0.4),0 0 0 1px var(--border-1);color:var(--text-primary);font-size:0.82rem;line-height:1.45;display:flex;align-items:flex-start;gap:10px;animation:toast-in .22s cubic-bezier(.2,.9,.3,1.2) both;position:relative;overflow:hidden}
.toast.dismissing{animation:toast-out .2s ease-in forwards}
.toast-icon{font-size:1.1rem;line-height:1.2;flex-shrink:0;margin-top:1px}
.toast-body{flex:1;min-width:0;word-wrap:break-word}
.toast-title{font-weight:600;color:var(--text-primary);margin-bottom:2px;font-size:0.85rem}
.toast-close{background:transparent;border:0;color:var(--text-muted);cursor:pointer;font-size:1rem;line-height:1;padding:2px 4px;margin:-2px -4px 0 0;border-radius:4px;flex-shrink:0}
.toast-close:hover{background:var(--border-1);color:var(--text-primary)}
.toast::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--tc,#00e5ff)}
.toast.success{--tc:var(--ok)}
.toast.success .toast-title{color:var(--ok)}
.toast.error{--tc:#ff3b3b}
.toast.error .toast-title{color:#ff6b6b}
.toast.warn{--tc:var(--warn)}
.toast.warn .toast-title{color:#ffb84d}
.toast.info{--tc:var(--action)}
@keyframes toast-in{from{opacity:0;transform:translateX(24px) scale(.96)}to{opacity:1;transform:translateX(0) scale(1)}}
@keyframes toast-out{to{opacity:0;transform:translateX(20px)}}
@media (max-width:560px){.toast-stack{left:12px;right:12px;bottom:12px;max-width:none}.toast{min-width:0;max-width:none}}

/* ═══ Button loading state (spinner + disabled) ═══ */
.btn-loading{position:relative;pointer-events:none;opacity:.75;cursor:wait}
.btn-loading>*{visibility:hidden}
.btn-loading::after{content:'';position:absolute;inset:0;margin:auto;width:14px;height:14px;border:2px solid rgba(255,255,255,0.22);border-top-color:currentColor;border-radius:50%;animation:btn-spin .7s linear infinite;visibility:visible}
@keyframes btn-spin{to{transform:rotate(360deg)}}

.admin-section{background:var(--surface-1);border:1px solid var(--border-1);border-radius:12px;overflow:hidden;margin-bottom:20px;max-width:960px}
.admin-section-header{padding:14px 20px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--border-1)}
.admin-section-title{font-size:0.85rem;font-weight:600}
.table{width:100%;border-collapse:collapse}
.table th{padding:10px 16px;font-size:0.62rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.08em;text-align:left;background:var(--surface-2);border-bottom:1px solid var(--border-1)}
.table td{padding:12px 16px;font-size:0.78rem;border-bottom:1px solid var(--border-1)}
.table tr:last-child td{border:none}
.table tr:hover td{background:rgba(255,255,255,0.02)}
.badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:0.62rem;font-family:monospace}
.badge-green{background:rgba(0,255,157,0.1);color:var(--ok);border:1px solid rgba(0,255,157,0.2)}
.badge-orange{background:rgba(255,107,53,0.1);color:#ff6b35;border:1px solid rgba(255,107,53,0.2)}
.badge-blue{background:rgba(0,229,255,0.1);color:var(--action);border:1px solid rgba(0,229,255,0.2)}
.badge-purple{background:rgba(150,100,255,0.1);color:#a064ff;border:1px solid rgba(150,100,255,0.2)}
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:200;display:none;align-items:center;justify-content:center;opacity:0;transition:opacity 0.18s ease}
.modal-overlay.open,.modal-overlay.show{display:flex}
.modal-overlay.show{opacity:1}
.modal{background:var(--surface-1);border:1px solid var(--border-2);border-radius:16px;padding:32px;width:100%;max-width:480px;position:relative;max-height:90vh;overflow-y:auto;transform:translateY(16px) scale(0.985);opacity:0;transition:transform 0.2s ease,opacity 0.2s ease}
.modal-overlay.show .modal{transform:translateY(0) scale(1);opacity:1}
.modal-title{font-size:1rem;font-weight:700;margin-bottom:20px;color:var(--action)}
.modal-row{margin-bottom:14px}
.modal-lbl{font-size:0.65rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.1em;margin-bottom:5px;display:block}
.modal-inp{width:100%;background:var(--surface-2);border:1px solid var(--border-2);border-radius:8px;padding:9px 12px;color:var(--text-primary);font-size:0.85rem;outline:none;transition:border-color 0.2s,box-shadow 0.2s}
.modal-inp:focus{border-color:rgba(0,229,255,0.5);box-shadow:0 0 0 3px rgba(0,229,255,0.12)}
.modal-inp:hover:not(:focus){border-color:rgba(255,255,255,0.18)}
.modal-inp:focus{border-color:var(--action)}
.modal-footer{display:flex;gap:8px;justify-content:flex-end;margin-top:20px}
.modal-close{position:absolute;top:16px;right:16px;background:none;border:none;color:var(--text-muted);font-size:1.2rem;cursor:pointer}
.modal-close:hover{color:#ff3b3b}
.assign-grid{display:flex;flex-direction:column;gap:6px;max-height:180px;overflow-y:auto;padding:4px}
.assign-item{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--surface-2);border:1px solid var(--border-1);border-radius:6px;font-size:0.78rem;cursor:pointer}
.assign-item input{accent-color:var(--action)}
.msg{font-size:0.72rem;padding:8px 12px;border-radius:6px;margin-top:10px;display:none}
.msg.ok{background:rgba(0,255,157,0.1);color:var(--ok);border:1px solid rgba(0,255,157,0.2)}
.msg.err{background:rgba(255,59,59,0.1);color:#ff3b3b;border:1px solid rgba(255,59,59,0.2)}
.site-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px;margin-bottom:20px;max-width:960px}
.site-card{background:var(--surface-1);border:1px solid var(--border-1);border-radius:12px;padding:16px;position:relative;overflow:hidden}
.site-card::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#00e5ff,#00ff9d)}
.site-card-name{font-size:0.9rem;font-weight:600;margin-bottom:4px}
.site-card-loc{font-size:0.7rem;color:var(--text-muted);margin-bottom:12px}
.site-card-stats{display:flex;gap:12px;margin-bottom:12px}
.site-stat{font-size:0.68rem;color:var(--text-muted)}
.site-stat strong{color:var(--text-primary);display:block;font-size:1rem;font-weight:700}
.site-card-footer{display:flex;gap:6px}

/* ── MOBILE RESPONSIVE ── */
/* Fullscreen player wrapper */
#player-wrap:fullscreen, #player-wrap:-webkit-full-screen {
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
}
#player-wrap:fullscreen video, #player-wrap:-webkit-full-screen video {
  max-height: 100vh !important;
  width: 100% !important;
  height: 100% !important;
  object-fit: contain;
}
#fs-exit-btn { transition: opacity 0.3s; }

/* ── Mobile Bottom Navigation (fixed) ──
   Visible only on narrow viewports. Four primary destinations + More drawer.
   The existing slide-in sidebar remains the "More" drawer so there is one
   source of truth for the full nav. */
.mobile-bottom-nav { display: none; }
@media (max-width: 768px) {
  .mobile-bottom-nav {
    display: flex;
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 95; /* below sidebar (100) and backdrop, above content */
    background: rgba(8,12,16,0.92);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-top: 1px solid rgba(0,229,255,0.18);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom));
    justify-content: space-around;
    align-items: stretch;
    gap: 2px;
  }
  .mobile-bottom-nav button {
    flex: 1 1 0;
    min-width: 0;
    background: transparent;
    border: none;
    color: var(--text-muted);
    font: inherit;
    font-size: 0.6rem;
    font-weight: 600;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 6px 2px 4px;
    border-radius: 10px;
    cursor: pointer;
    position: relative;
    min-height: 52px;
    transition: color 0.15s, background 0.15s;
  }
  .mobile-bottom-nav button .mbn-ico { font-size: 1.15rem; line-height: 1; }
  .mobile-bottom-nav button .mbn-lbl { letter-spacing: 0.04em; text-transform: uppercase; }
  .mobile-bottom-nav button.active { color:var(--action); background: rgba(0,229,255,0.08); }
  .mobile-bottom-nav button:active { background: rgba(0,229,255,0.15); }
  .mobile-bottom-nav .mbn-badge {
    position: absolute; top: 4px; right: calc(50% - 20px);
    background: #ff3b3b; color: #fff;
    font-size: 0.55rem; font-weight: 700;
    min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 8px;
    display: none; align-items: center; justify-content: center;
    box-shadow: 0 0 8px rgba(255,59,59,0.6);
  }
  .mobile-bottom-nav .mbn-badge.visible { display: flex; }

  /* Give the content some breathing room so nothing hides under the bar. */
  body.has-mobile-bottom-nav .content { padding-bottom: calc(72px + env(safe-area-inset-bottom)); }
  /* Top hamburger stays visible on mobile — it's the primary way to open
     the full sidebar (the bottom nav only shows the 4 most-common pages).
     Without this, Android users couldn't reach Manage Cameras / Sites /
     Player Profiles from a phone. */
  body.has-mobile-bottom-nav .hamburger-btn { display: inline-flex !important; }
  /* The floating notification bell duplicates the bottom-nav Alerts button on
     mobile and visually overlaps "More" — hide it. The bottom bar badge keeps
     surfacing the same unread count. */
  body.has-mobile-bottom-nav #notif-bell { display: none !important; }
  /* Shift the notif panel up so it doesn't hide under the bottom bar if ever
     opened (e.g. via cmdk on desktop-like viewports). */
  body.has-mobile-bottom-nav #notif-panel { bottom: calc(88px + env(safe-area-inset-bottom)) !important; }
}

@media (max-width: 768px) {

  /* Top nav — compact, hamburger visible. Hide non-essential items so
     core controls (☰, brand, ADMIN, theme, logout) fit on one row even
     on narrow phones. Health stats + site filter move to inside the
     drawer / dashboard pages. */
  .topnav {
    height: auto;
    min-height: 56px;
    padding: 8px 12px;
    gap: 8px;
    /* Allow horizontal scroll as last-resort if user has very long content */
    overflow-x: auto;
    overflow-y: hidden;
    flex-wrap: nowrap;
  }
  .topnav::-webkit-scrollbar { display: none; } /* hide scrollbar but keep scroll */
  .hamburger-btn { display: inline-flex; flex-shrink: 0; }
  .nav-brand { font-size: 1rem; flex-shrink: 0; }
  .nav-brand img { height: 30px !important; max-width: 120px; }
  .site-badge { display: none; }
  .admin-badge { font-size: 0.62rem; padding: 3px 7px; flex-shrink: 0; }
  /* Hide the always-visible site filter on mobile — it's still in the drawer's
     side picker, where there's room for it. */
  #topbar-site-filter { display: none !important; }
  /* Hide the dense health-indicators row — too many items for a phone topbar.
     Same data lives on the Server Health admin page (one tap from the drawer). */
  #topbar-health-indicators { display: none !important; }
  /* Hide search trigger (already hidden via .cmdk-trigger media rule) */
  .cmdk-trigger { display: none !important; }
  /* Compress the right-side group */
  .nav-right { gap: 6px; flex-shrink: 0; }
  .nav-right .live-txt, .nav-right .pulse { display: none; }
  .theme-toggle-btn { padding: 4px 8px; }
  .theme-toggle-btn #theme-toggle-label { display: none; }
  .user-chip { padding: 4px 8px 4px 6px; flex-shrink: 0; }
  .user-chip span { font-size: 0.72rem; max-width: 70px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: inline-block; }
  .logout-btn { padding: 6px 10px; font-size: 0.7rem; min-height: 36px; flex-shrink: 0; }

  /* Sidebar — slide-in drawer from left */
  .main { flex-direction: column; position: relative; }
  .sidebar {
    position: fixed;
    /* Anchor BOTH top and bottom so the drawer fills the visible viewport
       regardless of browser chrome size. Avoid setting `height` here so we
       don't fight with the implicit top/bottom-derived height. */
    top: 0;
    left: 0;
    bottom: 0;
    width: 260px;
    max-width: 82vw;
    padding: 16px 14px;
    /* Reserve space for iOS home-indicator + scroll cushion so the LAST
       nav item isn't flush against the screen edge / hidden behind the bar */
    padding-bottom: calc(40px + env(safe-area-inset-bottom, 0px));
    z-index: 100;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: 8px 0 24px rgba(0,0,0,0.5);
    /* Independent scroll container — the drawer's own scrollbar handles
       overflow; do NOT let touch-scroll fall through to the page underneath. */
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
  }
  /* Backdrop blocks all touches on the page underneath while drawer is open */
  .sidebar-backdrop.open {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.45);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    touch-action: none;
  }
  .sidebar.open {
    transform: translateX(0) !important;
    -webkit-transform: translateX(0) !important;
    visibility: visible !important;
    z-index: 10000 !important;
  }
  /* Android Chrome / Samsung Internet sometimes render position:fixed
     elements behind the page if z-index isn't explicit. Force the stack. */
  .sidebar { z-index: 10000; will-change: transform; }
  .sidebar-backdrop { z-index: 9999; }
  .sidebar-backdrop.open { display: block !important; }
  .sidebar-tools { position: static; padding: 0 0 10px; background: transparent; }

  /* Nav items — bigger touch targets, min 44px high */
  .nav-item {
    padding: 12px 14px;
    font-size: 0.85rem;
    min-height: 44px;
    border-radius: 10px;
  }
  .nav-section { font-size: 0.58rem; padding: 14px 14px 6px; }

  /* Content area */
  .content { padding: 12px; overflow-x: hidden; }
  .page-header { padding: 14px 16px; margin-bottom: 14px; }
  .page-title { font-size: 1.05rem; }
  .page-subtitle { font-size: 0.74rem; }

  /* Camera card — full width */
  .cam-card { max-width: 100%; }

  /* Stats grid — 2 columns on mobile */
  .stats { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .stat { padding: 10px; }
  .stat-val { font-size: 0.85rem; }

  /* Video — full width, proper aspect ratio */
  video { width: 100%; min-height: 200px; }

  /* Camera header — stack title above dropdown on narrow screens */
  .cam-header {
    flex-wrap: wrap;
    gap: 10px;
  }
  .cam-header > div:first-child { flex: 1 0 100%; min-width: 0; }
  .cam-header > div:last-child { flex: 1 0 100%; justify-content: flex-start !important; flex-wrap: wrap; }
  #live-cam-dropdown { max-width: 100% !important; flex: 1 1 auto; font-size: 16px !important; min-height: 40px; }

  /* Camera footer buttons — bigger touch targets */
  .cam-footer {
    flex-wrap: wrap;
    gap: 6px;
    padding: 10px 12px;
  }
  .cam-footer .btn {
    font-size: 0.78rem;
    padding: 10px 14px;
    min-height: 40px;
    min-width: 44px;
  }
  .stream-status { width: 100%; text-align: center; margin-left: 0; }

  /* Layout editor — stack the two columns */
  #page-layout > div[style*="grid-template-columns"] {
    grid-template-columns: 1fr !important;
  }

  /* Archive timeline — bigger markers & taps */
  #archive-timeline { height: 64px; }
  #archive-timeline-markers .arch-marker { width: 5px !important; }

  /* Archive bar — wrap cleanly */
  #live-archive-bar { padding: 10px 12px !important; gap: 8px !important; }
  #live-archive-bar button { min-height: 36px; }
  #live-archive-date, #live-archive-time {
    font-size: 16px !important; /* prevent iOS zoom */
    padding: 8px 10px !important;
  }

  /* PTZ panel */
  .ptz-grid { grid-template-columns: repeat(3, 56px); gap: 8px; }
  .ptz-key { width: 56px; height: 56px; font-size: 1.3rem; }

  /* Preset grid */
  .preset-grid { gap: 5px; }
  .preset-btn { font-size: 0.7rem; padding: 5px 10px; }

  /* Admin tables — horizontal scroll */
  .admin-section { max-width: 100%; overflow-x: auto; }
  .table { min-width: 500px; font-size: 0.72rem; }
  .table td, .table th { padding: 8px 10px; }

  /* Site cards — single column */
  .site-cards { grid-template-columns: 1fr; }

  /* Modals — full screen on mobile */
  .modal {
    width: 95vw;
    max-width: 95vw;
    padding: 20px 16px;
    margin: 10px;
    max-height: 90vh;
  }
  .modal-inp { font-size: 16px; } /* Prevents zoom on iOS */

  /* Recording grid */
  .rec-grid { gap: 6px; }
  .rec-item { padding: 10px 12px; gap: 8px; }
  .rec-name { font-size: 0.78rem; }
  .rec-meta { font-size: 0.62rem; gap: 6px; flex-wrap: wrap; }

  /* Timelapse image grid */
  #tl-img-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)) !important; }

  /* Social push cards */
  .social-grid { grid-template-columns: 1fr !important; }

  /* Plan grid */
  .plan-grid { grid-template-columns: 1fr !important; }
  .pkg-grid { grid-template-columns: 1fr !important; }

  /* Date pills */
  #date-pills { overflow-x: auto; flex-wrap: nowrap; padding-bottom: 4px; }
  #date-pills .rec-filter-btn { flex-shrink: 0; }

  /* SD card table */
  .viewer-tbl-wrap { overflow-x: auto; }

  /* Embed generator */
  .grid { grid-template-columns: 1fr !important; }
  .size-grid { grid-template-columns: repeat(3, 1fr); }

  /* Player card */
  .rec-player-card { max-width: 100%; }
  #rec-player { aspect-ratio: 16/9; }

  /* Timelapse player */
  #tl-player { max-width: 100% !important; }
  #tl-video { aspect-ratio: 16/9; }

  /* Admin section header */
  .admin-section-header { flex-wrap: wrap; gap: 8px; }
  .admin-section-header .btn { font-size: 0.68rem; padding: 5px 10px; }

  /* Manage pages overflow */
  #page-sites, #page-cameras, #page-users { overflow-x: auto; }
}

/* ── Mobile responsiveness — targeted overrides for tight viewports ──
   These extend the existing @media(max-width:768px) block by catching the
   inline-styled grids and dense flex rows that slipped through. Ordering
   matters: this block is BEFORE the 480px one so the cascade works naturally. */
@media (max-width: 640px) {
  /* Prevent any sneaky horizontal scrolling from inline-styled grids. */
  html, body { overflow-x: hidden; }

  /* Collapse wide auto-fill grids to single column on phones. Many of these
     use inline minmax(>=260px,1fr) which reserves more width than a 375px
     viewport can provide after padding, causing horizontal overflow. */
  #ss-results, #dash-cam-cards, #health-grid, #pano-grid, #branding-grid,
  #tl-img-grid, #acct-cameras, #dash-stats, #rec-grid .sd-tile-grid,
  .site-cards {
    grid-template-columns: 1fr !important;
  }

  /* Catch-all for inline auto-fill grids in the content area — any grid
     asking for ≥260px columns gets forced to 1 col on narrow screens. */
  .content [style*="minmax(260px"],
  .content [style*="minmax(280px"],
  .content [style*="minmax(300px"] {
    grid-template-columns: 1fr !important;
  }
  /* Slightly wider breakpoint tolerance for 200–240px grids on tiny phones */
  .content [style*="minmax(220px"],
  .content [style*="minmax(240px"] {
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)) !important;
  }

  /* Rec player toolbar — ensure buttons wrap cleanly with tappable size */
  #rec-player-card .btn,
  #rec-player-card button,
  #rec-player-card select {
    min-height: 38px;
    font-size: 0.72rem;
  }
  /* Share-links admin card rows — stack buttons under the label when cramped */
  #acct-shares-list > div {
    padding: 10px !important;
  }
  #acct-shares-list > div > button {
    flex: 1 1 30%;
    min-height: 36px;
  }

  /* B2 recordings list rows (#rec-grid flex rows built by b2.js) — wrap so
     buttons don't push the row past the viewport edge. */
  #rec-grid > div[style*="display:flex"] {
    flex-wrap: wrap;
  }
  #rec-grid > div[style*="display:flex"] > div[style*="flex:1"] {
    flex: 1 1 100%;
    min-width: 0;
  }

  /* Detection event tiles — buttons row wraps, bigger tap targets */
  #det-events-grid button, #det-feed button {
    min-height: 32px;
  }

  /* Modals built inline (not .modal class) — constrain width */
  #share-clip-modal, #share-clip-modal .modal,
  [id$="-modal"][style*="position:fixed"] > div {
    width: 95vw !important;
    max-width: 95vw !important;
    max-height: 92vh !important;
    overflow-y: auto;
  }

  /* Account page inputs/buttons — full-width readable */
  #page-account input, #page-account select, #page-account textarea {
    font-size: 16px !important; /* suppress iOS auto-zoom */
    min-height: 40px;
  }

  /* Recording tile grid (line 7803) — inline minmax(260,1fr) won't fit on a
     phone. Already caught by the generic rule above, but lock it in for the
     actual wrapper so Play/Save/Share buttons remain side-by-side not cramped. */
  #rec-grid .rec-item {
    flex-wrap: wrap;
  }
  #rec-grid .rec-item > div[style*="flex-direction:column"] {
    flex-direction: row !important;
    width: 100%;
    justify-content: flex-end;
    gap: 6px;
  }

  /* Recordings tab bar (Auto/Local/Cloud/SD) — horizontal scroll instead of
     wrap, matches iOS pattern */
  #rec-tabs {
    overflow-x: auto;
    flex-wrap: nowrap !important;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  #rec-tabs::-webkit-scrollbar { display: none; }
  #rec-tabs > * { flex-shrink: 0; }

  /* Live view — stream status + archive bar stack */
  #rec-stats-bar { flex-wrap: wrap; gap: 6px; font-size: 0.68rem !important; }

  /* Toast container already handles narrow viewports (see line 364) */
}

@media (max-width: 480px) {
  /* Extra small phones */
  .stats { grid-template-columns: repeat(2, 1fr); }
  .topnav { padding: 6px 10px; }
  .content { padding: 8px; }
  .cam-footer .btn { font-size: 0.65rem; padding: 5px 8px; }
  .ptz-key { width: 50px; height: 50px; }

  /* Live view title */
  .cam-header { padding: 10px 12px; }
  .cam-title { font-size: 0.8rem; }
  .cam-sub { font-size: 0.6rem; }

  /* Hide less important stats on tiny screens */
  .stat:nth-child(3), .stat:nth-child(4) { display: none; }
  .stats { grid-template-columns: repeat(2, 1fr); }
}


/* ── Camera (Live View) page polish — mobile first, desktop clean ──
   Targets #page-live only so we don't disturb other pages. */
@media (max-width: 640px) {
  /* Kill any horizontal scroll on the camera page */
  #page-live { overflow-x: hidden; }

  /* Top stats — single column stack, slightly larger text */
  #page-live .stats {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 6px;
  }
  #page-live .stat { padding: 8px 10px; }
  #page-live .stat-lbl { font-size: 0.62rem; }
  #page-live .stat-val { font-size: 0.92rem; }
  #page-live .stat-sub { font-size: 0.6rem; }

  /* Camera header wraps cleanly, dropdown goes full width below title */
  #page-live .cam-header {
    flex-wrap: wrap;
    gap: 8px;
    padding: 10px 12px;
  }
  #page-live .cam-header > div:first-child { flex: 1 1 100%; min-width: 0; }
  #page-live .cam-header > div:last-child {
    flex: 1 1 100%;
    flex-wrap: wrap;
    gap: 6px;
    justify-content: flex-start;
  }
  #page-live #live-cam-dropdown { max-width: 100% !important; flex: 1 1 auto; min-height: 40px; font-size: 0.85rem; }
  #page-live .cam-title { font-size: 1rem; line-height: 1.25; }
  #page-live .cam-sub { font-size: 0.7rem; }

  /* Video — preserve 16:9, never taller than viewport width allows */
  #page-live #player {
    width: 100% !important;
    height: auto !important;
    max-height: 56.25vw !important;
    aspect-ratio: 16/9;
  }

  /* Player bar (controls) — stack groups, full-width tap targets */
  #page-live #player-bar {
    padding: 8px 10px;
    gap: 6px;
  }
  #page-live #player-bar > div {
    flex-wrap: wrap;
    width: 100%;
    justify-content: flex-start;
  }
  #page-live #player-bar > div[style*="flex:1"] { display: none; } /* spacer */
  #page-live #player-bar .btn {
    min-height: 44px;
    font-size: 0.78rem;
    padding: 8px 12px;
    flex: 1 1 auto;
  }
  #page-live #player-bar select {
    min-height: 44px;
    font-size: 0.82rem !important;
    padding: 8px 10px !important;
    flex: 1 1 auto;
  }
  /* Dividers become invisible when stacked */
  #page-live #player-bar > div[style*="width:1px"],
  #page-live #player-bar div[style*="width:1px"][style*="height:20px"] { display: none; }

  /* Make "Go Live" (primary action when visible) more obvious */
  #page-live #btn-live {
    flex: 1 1 100% !important;
    font-weight: 700;
    letter-spacing: 0.03em;
  }

  /* Archive bar — stacks cleanly; controls are scannable */
  #page-live #live-archive-bar {
    flex-wrap: wrap;
    gap: 6px;
    padding: 10px 12px;
  }
  #page-live #live-archive-bar input,
  #page-live #live-archive-bar select,
  #page-live #live-archive-bar button {
    min-height: 40px;
    font-size: 0.8rem !important;
  }
  #page-live #live-archive-bar input[type="date"],
  #page-live #live-archive-bar input[type="time"] {
    flex: 1 1 46%;
  }

  /* PTZ keys a bit bigger, easier thumbs */
  #page-live .ptz-key { width: 56px; height: 56px; font-size: 1.05rem; }

  /* Panels get a touch more breathing room */
  #page-live .panel { padding: 10px; }
  #page-live .panel-title { font-size: 0.78rem; }

  /* Modals launched from the camera page — ensure they fit */
  #share-clip-modal > div, #share-clip-modal .modal-body,
  [id^="page-live"] ~ [id$="-modal"] > div {
    max-width: 95vw !important;
    max-height: 92vh !important;
    overflow-y: auto;
  }
}

/* Desktop — keep existing layout, just tighten the controls row so it doesn't
   wrap oddly on mid-width screens. Two-column split intentionally skipped
   because existing layout already works well at ≥1024px. */
@media (min-width: 1024px) {
  #page-live #player-bar { padding: 10px 14px; }
}


/* Detection notifications */
#detect-bell{display:none !important;display:none !important;
  position:fixed;top:18px;right:18px;z-index:9998;background:var(--surface-2);color:var(--text-primary);
  border:1px solid var(--border-1);border-radius:10px;padding:10px 12px;cursor:pointer;
  box-shadow:0 8px 24px rgba(0,0,0,0.28);font-size:18px
}
#detect-bell-count{
  display:inline-block;min-width:18px;padding:1px 6px;margin-left:6px;border-radius:999px;
  background:#ff3b3b;color:#fff;font-size:11px;font-weight:700;text-align:center
}
#detect-panel{
  position:fixed;bottom:72px;right:18px;top:auto;width:380px;max-height:70vh;overflow:auto;z-index:9998;
  background:var(--surface-1);border:1px solid var(--border-1);border-radius:12px;
  box-shadow:0 16px 40px rgba(0,0,0,0.35);display:none
}
#detect-panel-head{
  display:flex;align-items:center;justify-content:space-between;padding:12px 14px;
  border-bottom:1px solid var(--border-1);font-weight:700;color:var(--text-primary)
}
#detect-list{padding:10px}
.detect-item{
  display:flex;gap:10px;align-items:flex-start;padding:10px;border-radius:10px;cursor:pointer;
  background:var(--surface-2);border:1px solid var(--border-1);margin-bottom:8px
}
.detect-item:hover{border-color:rgba(0,229,255,0.35)}
.detect-thumb{
  width:88px;height:50px;object-fit:cover;border-radius:6px;background:var(--surface-0);flex-shrink:0
}
.detect-meta{flex:1;min-width:0}
.detect-title{font-size:13px;font-weight:700;color:var(--text-primary)}
.detect-sub{font-size:12px;color:var(--text-secondary);margin-top:2px}
.detect-time{font-size:11px;color:var(--text-muted);margin-top:4px}
#detect-viewer{
  position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,0.82);display:none;
  align-items:center;justify-content:center;padding:20px
}
#detect-viewer-card{
  width:min(1100px,95vw);max-height:92vh;overflow:auto;background:var(--surface-1);border-radius:14px;
  border:1px solid var(--border-1);box-shadow:0 20px 50px rgba(0,0,0,0.45);padding:16px
}
#detect-viewer-top{
  display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;color:var(--text-primary)
}
#detect-viewer-media img,#detect-viewer-media video{
  max-width:100%;max-height:72vh;border-radius:10px;background:var(--surface-0)
}
#detect-viewer-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px}


/* Tighten top spacing on admin, recordings, timelapse, and page sections */
#app,
.page,
.page-content,
.admin-page,
#page-recordings,
#page-timelapse,
#page-cameras,
#page-sites,
#page-users,
#page-dashboard,
#page-social,
#page-live,
#page-info {
  padding-top: 8px !important;
  margin-top: 0 !important;
}

#page-recordings > *:first-child,
#page-timelapse > *:first-child,
#page-cameras > *:first-child,
#page-sites > *:first-child,
#page-users > *:first-child,
#page-dashboard > *:first-child,
#page-social > *:first-child,
#page-live > *:first-child,
#page-info > *:first-child {
  margin-top: 0 !important;
  padding-top: 0 !important;
}

.admin-section-header,
.rec-player-header,
.cam-header {
  margin-top: 0 !important;
}

body {
  overflow-x: hidden;
}

/* ═══════════════════════════════════════════════════════════════════════
   UI REDESIGN — CSS Variables + Global Overrides (April 2026)
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  --bg-page:var(--surface-0); --bg-panel:var(--surface-1); --bg-card:var(--surface-2); --bg-input:#080b10;
  --border:var(--surface-3); --border-hover:var(--surface-3); --border-focus:#00e5b8;
  /* a11y: --text-faint bumped from var(--text-faint) (2.4:1) → var(--text-muted) (5.2:1) to meet WCAG AA on dark cards. */
  --text-primary:#f1f5fb; --text-secondary:#c0cfe0; --text-muted:#8a9bb5; --text-faint:#6a7b95;
  --accent-teal:#00e5b8; --accent-blue:#6eb4ff; --accent-green:#5ef898;
  --accent-amber:#ffd166; --accent-red:#ff6b6b; --accent-light-blue:#93c5fd;
  --font-ui:'DM Sans',system-ui,-apple-system,sans-serif;
  --font-mono:'JetBrains Mono',ui-monospace,monospace;

  /* ── Typography scale (Sprint 1 / Task 1.1) ──
     Floor for body copy is --text-sm (15 px). --text-xs is reserved for
     dense tabular numbers and timestamps ONLY. Individual font-size
     overrides throughout the SPA will be audited in a follow-up pass. */
  --text-xs: 13px;
  --text-sm: 15px;
  --text-md: 16px;
  --text-lg: 18px;
  --text-xl: 22px;

  /* ── Semantic color palette (Sprint 1 / Task 1.4) ──
     One color per meaning — new code and touched code must use these.
     --action   — any interactive affordance (buttons, links, focus)
     --ok       — healthy, live, armed, success
     --warn     — destructive, needs attention (delete, stop recording)
     --danger   — error / failed state
     Surfaces and text scales provided so page headers no longer need gradients. */
  --action:       #00E5FF;
  --action-hover: #22F0FF;
  --ok:           #00FF9D;
  --warn:         #FF9D00;
  --danger:       #FF5577;
  --text:         #E8ECF2;
  --surface-1:    #0B1016;
  --surface-2:    #11181F;
}

/* ── Global font + smoothing ── */
html,body,input,select,textarea,button {
  font-family:var(--font-ui);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  letter-spacing:.01em;
}

/* ── Body base: raises any unstyled text to the 15 px floor ── */
body { font-size: var(--text-sm); line-height: 1.5; }

/* ══════════════════════════════════════════════════════════════════════
   ACCESSIBILITY BASELINE — WCAG 2.1 AA  (added 2026-04-23)
   ══════════════════════════════════════════════════════════════════════ */

/* 1. Global focus-visible ring. Keyboard users always see where they are. */
*:focus-visible {
  outline: 2px solid var(--action, #00e5ff) !important;
  outline-offset: 2px !important;
  border-radius: 4px;
}
/* Suppress ring for mouse users only (not keyboard). */
*:focus:not(:focus-visible) { outline: none; }

/* 2. Enforce 44×44 minimum tap target on interactive elements.
      Narrower exceptions (tight toolbar icon rows, table-cell buttons)
      can override with `.tap-xs` when density is essential. */
button:not(.tap-xs),
[role="button"]:not(.tap-xs),
a.btn:not(.tap-xs),
.btn:not(.tap-xs) {
  min-height: 36px;  /* desktop-friendly; mobile bumps to 44 below */
}
@media (hover: none), (pointer: coarse), (max-width: 640px) {
  button:not(.tap-xs),
  [role="button"]:not(.tap-xs),
  a.btn:not(.tap-xs),
  .btn:not(.tap-xs),
  select, input[type="date"], input[type="time"], input[type="text"],
  input[type="email"], input[type="password"], input[type="number"], textarea {
    min-height: 44px;
    min-width: 44px;
  }
}

/* 3. Readable-text floor. Anything below 12px is effectively unreadable
      for most users and a 1.4.4 violation at default zoom. We allow the
      monospace/tabular-data class `.num-tight` to opt out. */
p, span, div, label, li, td, th, a, button, input, select, textarea {
  font-size: max(var(--size, 1em), 12px);
}
.num-tight, .mono-stamp, time { /* opt-outs for tabular timestamps */
  font-size: inherit !important;
}

/* 4. Screen-reader-only utility for offscreen announcements/labels. */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}

/* 5. Make every [onclick]-only element keyboard-focusable by default.
      Also gives them a pointer cursor and shows the focus ring.
      Pages should still migrate these to <button>, but this prevents
      the worst of the "unreachable with Tab" failures. */
[onclick]:not(button):not(a):not(input):not(select):not(textarea):not([tabindex]) {
  cursor: pointer;
}

/* 6. Respect prefers-reduced-motion — disables the few animations we have. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* 7. Raise contrast on disabled state to >= 3:1 so users know something
      is there — default browser grey on dark often falls to 1.8:1. */
:disabled, [aria-disabled="true"] {
  opacity: 0.6 !important;
}
/* 8. Skip-to-content link — visible only when focused. */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 10100;
  background: var(--action, #00e5ff); color: #0a1218;
  padding: 10px 16px; border-radius: 0 0 6px 0;
  font-weight: 700; font-size: 14px; text-decoration: none;
}
.skip-link:focus { left: 0; outline: 3px solid #fff; outline-offset: 2px; }

/* 9. Toast appearance (SR reads via aria-live on the region). */
#a11y-toast-region .toast {
  background: var(--surface-2); color: var(--text-primary);
  border: 1px solid rgba(0,229,255,0.35);
  padding: 10px 18px; border-radius: 10px;
  margin-top: 8px; min-width: 240px; max-width: 80vw;
  box-shadow: 0 6px 24px rgba(0,0,0,0.4);
  pointer-events: auto; font-size: 14px;
  animation: a11y-toast-in .18s ease-out;
}
#a11y-toast-region .toast.toast-err { border-color: rgba(255,107,107,0.5); color: #ffb4b4; }
#a11y-toast-region .toast.toast-ok  { border-color: rgba(0,255,157,0.4);  color: #9dffcf; }
@keyframes a11y-toast-in { from { opacity:0; transform: translateY(8px); } to { opacity:1; transform: translateY(0); } }

/* END a11y baseline */

/* ══════════════════════════════════════════════════════════════════════
   UI REFINEMENT v2 — operator-critical polish (added 2026-04-23)
   Addresses the 10-item design review. Token-driven, minimal !important.
   ══════════════════════════════════════════════════════════════════════ */

/* ── (7) Font normalization — force DM Sans everywhere, no Segoe drift. ── */
html, body, input, select, textarea, button,
.btn, .nav-item, .stat, .stat-lbl, .stat-val, .stat-sub,
.cam-title, .cam-sub, .detect-title, .detect-sub, .detect-time,
[class^="stream-status"], .stream-status {
  font-family: var(--font-ui, 'DM Sans', system-ui, -apple-system, sans-serif);
}
/* Monospace reserved for numeric clocks + timestamps only. */
.player-clock-overlay, #live-tz-time, #live-latency,
.mono-stamp, .num-tight, time, code, pre, kbd {
  font-family: var(--font-mono, 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace);
}

/* ══════════════════════════════════════════════════════════════════════
   (2) TEXT SIZING — v3 canonical scale for stats/pills/labels/buttons
   ══════════════════════════════════════════════════════════════════════ */
/* Canonical size tokens — anything you add from now on should use these. */
:root {
  --txt-xs:   12px;   /* chips, timestamps, meta (FLOOR) */
  --txt-sm:   13px;   /* buttons, secondary text */
  --txt-base: 14px;   /* body, stat values */
  --txt-md:   15px;   /* card headers */
  --txt-lg:   18px;   /* section headers */
  --txt-xl:   22px;   /* page title */
  --leading:  1.45;
}

/* Inline-style floor — catches every legacy hand-typed font-size below 12px.
   Uses attribute selectors so we don't have to hunt down every HTML site.    */
[style*="font-size:0.5rem"], [style*="font-size:0.55rem"],
[style*="font-size:0.58rem"], [style*="font-size:0.6rem"],
[style*="font-size:0.6em"],
[style*="font-size:0.62rem"], [style*="font-size:0.65rem"],
[style*="font-size:0.66rem"], [style*="font-size:0.68rem"],
[style*="font-size:10px"], [style*="font-size:11px"],
[style*="font-size: 10px"], [style*="font-size: 11px"],
[style*="font-size:9px"], [style*="font-size:8px"] {
  font-size: var(--txt-xs) !important;
}
[style*="font-size:0.7rem"], [style*="font-size:0.72rem"],
[style*="font-size: 12px"], [style*="font-size:12px"] {
  font-size: var(--txt-sm) !important;
}
[style*="font-size:0.75rem"], [style*="font-size:0.78rem"],
[style*="font-size:0.8rem"], [style*="font-size:0.82rem"] {
  font-size: var(--txt-base) !important;
}

/* Component-level scale (overrides inline only where the inline is smaller). */
.stat-lbl, .panel-title, .site-header [class*="sub"],
.cam-sub, .detect-sub, .detect-time,
.stream-status, .player-clock-overlay,
#live-tz-label, #live-latency,
[class*="badge"], [class*="-chip"], [class*="pill"] {
  font-size: var(--txt-xs) !important;
  letter-spacing: 0.01em;
}
.stat-val, .cam-title, .detect-title {
  font-size: var(--txt-base) !important;
  font-weight: 600 !important;
  line-height: var(--leading);
}
.btn, button.btn, a.btn {
  font-size: var(--txt-sm) !important;
  line-height: 1 !important;
}
/* Page title hierarchy — the big header treatment. */
.page > h1, .page > header h1, [id^="page-"] > h1,
h1.page-title, h2.page-title {
  font-size: var(--txt-xl) !important;
  font-weight: 700 !important;
  letter-spacing: -0.01em !important;
  line-height: 1.2 !important;
  color: var(--text-primary) !important;
}

/* ── (2) Accent color discipline. ──
   Cyan = default UI accent. Green = healthy / live. Orange = warn / seeking.
   Red = error / recording alert. Timelapse/archive shift from orange to
   a cooler neutral so orange is reserved for actual warnings. */
.btn-orange {
  /* Only "Go Live" keeps orange; everything else shifts. */
}
/* De-emphasize timelapse + archive buttons from warn-orange → accent-cyan.
   They're navigation affordances, not warnings. */
#btn-archive, #btn-timelapse-live {
  color: var(--action) !important;
  border-color: rgba(0,229,255,0.3) !important;
}

/* When the currently-loaded camera has recording disabled, hide recording-
   dependent controls for non-admin clients. Class is toggled by loadCamera()
   in index.html. Uses !important to win over #player-bar .btn{display:
   inline-flex !important} which otherwise resurrects the buttons. Also
   hides the inline "● REC" badge next to the camera selector. */
body.cam-recording-off #btn-archive,
body.cam-recording-off #btn-timelapse-live,
body.cam-recording-off #live-rec-badge {
  display: none !important;
}

/* Admin-only UI elements. Hidden for managers and clients. The matching
   server endpoint is gated by adminOnly() so even if someone bypasses the
   CSS, the API rejects with 403. */
body:not(.is-strict-admin) .admin-only-btn {
  display: none !important;
}

/* Billing perm: any user (manager, client, etc) with permissions.canViewBilling
   should see the Billing nav item. Beats the legacy `body:not(.is-admin)
   .admin-item { display:none }` rule. Server enforces with canAccessBilling(). */
body.has-billing-perm [data-layout-id="nav-billing"] {
  display: flex !important;
}

/* Billing-only nav collapse. Triggered by either:
   - body.is-accountant       — role-based (any host)
   - body.is-billing-host     — host-based (billing.hdrelay.io, even for admins)
   Both behave identically: hide everything except the Billing nav item.
   Server still enforces with adminOrAccountant() on the billing endpoints. */
body.is-accountant .sidebar .nav-item:not([data-layout-id="nav-billing"]):not([data-layout-id="nav-account"]):not(.section-divider):not(.section-label),
body.is-accountant .nav-section:not(.accountant-keep),
body.is-billing-host .sidebar .nav-item:not([data-layout-id="nav-billing"]):not([data-layout-id="nav-account"]):not(.section-divider):not(.section-label),
body.is-billing-host .nav-section:not(.accountant-keep) {
  display: none !important;
}
body.is-accountant #admin-nav,
body.is-billing-host #admin-nav { display: block !important; }
body.is-accountant #admin-badge,
body.is-billing-host #admin-badge { display: none !important; }

/* Per-camera player-toolbar button visibility. Body classes are toggled by
   loadCamera() based on cam.showPTZBtn / cam.showPresetsBtn / cam.showPanoBtn.
   !important is required because #player-bar .btn{display:inline-flex !important}
   beats inline style.display='none' otherwise. */
body.cam-hide-ptz-btn #btn-ptz,
body.cam-hide-presets-btn #btn-presets,
body.cam-hide-pano-btn #btn-panorama {
  display: none !important;
}
#live-tl-speed {
  border-color: rgba(0,229,255,0.25) !important;
  color: var(--action) !important;
}
#live-archive-bar {
  border-top-color: rgba(0,229,255,0.18) !important;
}
#live-archive-bar span[style*="color:var(--warn)"]:first-child {
  color: var(--text-secondary) !important;
}

/* ══════════════════════════════════════════════════════════════════════
   (3) LIVE PLAYER CONTROLS — v3 clean grid
   ══════════════════════════════════════════════════════════════════════ */
/* The bar is now a single flex row with clean divider lines between groups.
   No card backgrounds (they fought the dark footer and caused wrapping). No
   pseudo-element captions (they truncated). Just buttons + silent groups.   */
#player-bar {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  gap: 8px !important;
  padding: 10px 14px !important;
  background: var(--surface-0) !important;
  border-top: 1px solid var(--border-1) !important;
}
#player-bar [role="group"] {
  display: inline-flex !important;
  flex-wrap: nowrap !important;
  align-items: center !important;
  gap: 6px !important;
  padding: 0 10px !important;
  margin: 0 !important;
  background: transparent !important;
  border: 0 !important;
  border-right: 1px solid var(--border-1) !important;
  position: static !important;
}
#player-bar [role="group"]:last-of-type { border-right: 0 !important; }
#player-bar [role="group"]::before { content: none !important; }
#player-bar [role="group"]:first-of-type { padding-left: 0 !important; }
#player-bar [data-group="archive"] { margin-left: auto !important; padding-right: 0 !important; }

/* Buttons inside the bar — compact, consistent height, no inline-style drift. */
#player-bar .btn {
  height: 34px !important;
  padding: 0 12px !important;
  font-size: 13px !important;
  font-weight: 500 !important;
  display: inline-flex !important;
  align-items: center !important;
  gap: 6px !important;
  white-space: nowrap !important;
}
#player-bar select, #player-bar input[type="date"], #player-bar input[type="time"] {
  height: 34px !important;
  padding: 0 10px !important;
  font-size: 13px !important;
}
#player-bar #live-latency {
  height: 34px !important;
  display: inline-flex !important;
  align-items: center !important;
  padding: 0 10px !important;
  font-size: 12px !important;
  color: var(--text-muted) !important;
}

/* Hide redundant legacy vertical-rule divider <div>s — borders handle it now. */
#player-bar > div[style*="width:1px"],
#player-bar [role="group"] > div[style*="width:1px"] {
  display: none !important;
}

/* Empty groups vanish (e.g. no PTZ on this camera). */
@supports selector(:has(*)) {
  #player-bar [role="group"]:not(:has(> *:not([style*="display:none"]):not([style*="display: none"]))) {
    display: none !important;
  }
  #player-bar [role="group"]:not(:has(> *:not([style*="display:none"]):not([style*="display: none"]))) + [role="group"] {
    border-left: 0 !important;
  }
}

/* Mobile: full-row groups, 44px tap targets, borders become top dividers. */
@media (max-width: 900px) {
  #player-bar { gap: 6px !important; padding: 8px 10px !important; }
  #player-bar [role="group"] {
    flex: 1 1 100% !important;
    margin: 0 !important;
    padding: 6px 0 !important;
    border-right: 0 !important;
    border-top: 1px solid var(--border-1) !important;
    justify-content: flex-start !important;
    flex-wrap: wrap !important;
  }
  #player-bar [role="group"]:first-of-type { border-top: 0 !important; }
  #player-bar .btn,
  #player-bar select {
    height: 44px !important;
    font-size: 14px !important;
    padding: 0 14px !important;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   (4) VIDEO OVERLAY HIERARCHY — one TL status / one BL time / rest hidden
   ══════════════════════════════════════════════════════════════════════ */
/* Canonical positions — everything else on the video gets hidden by default. */
.player-overlay-br { display: none !important; }       /* legacy dup clock */
.player-overlay-br #player-clock-br { display: none !important; }

/* The single canonical time badge (bottom-left). Promoted, cleaner chrome. */
#live-tz-clock {
  bottom: 10px !important;
  left: 10px !important;
  font-size: var(--txt-sm) !important;
  padding: 6px 12px !important;
  background: rgba(0,0,0,0.62) !important;
  border: 1px solid var(--border-1) !important;
  backdrop-filter: blur(6px) !important;
  -webkit-backdrop-filter: blur(6px) !important;
  font-family: var(--font-mono) !important;
  letter-spacing: 0.02em !important;
  z-index: 3;
}
#live-tz-clock #live-tz-time { font-size: var(--txt-sm) !important; color: var(--text-primary) !important; }
#live-tz-clock #live-tz-label { font-size: var(--txt-xs) !important; color: var(--text-muted) !important; }

/* Timelapse wall-clock overlay (top-right) — cyan, not saturated orange. */
#live-tl-overlay {
  top: 10px !important; right: 10px !important;
  background: rgba(0,0,0,0.55) !important;
  color: var(--action) !important;
  border: 1px solid rgba(0,229,255,0.28) !important;
  font-size: var(--txt-sm) !important;
  padding: 6px 12px !important;
}

/* Timelapse badge (top-left) — informational, not alarming. */
#live-tl-badge {
  top: 10px !important; left: 10px !important;
  background: rgba(0,229,255,0.92) !important;
  color: #0a1218 !important;
  font-size: var(--txt-xs) !important;
  padding: 5px 11px !important;
  font-weight: 700 !important;
  letter-spacing: 0.08em !important;
}

/* Panorama hint — tighter, less chrome. */
#pano-hint {
  font-size: var(--txt-xs) !important;
  padding: 5px 11px !important;
  background: rgba(0,0,0,0.55) !important;
}

/* ── (5) Calmer page headers — flatter, stronger hierarchy. ── */
.page-header, [class*="page-header"],
h1[style*="gradient"], h2[style*="gradient"] {
  background: transparent !important;
  -webkit-background-clip: initial !important;
  background-clip: initial !important;
  -webkit-text-fill-color: currentColor !important;
  text-shadow: none !important;
  box-shadow: none !important;
  filter: none !important;
}
/* Page H1 type treatment — clean, legible, single color. */
.page > h1, .page > header h1, [id^="page-"] > h1 {
  color: var(--text-primary) !important;
  font-size: 22px !important;
  font-weight: 700 !important;
  letter-spacing: -0.01em !important;
  margin-bottom: 4px !important;
}
.page > h1 + p, .page > header p, [id^="page-"] > h1 + p {
  color: var(--text-muted) !important;
  font-size: 14px !important;
}

/* ══════════════════════════════════════════════════════════════════════
   (4b) SIDEBAR HIERARCHY — primary / secondary / tertiary nav weights
   ══════════════════════════════════════════════════════════════════════ */
/* Baseline — reset everything the 5 previous passes left on .nav-item. */
.nav-item {
  font-size: var(--txt-base) !important;
  font-weight: 500 !important;
  color: var(--text-secondary) !important;
  padding: 8px 14px !important;
  border-radius: 8px !important;
  margin: 1px 6px !important;
  display: flex !important;
  align-items: center !important;
  gap: 10px !important;
  line-height: 1.2 !important;
  transition: background 0.12s, color 0.12s !important;
  border-left: 3px solid transparent !important;
  cursor: pointer;
}
.nav-item:hover {
  color: var(--text-primary) !important;
  background: rgba(0,229,255,0.06) !important;
}
.nav-item.active {
  color: var(--text-primary) !important;
  background: rgba(0,229,255,0.09) !important;
  font-weight: 600 !important;
  border-left-color: var(--action) !important;
}
.nav-item .icon, .nav-item svg {
  width: 16px !important; height: 16px !important;
  flex-shrink: 0 !important;
}

/* Secondary (admin/config) — smaller, muted, thinner icons. */
.nav-item.admin-item,
.nav-item[data-layout-id="nav-account"],
.nav-item[data-layout-id="nav-my-billing"],
.nav-item[data-layout-id="nav-branding"],
.nav-item[data-layout-id="nav-landing"],
.nav-item[data-layout-id="nav-layout"],
.nav-item[data-layout-id="nav-info"],
.nav-item[data-layout-id="nav-player-profiles"] {
  font-size: var(--txt-sm) !important;
  font-weight: 400 !important;
  color: var(--text-muted) !important;
  padding: 6px 14px !important;
}
.nav-item.admin-item .icon,
.nav-item.admin-item svg { opacity: 0.65 !important; }
.nav-item.admin-item:hover {
  color: var(--text-secondary) !important;
  background: var(--border-1) !important;
}
.nav-item.admin-item:hover .icon,
.nav-item.admin-item:hover svg { opacity: 1 !important; }
.nav-item.admin-item.active {
  color: var(--text-primary) !important;
  background: rgba(0,229,255,0.09) !important;
  font-weight: 500 !important;
}

/* Section dividers — calmer caps, tight top margin. */
.sidebar-heading, [class*="sidebar-heading"] {
  font-size: 10.5px !important;
  color: var(--text-faint) !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase !important;
  font-weight: 600 !important;
  opacity: 0.55 !important;
  padding: 14px 18px 4px !important;
  margin: 0 !important;
}

/* Sidebar brand/footer area — visually quieter. */
.sidebar-footer-stats, .sidebar-footer {
  color: var(--text-muted) !important;
  font-size: var(--txt-xs) !important;
}

/* ══════════════════════════════════════════════════════════════════════
   (5) THEME / TOKEN CLEANUP — single canonical token layer (v3)
   This wins over the earlier 3 :root blocks because it's later in source
   and uses semantic surface tokens. Individual components should read from
   var(--surface-*)/var(--border-*)/var(--accent-*) and stop redefining.
   ══════════════════════════════════════════════════════════════════════ */
:root {
  /* Surfaces — canonical dark-theme values */
  --surface-0:  #070a0f;   /* page background */
  --surface-1:  #0c1018;   /* cards, panels */
  --surface-2:  #111620;   /* inputs, buttons, chips */
  --surface-3:  #1a2130;   /* hover, elevated inputs */
  --surface-4:  #232c3c;   /* hover-hover, pressed */

  /* Borders — canonical dark values */
  --border-1: rgba(255,255,255,0.06);
  --border-2: rgba(255,255,255,0.10);
  --border-3: rgba(255,255,255,0.14);

  /* Semantic accents — ONE color per meaning. Never mix. */
  --accent:         #00e5ff;
  --accent-hover:   #22f0ff;
  --accent-bg:      rgba(0,229,255,0.08);
  --accent-border:  rgba(0,229,255,0.25);
  --success:        #00ff9d;
  --success-bg:     rgba(0,255,157,0.08);
  --success-border: rgba(0,255,157,0.25);
  --warn:           #ff9d00;
  --warn-bg:        rgba(255,157,0,0.08);
  --warn-border:    rgba(255,157,0,0.28);
  --danger:         #ff5566;
  --danger-bg:      rgba(255,85,102,0.08);
  --danger-border:  rgba(255,85,102,0.28);

  /* Text — canonical dark-theme values (NOT vars; these ARE the source) */
  --text-primary:   #f1f5fb;
  --text-secondary: #c0cfe0;
  --text-muted:     #8a9bb5;
  --text-faint:     #6a7b95;

  /* Semantic aliases (keep old names working). */
  --action:        var(--accent);
  --action-hover:  var(--accent-hover);
  --ok:            var(--success);
  /* --danger already defined above as #ff5566 */
}

/* Apply canonical surfaces to common controls. */
.btn,
select:not(.inp),
input:not(.inp):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
textarea {
  background: var(--surface-2) !important;
  border: 1px solid var(--border-2) !important;
  color: var(--text-primary) !important;
  border-radius: 6px !important;
}
.btn { cursor: pointer; }
.btn:hover:not(:disabled) {
  background: var(--surface-3) !important;
  border-color: var(--border-3) !important;
  color: var(--text-primary) !important;
}
.btn.active,
.btn[aria-pressed="true"] {
  background: var(--accent-bg) !important;
  border-color: var(--accent-border) !important;
  color: var(--accent) !important;
}
/* Semantic button variants — colors only, structure stays the same. */
.btn-green  { background: var(--success-bg) !important; border-color: var(--success-border) !important; color: var(--success) !important; }
.btn-red    { background: var(--danger-bg)  !important; border-color: var(--danger-border)  !important; color: var(--danger)  !important; }
.btn-orange { background: var(--warn-bg)    !important; border-color: var(--warn-border)    !important; color: var(--warn)    !important; }

/* Cards / panels unified surface. */
.panel, .cam-card, [class*="-card"],
.modal-card, .dialog {
  background: var(--surface-1) !important;
  border: 1px solid var(--border-1) !important;
  border-radius: 10px !important;
}

/* Kill focus-rings drifting to yellow/white in inconsistent places. */
*:focus-visible {
  outline-color: var(--accent) !important;
}

/* ── (9) Recording list emphasis — time range + source stronger. ── */
[id*="recording"] .rec-time, [id*="archive"] .rec-time,
.rec-row .rec-time, .recording-row .rec-time,
td.rec-time {
  font-size: 14px !important;
  font-weight: 600 !important;
  color: var(--text-primary) !important;
  font-family: var(--font-mono) !important;
}
.rec-source, .rec-row .rec-source, [class*="source-badge"] {
  font-size: 11px !important;
  font-weight: 700 !important;
  letter-spacing: 0.04em !important;
  text-transform: uppercase;
}
.rec-row .rec-sub, .rec-row .rec-meta,
td.rec-meta, td.rec-sub {
  font-size: 12px !important;
  color: var(--text-muted) !important;
}

/* ── (10) Mobile: thumb-friendly live controls + hide dense info on phones. ── */
@media (max-width: 640px) {
  #player-bar .btn { padding: 10px 12px !important; font-size: 14px !important; min-height: 44px !important; }
  #player-bar select, #player-bar input {
    min-height: 44px !important;
    font-size: 14px !important;
    padding: 8px 10px !important;
  }
  #live-latency { display: none !important; } /* Dev-level info, hide on phones */
  #live-tz-clock { font-size: 12px !important; padding: 5px 9px !important; }
  /* Collapse the player-bar groups vertically for easier tapping. */
  #player-bar > div[style*="display:flex"] {
    flex-basis: 100%;
    justify-content: flex-start;
  }
  /* Recording rows — stack source + time for readability. */
  .rec-row, .recording-row { flex-direction: column; align-items: flex-start !important; gap: 4px !important; }
}

/* END UI REFINEMENT v2 */

/* ── Icon primitive (Sprint 1 / Task 1.2) ──
   Usage: <svg class="icon"><use href="#icon-NAME"/></svg>
   or    iconSvg('NAME') from JS. Inherits color + scales with font-size. */
.icon {
  width: 1em; height: 1em;
  stroke: currentColor; fill: none;
  stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
  vertical-align: -2px; flex-shrink: 0;
}
.icon-md { font-size: 1.15em; }
.icon-lg { font-size: 1.4em; }

/* ── Scrollbar ── */
::-webkit-scrollbar{width:5px;height:5px}
::-webkit-scrollbar-track{background:var(--bg-page)}
::-webkit-scrollbar-thumb{background:var(--border-hover);border-radius:3px}
::-webkit-scrollbar-thumb:hover{background:#3a4d65}

/* ── Headings ── */
h1,h2,h3,h4,.modal-title,.page-header{color:var(--text-primary)}

/* ── Global form input fix (CRITICAL — dark text on dark bg) ── */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not(.inp),
select:not(.inp),textarea{
  color:var(--text-primary)!important;background:var(--bg-input)!important;
  border:1px solid var(--border-hover)!important;border-radius:6px;
  font-size:13px;padding:8px 11px;outline:none;transition:border-color .15s,box-shadow .15s;
  font-family:var(--font-ui);
}
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not(.inp):focus,
select:not(.inp):focus,textarea:focus{
  border-color:var(--border-focus)!important;
  box-shadow:0 0 0 2px rgba(0,229,184,.12)!important;outline:none;
}
.modal-inp{color:var(--text-primary)!important;background:var(--bg-input)!important;border:1px solid var(--border-hover)!important;border-radius:6px!important;font-size:13px!important;padding:9px 12px!important}
.modal-inp:focus{border-color:var(--border-focus)!important;box-shadow:0 0 0 2px rgba(0,229,184,.12)!important}
.modal-lbl{color:var(--text-secondary)!important;font-size:11.5px!important;font-weight:500!important;margin-bottom:5px!important}
select option{background:var(--bg-card);color:var(--text-primary)}
input[type="checkbox"],input[type="radio"]{accent-color:var(--accent-teal)}

/* ── Tables ── */
thead th{color:var(--text-muted)!important;font-size:10px!important;text-transform:uppercase;letter-spacing:.6px;font-weight:600;background:var(--bg-page);padding:10px 12px!important}
tbody td{color:var(--text-secondary);font-size:12.5px;padding:10px 12px}
tbody tr{transition:background .1s}
tbody tr:hover td{color:var(--text-primary);background:rgba(17,22,32,.7)}

/* ── Sidebar ── */
.sidebar{background:linear-gradient(180deg,#0b1018 0%,#080d14 100%)!important;border-right:1px solid rgba(30,38,54,.8)!important}

/* ── Nav items ── */
.nav-item{
  color:var(--text-secondary)!important;font-weight:500!important;font-size:12.5px!important;
  padding:9px 16px!important;border-left:2.5px solid transparent;
  border-radius:0 7px 7px 0!important;transition:all .12s ease!important;
  line-height:1.35!important;margin:1px 0!important;
}
.nav-item:hover{background:rgba(22,28,40,.8)!important;color:var(--text-primary)!important}
.nav-item.active{
  background:linear-gradient(90deg,rgba(0,229,184,.08),rgba(15,32,64,.6))!important;
  color:#fff!important;font-weight:600!important;border-left-color:var(--accent-teal)!important;
  box-shadow:inset 0 0 12px rgba(0,229,184,.05)!important;
}

/* ── Nav section labels ── */
.nav-section-label{
  font-size:9.5px;text-transform:uppercase;letter-spacing:1.2px;
  color:var(--text-muted);padding:18px 16px 5px;pointer-events:none;
  user-select:none;font-weight:700;margin-top:4px;
  border-top:1px solid var(--border-1);
  display:flex;align-items:center;
}
.nav-section-label:first-of-type{padding-top:8px;margin-top:0;border-top:none}

/* ── Hide legacy sidebar elements ── */
.sidebar .nav-section{display:none!important}
.sidebar .client-help{display:none!important}

/* ── Page header ── */
.page-header{margin-bottom:22px}
.page-title{font-size:22px!important;font-weight:600!important;color:var(--text-primary)!important;letter-spacing:-.01em}
.page-subtitle{font-size:13px!important;color:var(--text-secondary)!important;line-height:1.6!important;margin-top:5px;opacity:.85}
.page-kicker{font-size:10px!important;color:var(--text-muted)!important;text-transform:uppercase;letter-spacing:.7px;font-weight:600;margin-bottom:2px}
.page-chip{border:1px solid var(--border)!important;border-radius:20px!important;padding:5px 12px!important;font-size:11px!important}

/* ── Topnav ── */
.topnav{font-family:var(--font-ui)!important;border-bottom:1px solid rgba(30,38,54,.6)!important;background:rgba(10,14,20,.95)!important;backdrop-filter:blur(12px)!important;-webkit-backdrop-filter:blur(12px)!important}
.nav-brand{font-weight:700!important;color:var(--accent-teal)!important;font-size:14px!important;letter-spacing:.4px}
.site-badge{color:var(--text-primary)!important;font-weight:600!important;font-size:12px!important;background:var(--bg-card)!important;border:1px solid var(--border)!important;border-radius:6px!important;padding:4px 10px!important}
.admin-badge{color:#fff!important;font-weight:700!important;background:rgba(255,107,107,.18)!important;border:1px solid rgba(255,107,107,.3)!important;border-radius:5px!important;padding:3px 8px!important;font-size:10px!important}
.live-txt{color:var(--accent-green)!important;font-size:11px!important;font-weight:600!important}
.logout-btn{color:var(--text-muted)!important;font-size:11px!important;transition:all .15s;border:1px solid var(--border)!important;border-radius:5px!important;padding:4px 10px!important}
.logout-btn:hover{color:var(--accent-red)!important;border-color:rgba(255,107,107,.3)!important;background:rgba(255,107,107,.06)!important}

/* ── Camera header ── */
.cam-title{color:var(--text-primary)!important;font-size:15px!important;font-weight:600!important;letter-spacing:-.01em}
.cam-sub{color:var(--text-muted)!important;font-size:11px!important;font-family:var(--font-mono)!important;letter-spacing:.02em}

/* ── Camera dropdown in player header ── */
#live-cam-dropdown{
  background:var(--bg-card)!important;border:1px solid var(--border-hover)!important;
  color:var(--text-primary)!important;padding:7px 12px!important;border-radius:7px!important;
  font-size:12px!important;font-weight:500!important;font-family:var(--font-ui)!important;
  cursor:pointer;transition:border-color .15s;
}
#live-cam-dropdown:hover{border-color:var(--accent-teal)!important}
#live-cam-dropdown:focus{border-color:var(--accent-teal)!important;box-shadow:0 0 0 2px rgba(0,229,184,.12)!important}

/* ── Cam footer toolbar ── */
.cam-footer{border-top:1px solid var(--border)!important;padding:8px 12px!important;gap:5px!important}
.cam-footer .btn,.cam-footer button{
  font-family:var(--font-ui)!important;font-size:11px!important;font-weight:500!important;
  border-radius:6px!important;padding:6px 11px!important;transition:all .12s!important;
  border:1px solid var(--border)!important;
}
.cam-footer .btn:hover,.cam-footer button:hover{
  border-color:var(--border-hover)!important;background:var(--bg-card)!important;
  color:var(--text-primary)!important;
}

/* ── Stream status + REC badge ── */
.stream-status{font-family:var(--font-mono)!important;font-weight:600!important;font-size:11px!important}
.rec-badge{font-family:var(--font-mono)!important;font-size:10px!important;letter-spacing:.5px}

/* ── User chip ── */
.user-chip{font-family:var(--font-ui)!important}
.user-chip span{color:var(--text-primary)!important;font-weight:500!important;font-size:12px!important}
.avatar{font-family:var(--font-ui)!important;font-weight:600!important;font-size:11px!important}

/* ── Quick nav ── */
#quick-nav-here{font-family:var(--font-ui)!important;color:var(--text-muted)!important}

/* ── Stat cards ── */
.stat{background:var(--bg-card)!important;border:1px solid var(--border)!important;border-radius:10px!important;padding:14px 16px!important;position:relative}
.stat::after{border-radius:0 0 10px 10px!important}
.stat-lbl,.stat .stat-lbl{color:var(--text-muted)!important;font-size:9.5px!important;text-transform:uppercase;letter-spacing:.5px;font-weight:600;margin-bottom:8px}
.stat-val{color:var(--text-primary)!important;font-size:18px!important;font-weight:600!important;line-height:1;font-family:var(--font-ui)!important}
.stat-sub{color:var(--text-muted)!important;font-size:10.5px!important;margin-top:6px;font-weight:400}

/* ── Button color variants ── */
.btn-teal{background:rgba(0,229,184,.08)!important;color:var(--accent-teal)!important;border:1px solid rgba(0,229,184,.2)!important}
.btn-teal:hover{background:rgba(0,229,184,.14)!important}
.btn-blue{background:rgba(110,180,255,.08)!important;color:var(--accent-blue)!important;border:1px solid rgba(110,180,255,.2)!important}
.btn-blue:hover{background:rgba(110,180,255,.14)!important}
.btn-amber{background:rgba(255,209,102,.08)!important;color:var(--accent-amber)!important;border:1px solid rgba(255,209,102,.2)!important}
.btn-amber:hover{background:rgba(255,209,102,.14)!important}

/* ── General .btn polish ── */
.btn{transition:all .12s ease!important;font-family:var(--font-ui)!important}

/* ── Status pills ── */
.status-active,.status-online{background:rgba(94,248,152,.08)!important;color:var(--accent-green)!important;border:1px solid rgba(94,248,152,.18);border-radius:12px;font-size:10px;padding:3px 10px;font-weight:500}
.status-inactive,.status-offline{background:rgba(255,107,107,.06)!important;color:var(--accent-red)!important;border:1px solid rgba(255,107,107,.15);border-radius:12px;font-size:10px;padding:3px 10px}

/* ── Permission badges ── */
.perm-granted{background:rgba(94,248,152,.06);color:var(--accent-green);border:1px solid rgba(94,248,152,.15);border-radius:12px;font-size:10px;padding:3px 10px;font-weight:500}
.perm-denied{background:rgba(74,94,120,.08);color:var(--text-faint);border:1px solid rgba(74,94,120,.15);border-radius:12px;font-size:10px;padding:3px 10px}

/* ── Recording rows ── */
.rec-item{transition:all .12s ease;border-radius:8px!important}
.rec-item:hover{background:var(--bg-card)!important;border-color:var(--border-hover)!important}
.rec-name{font-family:var(--font-mono)!important;font-weight:500;font-size:13px!important}
.rec-meta span{font-family:var(--font-mono)!important;font-size:11px!important;color:var(--text-muted)!important}
.rec-filter-btn{border-radius:6px!important;font-size:11px!important;font-weight:500!important;transition:all .12s!important}
.rec-filter-btn.active{background:rgba(15,32,64,.8)!important;border-color:var(--accent-blue)!important;color:var(--accent-blue)!important}
.rec-play-btn{border-radius:5px!important;font-weight:500!important}
.rec-dl-btn{border-radius:5px!important}

/* ── Camera card ── */
.cam-card{background:var(--bg-panel)!important;border:1px solid var(--border)!important;border-radius:12px!important;overflow:hidden!important}
.cam-header{padding:14px 16px!important;border-bottom:1px solid rgba(30,38,54,.5)!important}

/* ── Modal polish ── */
.modal{background:var(--bg-panel)!important;border:1px solid var(--border)!important;border-radius:12px!important;box-shadow:0 20px 60px rgba(0,0,0,.6)!important}
.modal-title{font-size:16px!important;font-weight:600!important;color:var(--text-primary)!important;margin-bottom:16px!important}
.modal-close{color:var(--text-muted)!important;font-size:18px!important;transition:color .12s!important}
.modal-close:hover{color:var(--text-primary)!important}
.modal-footer{border-top:1px solid var(--border)!important;padding-top:14px!important;margin-top:16px!important}

/* ── Player overlays ── */
.player-overlay{position:absolute;pointer-events:none;z-index:10}
.player-overlay-tl{top:8px;left:8px}.player-overlay-tr{top:8px;right:8px}
.player-overlay-bl{bottom:8px;left:8px}.player-overlay-br{bottom:8px;right:8px}
.player-overlay-pill{background:rgba(0,0,0,.65);border-radius:6px;padding:5px 10px;font-size:10px;color:var(--text-primary);font-family:var(--font-mono);font-weight:500;display:inline-block;margin-bottom:4px;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
.player-clock-overlay{font-family:var(--font-mono);font-size:10px;color:var(--text-primary);background:rgba(0,0,0,.65);border-radius:5px;padding:3px 9px;backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}

/* ── Topbar indicators ── */
.topbar-indicator{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:500;color:var(--text-secondary)}
.topbar-indicator .dot{width:6px;height:6px;border-radius:50%;display:inline-block}
.topbar-production-badge{background:rgba(255,209,102,.08);border:1px solid rgba(255,209,102,.18);color:var(--accent-amber);font-size:8px;font-family:var(--font-mono);padding:3px 8px;border-radius:4px;letter-spacing:.6px;text-transform:uppercase;font-weight:600}

/* ── Sidebar footer stats ──
   Sits at the END of the scrollable nav list. On desktop where sidebar is
   often shorter than viewport, `margin-top:auto` pushes it to the bottom
   visually (filling the empty space above with margin). When the sidebar
   has overflow scroll (many items), this margin collapses and the stats
   simply appear after the last nav item — both behaviours are correct.
   Kept `flex-shrink:0` so the parent's overflow:auto engages properly. */
.sidebar-footer-stats{
  margin-top:auto;border-top:1px solid rgba(30,38,54,.6);padding:14px 16px;
  font-size:10.5px;color:var(--text-muted);display:grid;grid-template-columns:1fr 1fr;gap:6px;
  background:rgba(8,11,16,.5);
  flex-shrink:0;
}
/* On narrow viewports (mobile drawer) the auto-margin can leave a ghost
   gap above the stats that makes scrolling feel wrong. Force the stats
   to follow the last nav item directly. */
@media (max-width:768px){
  .sidebar-footer-stats{margin-top:18px}
}
.sidebar-footer-stats .val{font-weight:600;font-family:var(--font-mono);margin-left:4px}
.sidebar-footer-stats .val-live{color:var(--accent-green)}
.sidebar-footer-stats .val-offline{color:var(--accent-red)}

/* ── Server Health badges ── */
.health-operational{background:rgba(94,248,152,.08);color:var(--accent-green);font-weight:600;padding:4px 10px;border-radius:6px;font-size:10px;border:1px solid rgba(94,248,152,.15)}
.health-degraded{background:rgba(255,209,102,.08);color:var(--accent-amber);font-weight:600;padding:4px 10px;border-radius:6px;font-size:10px;border:1px solid rgba(255,209,102,.15)}
.health-down{background:rgba(255,107,107,.08);color:var(--accent-red);font-weight:600;padding:4px 10px;border-radius:6px;font-size:10px;border:1px solid rgba(255,107,107,.15)}

/* ── Notification bell ── */
.notif-bell-btn{border:1px solid var(--border);border-radius:7px;background:var(--bg-card);padding:7px 9px;cursor:pointer;position:relative;transition:all .15s}
.notif-bell-btn:hover{border-color:var(--border-hover);background:#161c28;transform:translateY(-1px)}
.notif-badge{background:var(--accent-red);color:#fff;font-size:8px;font-weight:700;border:2px solid var(--bg-page);border-radius:50%;position:absolute;top:-4px;right:-4px;min-width:16px;height:16px;text-align:center;line-height:12px}
.notif-panel{background:var(--bg-panel);border:1px solid var(--border);border-radius:12px;width:320px;box-shadow:0 16px 48px rgba(0,0,0,.5);position:absolute;top:calc(100% + 8px);right:0;z-index:100;display:none;max-height:400px;overflow-y:auto}
.notif-panel.open{display:block}

/* ── Loading spinner ── */
.loading-spinner{width:24px;height:24px;border:2px solid var(--border);border-top-color:var(--accent-teal);border-radius:50%;display:inline-block;animation:redesign-spin .8s linear infinite}
@keyframes redesign-spin{to{transform:rotate(360deg)}}
@keyframes redesign-pulse{0%,100%{opacity:1}50%{opacity:.4}}
.pulse-dot{animation:redesign-pulse 1.5s ease-in-out infinite}

/* ── Content area polish ── */
.content{color:var(--text-secondary)!important}
.content-shell{color:var(--text-secondary)}

/* ── Admin section headers ── */
.admin-section-header{color:var(--text-primary)!important;font-size:14px!important;font-weight:600!important;border-bottom:1px solid var(--border)!important;padding-bottom:10px!important;margin-bottom:14px!important}

/* ── Alert / info / success boxes ── */
.msg{border-radius:6px!important;font-size:12px!important;padding:8px 12px!important}

/* ── Tooltip text globally ── */
[title]{cursor:help}

/* ═══ LAYOUT & UX OVERHAUL — 2026-04-21 ═══ */

/* ── 1. Spacing scale ── */
:root{
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px;
}

/* ── 1b. Card / button baseline upgrades ── */
.admin-section{
  border-radius:10px!important;
  box-shadow:0 2px 8px rgba(0,0,0,.3)!important;
  border:1px solid #1e2a3a!important;
}
.btn{
  border-radius:7px!important;
  font-weight:600!important;
  padding:8px 14px!important;
  transition:background .15s,box-shadow .15s,border-color .15s!important;
}
.btn-sm{
  padding:5px 10px!important;
  font-size:0.68rem!important;
}
/* Hover lift on cards */
.admin-section:hover,.stat:hover{
  box-shadow:0 4px 16px rgba(0,0,0,.4)!important;
  transition:box-shadow .15s!important;
}

/* ── 2. Admin camera table ── */

/* Table header */
#cameras-table ~ * thead th,
#cameras-table thead th,
.table thead th,
thead th{
  font-size:0.7rem!important;
  letter-spacing:0.08em!important;
  text-transform:uppercase!important;
  color:#4a5a6a!important;
  padding:10px 12px!important;
  background:var(--surface-0)!important;
}

/* Camera data rows */
#cameras-table tr:not(.site-hdr-row) td{
  padding:12px 10px!important;
  border-bottom:1px solid #141f2b!important;
  vertical-align:middle!important;
}
#cameras-table tr:not(.site-hdr-row):nth-child(even) td{
  background:rgba(255,255,255,.02)!important;
}
#cameras-table tr:not(.site-hdr-row):hover td{
  background:rgba(0,198,255,.04)!important;
}

/* Site group header rows */
#cameras-table tr.site-hdr-row td{
  background:#0d1b2a!important;
  border-left:3px solid #00c6ff!important;
  padding:10px 14px!important;
  font-size:1rem!important;
  font-weight:700!important;
  color:var(--text-primary)!important;
  border-bottom:1px solid #1e2a3a!important;
  cursor:pointer!important;
}
#cameras-table tr.site-hdr-row:hover td{
  background:#0f2236!important;
}
/* Camera count muted badge inside site header */
#cameras-table tr.site-hdr-row td span[style*="8a97a5"]{
  background:rgba(255,255,255,.07)!important;
  border-radius:10px!important;
  padding:2px 8px!important;
  font-size:0.7rem!important;
  font-weight:500!important;
}
/* Chevron rotation via CSS on open/closed chevrons */
#cameras-table .site-chev{
  display:inline-block!important;
  transition:transform .2s!important;
  font-size:0.75rem!important;
  color:#00c6ff!important;
}

/* Name cell: bold name, remove raw ID — hide the id sub-div */
#cameras-table td strong + div[style*="0.65rem"]{
  display:none!important;
}
/* Site pill badge */
#cameras-table td:nth-child(2){
  white-space:nowrap!important;
}
/* Action cell layout: two rows */
#cameras-table td:last-child{
  white-space:nowrap!important;
  min-width:130px!important;
}
#cameras-table td:last-child > div{
  flex-wrap:wrap!important;
  gap:5px!important;
}
/* Make action buttons compact with min tap target */
#cameras-table td:last-child .btn,
#cameras-table td:last-child button{
  padding:5px 9px!important;
  font-size:0.65rem!important;
  min-height:38px!important;
  border-radius:6px!important;
}
#cameras-table td:last-child select{
  min-height:38px!important;
  font-size:0.65rem!important;
}

/* REC / TL labels — make them a bit larger for tap */
#cameras-table label{
  font-size:0.7rem!important;
  min-height:32px!important;
  display:inline-flex!important;
  align-items:center!important;
  gap:4px!important;
}
#cameras-table input[type="checkbox"]{
  width:15px!important;
  height:15px!important;
}

/* ── 3. Monitoring / dashboard camera cards ── */
#dash-cam-cards > div,
#dash-cam-cards > a{
  border-radius:10px!important;
  border:1px solid var(--border)!important;
  box-shadow:0 2px 8px rgba(0,0,0,.3)!important;
  transition:border-color .15s,box-shadow .15s,transform .15s!important;
}
#dash-cam-cards > div:hover,
#dash-cam-cards > a:hover{
  border-color:#00c6ff!important;
  box-shadow:0 4px 20px rgba(0,198,255,.12)!important;
  transform:translateY(-2px)!important;
}

/* ── 4. Navigation sidebar polish ── */
/* Active item: left 3px accent bar */
.nav-item.active{
  border-left:3px solid var(--accent-teal)!important;
  padding-left:13px!important;
  font-weight:600!important;
}
.nav-item{
  border-radius:6px!important;
  padding:10px 12px!important;
  transition:background .15s,color .15s!important;
}
.nav-item:hover{
  background:rgba(255,255,255,.05)!important;
}
/* DISABLED — was forcing sidebar into a horizontal bottom-bar that hid
   most nav items behind 0px font-size. Replaced by the proper slide-in
   drawer at @media (max-width:768px). The unreachable selector
   `(min-width:99999px)` keeps the rules parsed but never matched. */
@media(max-width:640px) and (min-width:99999px){
  .sidebar{
    position:fixed!important;
    bottom:0!important;left:0!important;right:0!important;
    top:auto!important;
    height:auto!important;
    width:100%!important;
    flex-direction:row!important;
    justify-content:space-around!important;
    align-items:center!important;
    padding:6px 0!important;
    border-right:none!important;
    border-top:1px solid rgba(255,255,255,.1)!important;
    z-index:80!important;
    background:#0b1018!important;
    overflow-x:auto!important;
    overflow-y:hidden!important;
  }
  .sidebar .nav-item{
    flex-direction:column!important;
    gap:2px!important;
    padding:6px 10px!important;
    font-size:0!important;
    min-width:48px!important;
    text-align:center!important;
  }
  /* Show only the emoji/icon part */
  .sidebar .nav-item span:first-child{
    font-size:1.2rem!important;
  }
  .sidebar .nav-section-kicker,
  .sidebar .sidebar-tools,
  .sidebar .sidebar-footer-stats{
    display:none!important;
  }
  .main .content,.main .content-shell{
    padding-bottom:72px!important;
  }
}

/* ── 5. Modals ── */
.modal{
  border-radius:14px!important;
  box-shadow:0 20px 60px rgba(0,0,0,.7)!important;
}
.modal-overlay{
  backdrop-filter:blur(4px)!important;
  -webkit-backdrop-filter:blur(4px)!important;
}
@media(max-width:640px){
  .modal{
    max-width:95vw!important;
    max-height:90vh!important;
    overflow-y:auto!important;
    margin:0 auto!important;
  }
}

/* ── 6. Forms / inputs ── */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not(.inp),
select:not(.inp),
textarea,
.modal-inp{
  border-radius:6px!important;
  padding:8px 10px!important;
  border:1px solid #2a3a4a!important;
  transition:border-color .15s,box-shadow .15s!important;
}
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not(.inp):focus,
select:not(.inp):focus,
textarea:focus,
.modal-inp:focus{
  border-color:#00c6ff!important;
  outline:none!important;
  box-shadow:0 0 0 2px rgba(0,198,255,.15)!important;
}
.modal-lbl,label.lbl,
.lbl{
  font-size:0.75rem!important;
  font-weight:600!important;
  text-transform:uppercase!important;
  letter-spacing:0.05em!important;
  color:#6a7a8a!important;
  margin-bottom:4px!important;
  display:block!important;
}

/* ── 7. Detection / alert category pills ── */
.alert-cat-person,.evt-person{
  background:rgba(60,140,255,.12)!important;
  color:#3c8cff!important;
  border:1px solid rgba(60,140,255,.25)!important;
  border-radius:10px!important;
  padding:2px 8px!important;
  font-size:0.65rem!important;
  font-weight:600!important;
}
.alert-cat-car,.evt-car,.evt-vehicle{
  background:rgba(0,200,100,.1)!important;
  color:#00c864!important;
  border:1px solid rgba(0,200,100,.22)!important;
  border-radius:10px!important;
  padding:2px 8px!important;
  font-size:0.65rem!important;
  font-weight:600!important;
}
.alert-cat-motion,.evt-motion{
  background:rgba(255,200,0,.1)!important;
  color:#ffc800!important;
  border:1px solid rgba(255,200,0,.22)!important;
  border-radius:10px!important;
  padding:2px 8px!important;
  font-size:0.65rem!important;
  font-weight:600!important;
}
.alert-cat-system,.evt-system{
  background:rgba(255,70,70,.1)!important;
  color:#ff4646!important;
  border:1px solid rgba(255,70,70,.22)!important;
  border-radius:10px!important;
  padding:2px 8px!important;
  font-size:0.65rem!important;
  font-weight:600!important;
}

/* ── Table mobile: card stacks ── */
@media(max-width:640px){
  .table,.table thead,.table tbody,.table tr,.table th,.table td{
    display:block!important;
  }
  .table thead tr{display:none!important;}
  .table tbody tr{
    background:var(--bg-card)!important;
    border:1px solid var(--border)!important;
    border-radius:8px!important;
    margin-bottom:10px!important;
    padding:8px!important;
  }
  .table td{
    border:none!important;
    padding:4px 6px!important;
    font-size:0.78rem!important;
  }
  .table td::before{
    content:attr(data-label);
    font-size:0.6rem;
    text-transform:uppercase;
    color:#4a5a6a;
    letter-spacing:.06em;
    display:block;
    margin-bottom:2px;
  }
}

/* ═══ END LAYOUT & UX OVERHAUL ═══ */

/* ═══ END UI REDESIGN CSS ═══ */


/* ════════════════════════════════════════════════════════════════════════════
   UI v4 — CANONICAL FINAL LAYER  (added 2026-04-23, MUST stay last in <style>)

   Purpose: consolidate tokens, win over the 4 prior :root/override blocks,
   and deliver the 5-item design pass in one coherent cascade instead of
   layered band-aids. Everything here is intentionally !important because
   ~80% of portal markup carries inline style="" attributes that otherwise
   override by specificity.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── 5. TOKENS — single source of truth. ──
   Overrides all four earlier :root blocks by virtue of source-order. New
   components should reference these; legacy aliases kept for compat.         */
:root {
  /* Type scale */
  --txt-xs:   12px;  --txt-sm:   13px;  --txt-base: 14px;
  --txt-md:   15px;  --txt-lg:   18px;  --txt-xl:   22px;
  --txt-2xl:  26px;
  --leading:  1.45;

  /* Surfaces (z-stack: page → card → control → hover → pressed) */
  --surface-0: #070a0f;  --surface-1: #0c1018;  --surface-2: #111620;
  --surface-3: #1a2130;  --surface-4: #232c3c;

  /* Borders */
  --border-1: rgba(255,255,255,0.06);
  --border-2: rgba(255,255,255,0.10);
  --border-3: rgba(255,255,255,0.14);

  /* Text — canonical dark-theme values (NOT vars; these ARE the source) */
  --text-primary:   #f1f5fb;
  --text-secondary: #c0cfe0;
  --text-muted:     #8a9bb5;
  --text-faint:     #6a7b95;

  /* Semantic color system — ONE meaning per color. */
  --accent:         #00e5ff;
  --accent-hover:   #22f0ff;
  --accent-bg:      rgba(0,229,255,0.09);
  --accent-border:  rgba(0,229,255,0.28);
  --success:        #00ff9d;
  --success-bg:     rgba(0,255,157,0.09);
  --success-border: rgba(0,255,157,0.28);
  --warn:           #ff9d00;
  --warn-bg:        rgba(255,157,0,0.09);
  --warn-border:    rgba(255,157,0,0.30);
  --danger:         #ff5566;
  --danger-bg:      rgba(255,85,102,0.09);
  --danger-border:  rgba(255,85,102,0.30);

  /* Legacy aliases — keep old names working across JS/CSS. */
  --action:       var(--accent);
  --action-hover: var(--accent-hover);
  --ok:           var(--success);
  --font-ui:      'DM Sans', system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;
}

/* ── 2. TEXT SIZING — global floor + canonical scale. ──                    */
html, body { font-size: var(--txt-base) !important; line-height: var(--leading) !important; }
html, body, input, select, textarea, button, .btn {
  font-family: var(--font-ui) !important;
}
/* Attribute-selector blast: catches every inline font-size below the 12px
   floor and promotes it to the canonical scale. */
[style*="font-size:0.4rem"], [style*="font-size:0.45rem"],
[style*="font-size:0.5rem"], [style*="font-size:0.55rem"],
[style*="font-size:0.58rem"], [style*="font-size:0.6rem"],
[style*="font-size:0.62rem"], [style*="font-size:0.64rem"],
[style*="font-size:0.65rem"], [style*="font-size:0.66rem"],
[style*="font-size:0.68rem"],
[style*="font-size:8px"], [style*="font-size:9px"],
[style*="font-size:10px"], [style*="font-size:11px"],
[style*="font-size: 8px"], [style*="font-size: 9px"],
[style*="font-size: 10px"], [style*="font-size: 11px"] {
  font-size: var(--txt-xs) !important;
}
[style*="font-size:0.7rem"], [style*="font-size:0.72rem"] {
  font-size: var(--txt-sm) !important;
}
[style*="font-size:0.75rem"], [style*="font-size:0.78rem"],
[style*="font-size:0.8rem"], [style*="font-size:0.82rem"],
[style*="font-size:0.85rem"] {
  font-size: var(--txt-base) !important;
}

/* Component-level canonical scale. */
.stat-lbl, .panel-title, .cam-sub, .detect-sub, .detect-time,
.stream-status, .player-clock-overlay,
[class*="badge"], [class*="chip"], [class*="pill"] {
  font-size: var(--txt-xs) !important;
  letter-spacing: 0.015em !important;
}
.stat-val, .cam-title, .detect-title {
  font-size: var(--txt-base) !important;
  font-weight: 600 !important;
  color: var(--text-primary) !important;
}
.btn, button.btn, a.btn {
  font-size: var(--txt-sm) !important;
  font-weight: 500 !important;
  line-height: 1 !important;
  height: 34px !important;
  padding: 0 12px !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: 6px !important;
  white-space: nowrap !important;
  border-radius: 6px !important;
  background: var(--surface-2) !important;
  border: 1px solid var(--border-2) !important;
  color: var(--text-primary) !important;
  cursor: pointer;
  transition: background .12s, border-color .12s, color .12s !important;
}
.btn:hover:not(:disabled) {
  background: var(--surface-3) !important;
  border-color: var(--border-3) !important;
}
.btn:active:not(:disabled) { background: var(--surface-4) !important; }
.btn-green   { background: var(--success-bg) !important; border-color: var(--success-border) !important; color: var(--success) !important; }
.btn-red     { background: var(--danger-bg)  !important; border-color: var(--danger-border)  !important; color: var(--danger)  !important; }
.btn-orange  { background: var(--warn-bg)    !important; border-color: var(--warn-border)    !important; color: var(--warn)    !important; }
.btn-teal    { background: var(--accent-bg)  !important; border-color: var(--accent-border)  !important; color: var(--accent)  !important; }

/* Page title hierarchy — flatter, stronger. */
.page > h1, .page > header h1, [id^="page-"] > h1, h1.page-title {
  font-size: var(--txt-xl) !important;
  font-weight: 700 !important;
  letter-spacing: -0.01em !important;
  line-height: 1.2 !important;
  color: var(--text-primary) !important;
  background: none !important;
  -webkit-background-clip: initial !important;
  background-clip: initial !important;
  -webkit-text-fill-color: currentColor !important;
  text-shadow: none !important;
  filter: none !important;
  margin: 0 0 4px !important;
}

/* ── 1. LIVE PLAYER CONTROLS — clean single-row layout. ──                   */
#player-bar {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  gap: 8px !important;
  padding: 10px 14px !important;
  background: var(--surface-0) !important;
  border-top: 1px solid var(--border-1) !important;
  min-height: 54px !important;
}
#player-bar [role="group"] {
  display: inline-flex !important;
  flex-wrap: nowrap !important;
  align-items: center !important;
  gap: 6px !important;
  padding: 0 10px !important;
  margin: 0 !important;
  background: transparent !important;
  border: 0 !important;
  border-right: 1px solid var(--border-1) !important;
  position: static !important;
  height: 34px !important;
}
#player-bar [role="group"]::before { content: none !important; }
#player-bar [role="group"]:first-of-type { padding-left: 0 !important; }
#player-bar [role="group"]:last-of-type  { border-right: 0 !important; padding-right: 0 !important; }
#player-bar [data-group="archive"] { margin-left: auto !important; }
#player-bar .btn {
  height: 32px !important;
  padding: 0 11px !important;
  font-size: var(--txt-sm) !important;
}
#player-bar select, #player-bar input {
  height: 32px !important;
  padding: 0 10px !important;
  font-size: var(--txt-sm) !important;
  background: var(--surface-2) !important;
  border: 1px solid var(--border-2) !important;
  color: var(--text-primary) !important;
  border-radius: 6px !important;
}
#player-bar #live-latency {
  height: 32px !important;
  display: inline-flex !important;
  align-items: center !important;
  padding: 0 10px !important;
  font-size: var(--txt-xs) !important;
  color: var(--text-muted) !important;
  font-family: var(--font-mono) !important;
  background: var(--surface-2) !important;
  border: 1px solid var(--border-2) !important;
  border-radius: 6px !important;
}
#player-bar > div[style*="width:1px"],
#player-bar [role="group"] > div[style*="width:1px"] { display: none !important; }
@supports selector(:has(*)) {
  #player-bar [role="group"]:not(:has(> *:not([style*="display:none"]):not([style*="display: none"]))) {
    display: none !important;
  }
}
@media (max-width: 900px) {
  #player-bar { padding: 8px 10px !important; }
  #player-bar [role="group"] {
    flex: 1 1 100% !important;
    border-right: 0 !important;
    border-top: 1px solid var(--border-1) !important;
    height: auto !important;
    padding: 8px 0 !important;
    justify-content: flex-start !important;
    flex-wrap: wrap !important;
  }
  #player-bar [role="group"]:first-of-type { border-top: 0 !important; }
  #player-bar .btn, #player-bar select, #player-bar input {
    height: 44px !important;
    font-size: var(--txt-base) !important;
    padding: 0 14px !important;
  }
  #player-bar [data-group="archive"] { margin-left: 0 !important; }
}

/* ── 3. VIDEO OVERLAY HIERARCHY — one BL time, one TR status, rest hidden. ── */
.player-overlay-br { display: none !important; }
.player-overlay-br #player-clock-br { display: none !important; }
#live-tz-clock {
  bottom: 10px !important; left: 10px !important;
  top: auto !important; right: auto !important;
  font-size: var(--txt-sm) !important;
  padding: 6px 12px !important;
  background: rgba(0,0,0,0.62) !important;
  border: 1px solid var(--border-2) !important;
  border-radius: 6px !important;
  backdrop-filter: blur(8px) !important;
  -webkit-backdrop-filter: blur(8px) !important;
  font-family: var(--font-mono) !important;
  letter-spacing: 0.02em !important;
  z-index: 3;
  gap: 8px !important;
}
#live-tz-clock #live-tz-time  { font-size: var(--txt-sm) !important; color: var(--text-primary) !important; }
#live-tz-clock #live-tz-label { font-size: var(--txt-xs) !important; color: var(--text-muted) !important; }
#live-tl-overlay {
  top: 10px !important; right: 10px !important;
  background: rgba(0,0,0,0.62) !important;
  color: var(--accent) !important;
  border: 1px solid var(--accent-border) !important;
  font-size: var(--txt-sm) !important;
  padding: 6px 12px !important;
  border-radius: 999px !important;
  font-family: var(--font-mono) !important;
}
#live-tl-badge {
  top: 10px !important; left: 10px !important;
  background: var(--accent) !important;
  color: #0a1218 !important;
  font-size: var(--txt-xs) !important;
  padding: 5px 11px !important;
  font-weight: 700 !important;
  letter-spacing: 0.08em !important;
  border-radius: 999px !important;
}
#pano-hint {
  font-size: var(--txt-xs) !important;
  padding: 5px 11px !important;
  background: rgba(0,0,0,0.55) !important;
}

/* ── 4. SIDEBAR HIERARCHY — primary / secondary / section caps. ──          */
.nav-item {
  font-size: var(--txt-base) !important;
  font-weight: 500 !important;
  color: var(--text-secondary) !important;
  padding: 8px 14px !important;
  border-radius: 8px !important;
  margin: 1px 6px !important;
  display: flex !important;
  align-items: center !important;
  gap: 10px !important;
  line-height: 1.2 !important;
  border-left: 3px solid transparent !important;
  transition: background .12s, color .12s !important;
  cursor: pointer;
}
.nav-item:hover {
  color: var(--text-primary) !important;
  background: rgba(0,229,255,0.06) !important;
}
.nav-item.active {
  color: var(--text-primary) !important;
  background: var(--accent-bg) !important;
  font-weight: 600 !important;
  border-left-color: var(--accent) !important;
}
.nav-item .icon, .nav-item svg {
  width: 16px !important; height: 16px !important;
  flex-shrink: 0 !important;
}
.nav-item.admin-item,
.nav-item[data-layout-id="nav-account"],
.nav-item[data-layout-id="nav-my-billing"],
.nav-item[data-layout-id="nav-branding"],
.nav-item[data-layout-id="nav-landing"],
.nav-item[data-layout-id="nav-layout"],
.nav-item[data-layout-id="nav-info"],
.nav-item[data-layout-id="nav-player-profiles"] {
  font-size: var(--txt-sm) !important;
  font-weight: 400 !important;
  color: var(--text-muted) !important;
  padding: 6px 14px !important;
}
.nav-item.admin-item .icon,
.nav-item.admin-item svg { opacity: 0.65 !important; }
.nav-item.admin-item:hover {
  color: var(--text-secondary) !important;
  background: var(--border-1) !important;
}
.nav-item.admin-item:hover .icon,
.nav-item.admin-item:hover svg { opacity: 1 !important; }

.sidebar-heading, [class*="sidebar-heading"] {
  font-size: 10.5px !important;
  color: var(--text-faint) !important;
  letter-spacing: 0.16em !important;
  text-transform: uppercase !important;
  font-weight: 600 !important;
  opacity: 0.55 !important;
  padding: 14px 18px 4px !important;
  margin: 0 !important;
}

/* Remove gradient/glow treatments from page headers globally. */
.page-header, [class*="page-header"],
h1[style*="gradient"], h2[style*="gradient"] {
  background: transparent !important;
  -webkit-text-fill-color: currentColor !important;
  box-shadow: none !important;
  text-shadow: none !important;
  filter: none !important;
}

/* Card unification. */
.panel, .cam-card, [class*="-card"], .modal-card {
  background: var(--surface-1) !important;
  border: 1px solid var(--border-1) !important;
  border-radius: 10px !important;
}

/* Unified focus ring color. */
*:focus-visible { outline-color: var(--accent) !important; }

/* ════════════════════════════════════════════════════════════════════════════
   THEME — LIGHT MODE  (added 2026-04-25)
   Activated by `body.theme-light`. Toggle button in the topbar; choice is
   persisted in localStorage as `cs_theme` and re-applied on page boot.
   Only redefines tokens — every component reads via var(--…) so nothing
   else needs to change.
   ════════════════════════════════════════════════════════════════════════════ */
body.theme-light {
  /* Soft, muted light theme — easier on the eyes than pure white.
     Backgrounds are warm-tinted gray instead of bright white. */
  --surface-0: #eef1f6;   /* page background — soft gray */
  --surface-1: #f7f9fc;   /* cards, panels — off-white */
  --surface-2: #e8ecf3;   /* inputs, buttons, chips */
  --surface-3: #dde2eb;   /* hover */
  --surface-4: #c8d0dc;   /* pressed */

  /* Borders */
  --border-1: rgba(0,0,0,0.06);
  --border-2: rgba(0,0,0,0.10);
  --border-3: rgba(0,0,0,0.16);

  /* Text — fixed hex values; these ARE the canonical light-theme text
     colors and must NOT reference other vars (an earlier refactor pass
     accidentally turned these into self-references / surface refs which
     made every text element invisible on light backgrounds). */
  --text-primary:   #0f172a;   /* near-black, max contrast */
  --text-secondary: #1e293b;   /* dark slate */
  --text-muted:     #475569;   /* medium-dark slate, still readable */
  --text-faint:     #64748b;   /* light slate — used for tiny meta only */

  /* Accent — keep cyan, but darker for contrast on light bg */
  --accent:         #0099b8;
  --accent-hover:   #00b3d6;
  --accent-bg:      rgba(0,153,184,0.10);
  --accent-border:  rgba(0,153,184,0.30);
  --success:        #16a34a;
  --success-bg:     rgba(22,163,74,0.10);
  --success-border: rgba(22,163,74,0.30);
  --warn:           #d97706;
  --warn-bg:        rgba(217,119,6,0.10);
  --warn-border:    rgba(217,119,6,0.30);
  --danger:         #dc2626;
  --danger-bg:      rgba(220,38,38,0.10);
  --danger-border:  rgba(220,38,38,0.28);
}
/* Page-level chrome that uses raw colors instead of tokens — patch directly. */
body.theme-light { background: var(--surface-0) !important; color: var(--text-primary); }
body.theme-light .topnav,
body.theme-light .sidebar,
body.theme-light .main {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-1) !important;
}
body.theme-light .nav-item { color: var(--text-secondary) !important; }
body.theme-light .nav-item:hover { background: rgba(0,153,184,0.08) !important; color: var(--text-primary) !important; }
body.theme-light .nav-item.active { background: var(--accent-bg) !important; color: var(--accent) !important; }
body.theme-light .panel,
body.theme-light .cam-card,
body.theme-light [class*="-card"],
body.theme-light .modal-card {
  background: var(--surface-1) !important;
  border-color: var(--border-1) !important;
}
body.theme-light .btn:not(.btn-green):not(.btn-red):not(.btn-orange):not(.btn-teal) {
  background: var(--surface-2) !important;
  border-color: var(--border-2) !important;
  color: var(--text-primary) !important;
}
body.theme-light input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
body.theme-light select,
body.theme-light textarea {
  background: var(--surface-1) !important;
  border-color: var(--border-2) !important;
  color: var(--text-primary) !important;
}
/* Login screen */
body.theme-light #login-screen { background: var(--surface-0) !important; color: var(--text-primary) !important; }
body.theme-light #login-screen .login-card,
body.theme-light #login-screen [class*="login"] { background: var(--surface-1) !important; }
/* Force-readable backgrounds on hand-styled inline-dark-color elements */
body.theme-light [style*="var(--surface-1)"],
body.theme-light [style*="var(--surface-0)"],
body.theme-light [style*="var(--surface-2)"],
body.theme-light [style*="var(--surface-0)"],
body.theme-light [style*="var(--surface-1)"] {
  background-color: var(--surface-1) !important;
}
body.theme-light [style*="color:var(--text-primary)"],
body.theme-light [style*="color:var(--text-secondary)"],
body.theme-light [style*="color:var(--text-secondary)"] {
  color: var(--text-primary) !important;
}
body.theme-light [style*="color:var(--text-muted)"],
body.theme-light [style*="color:var(--text-muted)"] {
  color: var(--text-muted) !important;
}
/* Code/preformatted areas keep dark for readability of monospace data */
body.theme-light pre, body.theme-light code, body.theme-light .mono-stamp {
  background: var(--surface-3) !important;
  color: var(--text-primary) !important;
}
/* Detection event tiles, recording rows, etc. — flip card surface */
body.theme-light .detect-event-card,
body.theme-light .detect-item,
body.theme-light .rec-row {
  background: var(--surface-1) !important;
  border-color: var(--border-1) !important;
}
/* Site filter banner in light mode */
body.theme-light #site-filter-banner {
  background: rgba(0,153,184,0.08) !important;
  border-color: rgba(0,153,184,0.30) !important;
  color: var(--text-primary) !important;
}

/* ── LIGHT THEME — comprehensive component coverage ── */
/* The earlier rules only caught a few inline-style hex colors. The portal has
   many more components with hard-coded dark backgrounds. These rules force
   them to use light surfaces, scoped exclusively to body.theme-light. */

/* Sidebar branding + tools row */
body.theme-light .nav-brand,
body.theme-light .sidebar-tools,
body.theme-light .nav-filter-inp {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-2) !important;
}
body.theme-light .nav-filter-inp::placeholder { color: var(--text-muted) !important; }

/* Topbar: search trigger, indicators */
body.theme-light .cmdk-trigger {
  background: var(--surface-2) !important;
  color: var(--text-secondary) !important;
  border-color: var(--border-2) !important;
}
body.theme-light .cmdk-kbd {
  background: var(--surface-3) !important;
  color: var(--text-muted) !important;
  border-color: var(--border-2) !important;
}
body.theme-light .topbar-indicator,
body.theme-light .site-badge {
  background: var(--surface-2) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-2) !important;
}
body.theme-light .admin-badge {
  background: rgba(217,119,6,0.12) !important;
  color: var(--warn) !important;
  border-color: var(--warn-border) !important;
}

/* Stat cards (the four dark boxes — STATUS / RECORDING / PROTOCOL / CAMERA) */
body.theme-light .stat,
body.theme-light .s1, body.theme-light .s2, body.theme-light .s3, body.theme-light .s4 {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border: 1px solid var(--border-1) !important;
  box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}
body.theme-light .stat-lbl { color: var(--text-muted) !important; }
body.theme-light .stat-val { color: var(--text-primary) !important; }
body.theme-light .stat-sub { color: var(--text-muted) !important; }

/* Camera cards in Live View / Multi View */
body.theme-light .cam-card,
body.theme-light .cam-tile {
  background: var(--surface-1) !important;
  border: 1px solid var(--border-1) !important;
  box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}
body.theme-light .cam-title { color: var(--text-primary) !important; }
body.theme-light .cam-sub { color: var(--text-muted) !important; }
body.theme-light .cam-footer { background: var(--surface-2) !important; border-top-color: var(--border-1) !important; }

/* Realtime / status pills (the black pill at top-right of Live View) */
body.theme-light [class*="realtime"],
body.theme-light [class*="status-pill"],
body.theme-light .live-status,
body.theme-light .stream-status {
  background: var(--surface-1) !important;
  color: var(--accent) !important;
  border: 1px solid var(--accent-border) !important;
}

/* Page header section ("Live Operations" / "Live View" subtitle) */
body.theme-light .page-header,
body.theme-light [id^="page-"] > h1,
body.theme-light [id^="page-"] > header,
body.theme-light .page-kicker {
  color: var(--text-primary) !important;
}
body.theme-light [id^="page-"] > h1 + p,
body.theme-light .page-subtitle {
  color: var(--text-muted) !important;
}

/* Site filter banner — keep cyan-tinted but readable on white */
body.theme-light #site-filter-banner {
  background: rgba(0,153,184,0.06) !important;
  border-color: rgba(0,153,184,0.25) !important;
  color: var(--text-primary) !important;
}

/* "Show all sites" button inside the banner */
body.theme-light #site-filter-banner button {
  background: var(--surface-1) !important;
  color: var(--accent) !important;
  border-color: var(--accent-border) !important;
}

/* Modals (edit camera, edit user, etc.) */
body.theme-light .modal,
body.theme-light .modal-card,
body.theme-light [class*="modal-content"] {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-2) !important;
}
body.theme-light .modal-lbl { color: var(--text-muted) !important; }
body.theme-light .modal-inp,
body.theme-light .modal input, body.theme-light .modal select, body.theme-light .modal textarea {
  background: var(--surface-2) !important;
  border-color: var(--border-2) !important;
  color: var(--text-primary) !important;
}

/* Table rows (Manage Cameras, Users, etc.) */
body.theme-light table { color: var(--text-primary); }
body.theme-light th { background: var(--surface-2) !important; color: var(--text-secondary) !important; }
body.theme-light td { border-color: var(--border-1) !important; }
body.theme-light tr:hover td { background: rgba(0,153,184,0.04) !important; }

/* Recordings list rows + detection event tiles */
body.theme-light .rec-row,
body.theme-light .recording-row,
body.theme-light .detect-event-card,
body.theme-light .detect-item {
  background: var(--surface-1) !important;
  border: 1px solid var(--border-1) !important;
  color: var(--text-primary) !important;
}
body.theme-light .rec-time,
body.theme-light .detect-title { color: var(--text-primary) !important; }
body.theme-light .rec-source,
body.theme-light .detect-sub,
body.theme-light .detect-time { color: var(--text-muted) !important; }

/* Player overlay backdrop (kept dark — over video — but text stays readable) */
body.theme-light #live-tz-clock,
body.theme-light .player-overlay {
  background: rgba(0,0,0,0.62) !important;  /* over video, intentionally dark */
  color: #fff !important;
  border-color: var(--border-2) !important;
}

/* ── Aggressive inline-style invert ── */
/* The portal has hundreds of components with inline style="background:#XYZ;
   color:#ABC;" hard-coded for dark mode. Override every common dark-mode
   color string and flip it to a light-mode equivalent. */

/* Backgrounds — all common dark hex prefixes */
body.theme-light [style*="background:#0"],
body.theme-light [style*="background-color:#0"],
body.theme-light [style*="background:#1"],
body.theme-light [style*="background-color:#1"],
body.theme-light [style*="background: #0"],
body.theme-light [style*="background-color: #0"],
body.theme-light [style*="background: #1"],
body.theme-light [style*="background-color: #1"],
body.theme-light [style*="background:rgb(15,"],
body.theme-light [style*="background:rgb(20,"],
body.theme-light [style*="background:rgb(7,"] {
  background: var(--surface-1) !important;
  background-color: var(--surface-1) !important;
}

/* Light text colors used in dark mode (white-ish, off-white, bluish-white)
   need to flip to dark in light mode. ONLY in main content, not in player
   overlays or pills sitting over video. */
body.theme-light .main [style*="color:var(--text-primary)"],
body.theme-light .main [style*="color:#E8EDF2"],
body.theme-light .main [style*="color: var(--text-primary)"],
body.theme-light .main [style*="color:var(--text-primary)"],
body.theme-light .main [style*="color:var(--text-primary)"],
body.theme-light .main [style*="color:#fff"],
body.theme-light .main [style*="color:#FFF"],
body.theme-light .main [style*="color:white"],
body.theme-light .main [style*="color: white"] {
  color: var(--text-primary) !important;
}

/* Muted dark-mode grays → light-mode muted */
body.theme-light .main [style*="color:var(--text-secondary)"],
body.theme-light .main [style*="color:var(--text-secondary)"],
body.theme-light .main [style*="color:var(--text-secondary)"],
body.theme-light .main [style*="color: var(--text-secondary)"] {
  color: var(--text-secondary) !important;
}
body.theme-light .main [style*="color:var(--text-muted)"],
body.theme-light .main [style*="color:var(--text-muted)"],
body.theme-light .main [style*="color:var(--text-faint)"],
body.theme-light .main [style*="color: var(--text-muted)"] {
  color: var(--text-muted) !important;
}

/* Border colors — dark borders → light borders */
body.theme-light [style*="border:1px solid rgba(255,255,255"],
body.theme-light [style*="border: 1px solid rgba(255,255,255"],
body.theme-light [style*="border-color:rgba(255,255,255"] {
  border-color: var(--border-2) !important;
}
body.theme-light [style*="border-top:1px solid rgba(255,255,255"],
body.theme-light [style*="border-bottom:1px solid rgba(255,255,255"] {
  border-top-color: var(--border-1) !important;
  border-bottom-color: var(--border-1) !important;
}

/* Catch the gradient-style stat cards explicitly. They use linear-gradient
   with multiple dark stops and aren't matched by single-hex selectors. */
body.theme-light [style*="linear-gradient"] {
  background-image: none !important;
  background-color: var(--surface-1) !important;
}

/* Realtime monitoring pill / similar — black backgrounds with bright text */
body.theme-light [style*="background:#000"],
body.theme-light [style*="background-color:#000"],
body.theme-light [style*="background:rgba(0,0,0"] {
  background: var(--surface-2) !important;
}
body.theme-light [style*="background:rgba(0,0,0,0.6"],
body.theme-light [style*="background:rgba(0,0,0,0.7"],
body.theme-light [style*="background:rgba(0,0,0,0.8"] {
  /* These are usually video overlays — keep them dark */
  background: rgba(0,0,0,0.62) !important;
  color: #fff !important;
}

/* Forcefully readable dropdown selects */
body.theme-light select,
body.theme-light select option {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
}

/* Over-video elements stay dark — explicitly opt them out */
body.theme-light #player-wrap *,
body.theme-light .player-overlay,
body.theme-light .player-overlay-tl,
body.theme-light .player-overlay-tr,
body.theme-light .player-overlay-bl,
body.theme-light .player-overlay-br,
body.theme-light #live-tz-clock,
body.theme-light #live-tl-overlay,
body.theme-light #live-tl-badge {
  /* Don't touch — they live over the black <video> element */
}
body.theme-light #player-wrap .pc-iframe-body { background: #fff !important; }

/* Keep the over-video pills/buttons readable (white text on translucent dark) */
body.theme-light video + *,
body.theme-light #player-bar {
  background: var(--surface-2) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-1) !important;
}

/* ── HARD OVERRIDES for stubborn elements (specific IDs / classes) ── */
/* These elements have inline styles the normalizer can miss because they
   use rgb(), rgba(), or compound style strings. Force-style them by ID. */
body.theme-light #live-cam-dropdown,
body.theme-light #rec-cam-sel,
body.theme-light #tl-cam-sel,
body.theme-light #pano-cam-sel,
body.theme-light #detect-cam-sel,
body.theme-light #topbar-site-filter {
  background: var(--surface-1) !important;
  background-color: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-2) !important;
}
body.theme-light #live-cam-dropdown option,
body.theme-light #rec-cam-sel option,
body.theme-light #tl-cam-sel option,
body.theme-light #topbar-site-filter option {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
}

/* Sidebar — every nav row, including dynamically inserted site items */
body.theme-light .sidebar,
body.theme-light .sidebar-tools,
body.theme-light #sidebar-nav,
body.theme-light .sidebar-footer-stats {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-1) !important;
}
body.theme-light .nav-item,
body.theme-light .site-nav-item {
  background: transparent !important;
  color: var(--text-secondary) !important;
}
body.theme-light .nav-item.active,
body.theme-light .site-nav-item.active {
  background: var(--accent-bg) !important;
  color: var(--accent) !important;
}
body.theme-light .nav-brand { color: var(--text-primary) !important; }

/* Avatar circle */
body.theme-light .avatar {
  background: var(--accent) !important;
  color: #fff !important;
}

/* "Realtime monitoring" pill (dark black inline) */
body.theme-light [style*="Realtime"],
body.theme-light .realtime-pill,
body.theme-light .realtime-monitoring,
body.theme-light [class*="realtime"] {
  background: var(--surface-1) !important;
  color: var(--accent) !important;
  border: 1px solid var(--accent-border) !important;
}

/* Sidebar footer "Total cameras / Live now" stat */
body.theme-light .sidebar-footer,
body.theme-light .sidebar-footer-stats,
body.theme-light .sidebar-footer * {
  background: var(--surface-2) !important;
  color: var(--text-primary) !important;
}

/* Topbar site filter visibility on light bg */
body.theme-light #topbar-site-filter {
  border-color: var(--accent-border) !important;
  color: var(--accent) !important;
}

/* Stat cards bottom borders (the colored stripes) — keep them but soften */
body.theme-light .stat[style*="border-bottom"],
body.theme-light .stat-bottom-bar { opacity: 0.7; }

/* ── TABLES — force-fix Manage Cameras / Users / Sites tables ── */
/* These tables are rendered dynamically with hard-coded inline backgrounds.
   Force every table, row, and cell to use theme variables. */
body.theme-light table,
body.theme-light .table,
body.theme-light table thead,
body.theme-light table tbody,
body.theme-light table tfoot,
body.theme-light tr,
body.theme-light td,
body.theme-light th {
  background: transparent !important;
  background-color: transparent !important;
  color: var(--text-primary) !important;
  border-color: var(--border-1) !important;
}
body.theme-light table {
  background: var(--surface-1) !important;
  border: 1px solid var(--border-1) !important;
  border-radius: 10px !important;
  overflow: hidden;
}
body.theme-light th,
body.theme-light thead tr {
  background: var(--surface-2) !important;
  color: var(--text-secondary) !important;
  font-weight: 700;
}
body.theme-light tbody tr:hover {
  background: var(--surface-2) !important;
}
body.theme-light tbody tr:hover td { background: transparent !important; }
body.theme-light tbody tr td {
  background: transparent !important;
  border-top-color: var(--border-1) !important;
  border-bottom-color: var(--border-1) !important;
}
/* Section/group rows inside tables (e.g. site headers) */
body.theme-light tr.site-row,
body.theme-light tr.group-header,
body.theme-light tr[class*="site-"] {
  background: var(--accent-bg) !important;
  color: var(--text-primary) !important;
}
body.theme-light tr.site-row td,
body.theme-light tr.group-header td {
  background: var(--accent-bg) !important;
  color: var(--text-primary) !important;
  font-weight: 600;
}

/* Camera name + secondary lines inside table cells */
body.theme-light td * {
  color: var(--text-primary) !important;
}
body.theme-light td [style*="color:var(--text-muted)"],
body.theme-light td [style*="color:var(--text-secondary)"],
body.theme-light td .stat-sub,
body.theme-light td .cam-sub {
  color: var(--text-muted) !important;
}

/* Page-level cards that wrap tables (#cameras-table-wrap etc.) */
body.theme-light [id*="table"],
body.theme-light [id*="-card"]:not([id*="player"]),
body.theme-light [id*="-wrap"]:not(#player-wrap):not([id*="player"]) {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-1) !important;
}

/* Install banner at bottom (PWA prompt) */
body.theme-light [id*="install"],
body.theme-light [class*="install-banner"],
body.theme-light .pwa-prompt {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border: 1px solid var(--border-2) !important;
  box-shadow: 0 6px 24px rgba(0,0,0,0.08);
}

/* "Add Camera" button + similar accent buttons in table headers */
body.theme-light [class*="btn-green"],
body.theme-light .btn-green {
  background: var(--success-bg) !important;
  color: var(--success) !important;
  border-color: var(--success-border) !important;
}
body.theme-light .btn-teal,
body.theme-light [class*="add-cam"] {
  background: var(--accent-bg) !important;
  color: var(--accent) !important;
  border-color: var(--accent-border) !important;
}

/* ════════════════════════════════════════════════════════════════════════
   LIGHT THEME — NUCLEAR OVERRIDE (final layer)
   The portal has thousands of inline-styled components that bypass earlier
   rules. This block uses universal selectors with !important to force every
   container in the main content area to use light surfaces and dark text.
   ════════════════════════════════════════════════════════════════════════ */

/* 1. Every block-level container under .main gets a light surface unless
      it's a button/badge/pill/exempt class. Highly broad on purpose. */
body.theme-light .main div:not([class*="btn"]):not([class*="pill"]):not([class*="badge"]):not([class*="chip"]):not([class*="dot"]):not([id="player-wrap"]):not(.player-overlay):not(.player-overlay-tl):not(.player-overlay-tr):not(.player-overlay-bl):not(.player-overlay-br):not([class*="rec-badge"]):not(.live-badge),
body.theme-light .main section,
body.theme-light .main article,
body.theme-light .main aside,
body.theme-light .main fieldset {
  background-color: transparent !important;
  background-image: none !important;
}

/* 2. Cards / panels (anything that visually IS a card) gets the light card surface. */
body.theme-light .main .stat,
body.theme-light .main .panel,
body.theme-light .main .cam-card,
body.theme-light .main .detect-event-card,
body.theme-light .main .detect-item,
body.theme-light .main .rec-row,
body.theme-light .main .recording-row,
body.theme-light .main [id$="-card"],
body.theme-light .main [class*="-card"]:not(.cmdk-modal):not([class*="player"]),
body.theme-light .main [class*="card-"],
body.theme-light .main table {
  background: var(--surface-1) !important;
  border: 1px solid var(--border-1) !important;
  color: var(--text-primary) !important;
}

/* 3. Inputs / buttons / selects get their own surface */
body.theme-light .main input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
body.theme-light .main select,
body.theme-light .main textarea {
  background: var(--surface-2) !important;
  background-color: var(--surface-2) !important;
  color: var(--text-primary) !important;
  border: 1px solid var(--border-2) !important;
}
body.theme-light .main select option {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
}

/* 4. ALL text inside .main → primary text color, unless the element is
      itself colored (button accent, success/danger pill, etc.) */
body.theme-light .main *:not([class*="btn-"]):not([class*="-pill"]):not([class*="-badge"]):not(.live-badge):not(.rec-badge):not(.dot):not(.stream-status) {
  color: var(--text-primary);
}

/* 5. Muted secondary text — keep readable but de-emphasized */
body.theme-light .main .stat-lbl,
body.theme-light .main .cam-sub,
body.theme-light .main .detect-sub,
body.theme-light .main .detect-time,
body.theme-light .main .panel-title,
body.theme-light .main .modal-lbl,
body.theme-light .main [class*="sub"],
body.theme-light .main [class*="muted"],
body.theme-light .main [class*="hint"] {
  color: var(--text-muted) !important;
}

/* 6. Sidebar & topbar — apply same light surface */
body.theme-light .topnav {
  background: var(--surface-1) !important;
  border-bottom: 1px solid var(--border-1) !important;
}
body.theme-light .topnav, body.theme-light .topnav * {
  color: var(--text-primary);
}
body.theme-light aside.sidebar,
body.theme-light #sidebar-nav {
  background: var(--surface-1) !important;
  border-right: 1px solid var(--border-1) !important;
}
body.theme-light .sidebar *:not([class*="btn-"]):not([class*="-pill"]):not(.dot):not(.icon) {
  color: var(--text-secondary);
}
body.theme-light .nav-item.active,
body.theme-light .nav-item.active * {
  color: var(--accent) !important;
}

/* 7. KEEP these dark on purpose — over-video elements + monospace data */
body.theme-light video,
body.theme-light #player-wrap,
body.theme-light #player-wrap *,
body.theme-light .player-overlay,
body.theme-light .player-overlay-tl, body.theme-light .player-overlay-tr,
body.theme-light .player-overlay-bl, body.theme-light .player-overlay-br,
body.theme-light #live-tz-clock, body.theme-light #live-tl-overlay,
body.theme-light #live-tl-badge, body.theme-light .pano-hint,
body.theme-light pre, body.theme-light code, body.theme-light kbd {
  background-color: revert;
  color: revert;
}
body.theme-light #player-wrap div,
body.theme-light .player-overlay {
  background-color: rgba(0,0,0,0.62) !important;
  color: #fff !important;
}

/* 8. Accent buttons (cyan/green/red/orange) keep their semantic color */
body.theme-light .btn-green, body.theme-light .btn-red,
body.theme-light .btn-orange, body.theme-light .btn-teal {
  /* Earlier rules already set these; just ensure the tint isn't overridden */
}
body.theme-light .btn:not(.btn-green):not(.btn-red):not(.btn-orange):not(.btn-teal) {
  background: var(--surface-2) !important;
  color: var(--text-primary) !important;
  border: 1px solid var(--border-2) !important;
}
body.theme-light .btn:hover:not(:disabled) {
  background: var(--surface-3) !important;
}

/* 9. Page-header h1 and section titles */
body.theme-light h1, body.theme-light h2, body.theme-light h3,
body.theme-light h4, body.theme-light h5, body.theme-light h6 {
  color: var(--text-primary) !important;
}

/* 10. Modals — full surface override */
body.theme-light .modal,
body.theme-light [class*="modal-"] {
  background: var(--surface-1) !important;
  color: var(--text-primary) !important;
  border-color: var(--border-2) !important;
}
body.theme-light .modal *:not(.btn):not(.btn-green):not(.btn-red):not(.btn-orange) {
  color: inherit;
}

/* Theme toggle button styling */
.theme-toggle-btn {
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  color: var(--text-primary);
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
  margin-left: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  transition: background .12s, border-color .12s;
}
.theme-toggle-btn:hover { background: var(--surface-3); border-color: var(--border-3); }

/* ════ END UI v4 CANONICAL ════ */



/* ── Mobile responsive audit fixes (2026-05-12) ── */
/* All rules scoped to ≤640px so desktop behaviour is unchanged. */

@media (max-width: 640px) {
  /* 1. Camera Grid — single column on phone, 2 col on small tablet portrait.
        The page uses inline minmax(290px,1fr) which slips past the existing
        280/300 catcher. */
  #cg-grid,
  #page-cameragrid [style*="minmax(290px"],
  #page-cameragrid [style*="minmax(280px"] {
    grid-template-columns: 1fr !important;
    gap: 10px !important;
  }
  #cg-grid .cg-card video,
  #cg-grid .cg-card img {
    width: 100% !important;
    height: auto !important;
  }

  /* 2. iOS auto-zoom prevention — ANY text-like input inside the main
        content area gets ≥16px font-size on focus-eligible inputs. iOS
        only zooms when font-size < 16px, so this is the canonical fix.
        We already had this for #page-account; extend to all content pages. */
  .content input[type="text"],
  .content input[type="email"],
  .content input[type="password"],
  .content input[type="number"],
  .content input[type="search"],
  .content input[type="tel"],
  .content input[type="url"],
  .content input[type="date"],
  .content input[type="time"],
  .content input[type="datetime-local"],
  .content input:not([type]),
  .content select,
  .content textarea,
  #nav-filter-inp {
    font-size: 16px !important;
  }

  /* 3. Nav-item tap targets — bump vertical padding so each item is a
        comfortable touch target without changing the visual style on
        desktop (this block is scoped to ≤640px). 48px is the Material
        Design recommended tappable area. */
  .nav-item {
    padding-top: 12px !important;
    padding-bottom: 12px !important;
    font-size: 0.85rem !important;
    min-height: 44px;
  }
  .nav-section,
  .nav-section-label-injected {
    padding-top: 14px !important;
  }
}

/* Coarse-pointer / no-hover devices (covers tablets in landscape too,
   not just narrow widths). Keep this minimal — only the tap-target
   bumps that hurt nobody on desktop touchscreens either. */
@media (hover: none) and (pointer: coarse) {
  .nav-item {
    min-height: 44px;
  }
  /* Make .btn easier to hit on touch — desktop click targets stay the
     same because they don't match this media query. */
  .content .btn,
  #player-bar .btn {
    min-height: 36px;
  }
}

/* 4. Camera Grid card polish on narrow viewports — handled by rule 1 above
      forcing 1-col. Add card padding tweak so text doesn't crowd the edge. */
@media (max-width: 480px) {
  #cg-grid .cg-card { padding: 8px !important; }
  #cg-grid .cg-card-title { font-size: 0.82rem; }
  #cg-grid .cg-card-meta  { font-size: 0.66rem; }
}


/* ── mobile-polish-marker (2026-05-22) ─────────────────────────────────────
   Gap-fill on top of the existing 768/640/480 media queries. Focused on
   tables, touch targets, modal action rows, and stray inputs that escaped
   the iOS-zoom suppression. */
@media (max-width: 768px) {
  /* Admin tables overflow on narrow viewports — wrap in a scrollable container
     using a sibling wrap div if present, OR force overflow on the table itself. */
  #users-table, #cameras-table, #sites-table {
    font-size: 0.72rem;
  }
  /* If the table sits in a generic wrap div, scroll horizontally instead of
     forcing the whole page wider. */
  .table-wrap, [class*="table-wrap"],
  #users-table parent, #cameras-table parent, #sites-table parent {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  /* Direct parent of the cameras-table etc. — Bootstrap-ish overflow */
  #cameras-table, #users-table, #sites-table {
    display: block;
    overflow-x: auto;
    white-space: nowrap;
    max-width: 100%;
  }
  #cameras-table td, #users-table td, #sites-table td {
    white-space: nowrap;
  }

  /* Player toolbar — bump touch targets to 44px (Apple HIG) on mobile.
     The buttons live just under #player-wrap inside the .controls strip. */
  #player-wrap ~ * .btn,
  #player-wrap ~ * button,
  .player-toolbar .btn,
  .player-toolbar button,
  [data-layout-id^="btn-"] {
    min-height: 44px;
    min-width: 44px;
    padding: 8px 12px;
    font-size: 0.78rem;
  }

  /* Modal action rows — make OK / Cancel / Save full-width and stacked on phones
     so they don't crowd. Affects any .modal-row containing buttons. */
  .modal-overlay .modal-row[style*="justify-content:flex-end"],
  .modal-overlay .modal-row[style*="justify-content: flex-end"] {
    flex-wrap: wrap;
    gap: 8px;
  }
  .modal-overlay .modal-row[style*="justify-content:flex-end"] > button,
  .modal-overlay .modal-row[style*="justify-content: flex-end"] > button {
    flex: 1 1 calc(50% - 4px);
    min-height: 44px;
  }

  /* Modal close button has more breathing room from the title on small screens */
  .modal-overlay .modal-close {
    top: 10px !important;
    right: 10px !important;
    width: 36px;
    height: 36px;
    font-size: 1.1rem;
    line-height: 36px;
  }

  /* PTZ joystick — make sure it's at least 220px tall and centered when
     the screen is narrow */
  #ptz-pad, .ptz-joystick {
    min-height: 220px;
    touch-action: none;
  }
}

@media (max-width: 640px) {
  /* Universal iOS zoom-prevention safety net for any escaped inputs. The
     existing rules cover .inp / #live-cam-dropdown / #page-account / .modal-inp.
     This catches everything else. */
  input[type="text"]:not(.dbg-val):not([disabled]),
  input[type="email"]:not(.dbg-val):not([disabled]),
  input[type="password"]:not(.dbg-val):not([disabled]),
  input[type="search"]:not(.dbg-val):not([disabled]),
  input[type="number"]:not(.dbg-val):not([disabled]),
  input[type="tel"]:not(.dbg-val):not([disabled]),
  input[type="url"]:not(.dbg-val):not([disabled]),
  textarea:not([disabled]),
  select:not([disabled]) {
    font-size: 16px !important;
  }

  /* Force any inline-styled "max-width:640px" / "min(640px,...)" modals
     to actually use the available screen on phones. Many inline-styled
     modal panels (Flow Player editor, Add Camera, etc.) set width:
     min(640px, 96vw) — the 96vw already wins on mobile but padding
     eats the rest. Reduce inner padding so content area is bigger. */
  .modal-overlay > div[style*="padding:24px"],
  .modal-overlay > div[style*="padding: 24px"] {
    padding: 16px !important;
  }

  /* Generic input height + spacing on small phones */
  input:not([type="checkbox"]):not([type="radio"]):not([type="color"]),
  select, textarea {
    min-height: 40px;
  }
  textarea { min-height: 80px; }

  /* Stack toolbar groups when there are too many buttons */
  .controls, .player-controls, .player-toolbar {
    flex-wrap: wrap;
    gap: 6px;
  }

  /* Detection / B2 / share modals — ensure the action row is at the bottom
     with enough thumb-room */
  .modal-overlay button.btn-primary {
    min-height: 44px;
  }
}

@media (max-width: 480px) {
  /* Even tighter on tiny phones — drop padding further */
  .modal-overlay > div { padding: 12px !important; }
  .modal-overlay .modal-row { margin-bottom: 8px; }
  /* Hide some non-essential decorative items */
  .page-header-kicker { display: none; }
  .page-header-card { padding: 12px 14px !important; margin-bottom: 12px !important; }
}
/* ─────────────────────────────────────────────────────────────────────── */


/* ── button-hierarchy-marker (2026-05-28): unified button interaction ──────
   Consistent shape + hover/active feel across every .btn in the portal.
   Targets transform/shadow/radius/weight — properties individual buttons
   don't set inline — so it applies uniformly without touching their
   per-button colors. */
.btn:hover:not(:disabled){ transform:translateY(-1px); box-shadow:0 4px 12px rgba(0,0,0,0.28); }
.btn:active:not(:disabled){ transform:translateY(0); box-shadow:none; }

/* Canonical primary CTA — filled cyan→green. Use class="btn btn-primary".
   Selectors raised to button.btn-primary / a.btn-primary / .btn.btn-primary
   so they beat the existing high-specificity !important button rules. */
.btn.btn-primary, button.btn-primary, a.btn-primary{
  background:linear-gradient(135deg,#00e5ff,#00ff9d) !important;
  color:#001218 !important;
  border:0 !important;
  font-weight:800 !important;
  box-shadow:0 6px 16px rgba(0,229,255,0.28), inset 0 1px 0 rgba(255,255,255,0.35) !important;
}
.btn.btn-primary:hover:not(:disabled), button.btn-primary:hover:not(:disabled), a.btn-primary:hover:not(:disabled){
  filter:brightness(1.05);
  transform:translateY(-1px);
  color:#001218 !important;
  box-shadow:0 10px 22px rgba(0,229,255,0.42), inset 0 1px 0 rgba(255,255,255,0.45) !important;
}

/* Keep the tight player toolbar from lifting (would jitter the dense bar). */
#player-bar .btn:hover:not(:disabled){ transform:none; box-shadow:none; }
