/* hidden means hidden. Several components set display:grid/flex, and an author
   display rule beats the browser's own [hidden] - so nine elements the script
   had hidden stayed on screen, among them a 78% black layer over every wall
   tile that made the live picture look dim. One rule instead of a patch per
   component. */
[hidden]{display:none !important}

:root{
  --bg:#070c12;
  --ink:#eef4fa;
  --ink2:#b4c3d2;
  --ink3:#7e93a6;
  --accent:#7ad4ff;
  --accent-2:#a78bfa;
  --accent-ink:#041018;
  --ok:#3ee0a0;
  --warn:#f5c451;
  --bad:#ff7a88;
  --glass:rgba(14, 22, 34, .52);
  --glass-2:rgba(18, 30, 44, .38);
  --glass-strong:rgba(10, 16, 26, .72);
  --hair:rgba(255,255,255,.14);
  --hair-hi:rgba(255,255,255,.28);
  --inset:inset 0 1px 0 rgba(255,255,255,.16);
  --blur:20px;
  --sat:1.4;
  --radius:18px;
  --font:"Vazirmatn","Segoe UI",Tahoma,Arial,sans-serif;
  --mono:ui-monospace,"Cascadia Mono",Consolas,monospace;
  --tap:44px;
  --dock-h:64px;
}
*{box-sizing:border-box}
html,body{height:100%}
html{color-scheme:dark}
body{
  margin:0;color:var(--ink);font-family:var(--font);font-size:15px;line-height:1.7;
  font-weight:400;
  background:var(--bg);
  min-height:100dvh;
  padding-bottom:calc(var(--dock-h) + env(safe-area-inset-bottom));
  -webkit-tap-highlight-color:transparent;
  touch-action:manipulation;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
}
.aura{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(900px 520px at 88% -8%, rgba(90, 170, 220, .22), transparent 58%),
    radial-gradient(700px 480px at -12% 108%, rgba(140, 90, 210, .16), transparent 55%),
    radial-gradient(500px 360px at 50% 40%, rgba(40, 80, 110, .08), transparent 60%);
}
#app,#lock,.drawer,.focus,.toasts{position:relative;z-index:1}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:10px}
.kv{font-family:var(--mono);font-size:.78rem;color:var(--ink2)}
.grow{flex:1 1 auto}
.err{color:var(--bad);font-size:.82rem;min-height:1.1em;margin:0}
button.talk{
width:100%;margin:8px 0;padding:10px;border-radius:10px;border:1px solid var(--hair);
  background:rgba(0,0,0,.25);color:inherit;font:inherit;touch-action:none}
button.talk[disabled]{opacity:.45}
button.talk.live{background:#b3261e;color:#fff;border-color:#b3261e;font-weight:800}
.hint{font-size:.78rem;line-height:1.7;color:var(--ink3);margin:6px 0}
.rowlabel{font-size:.76rem;color:var(--ink3);font-weight:700;margin:14px 0 6px}
.skip{position:absolute;inset-inline-start:-999px;top:8px;background:var(--accent);color:var(--accent-ink);
  padding:8px 12px;border-radius:8px;z-index:200;font-weight:800}
.skip:focus{inset-inline-start:8px}

.glass{
  background:var(--glass);
  border:1px solid var(--hair);
  box-shadow:var(--inset), 0 18px 48px rgba(0,0,0,.28);
  backdrop-filter:blur(var(--blur)) saturate(var(--sat));
  -webkit-backdrop-filter:blur(var(--blur)) saturate(var(--sat));
}

button,.btn{
  font:inherit;border:1px solid var(--hair);background:rgba(255,255,255,.06);color:var(--ink);
  border-radius:12px;padding:9px 14px;cursor:pointer;font-weight:600;min-height:40px;
  display:inline-flex;align-items:center;justify-content:center;gap:6px;text-decoration:none;
  box-shadow:var(--inset);
}
button:hover:not(:disabled),.btn:hover{background:rgba(255,255,255,.12);border-color:var(--hair-hi)}
button:disabled{opacity:.4;cursor:not-allowed}
button.primary{background:linear-gradient(180deg,#9ae0ff,#4cc2ff);color:var(--accent-ink);
  border-color:transparent;font-weight:800;box-shadow:inset 0 1px 0 #fff8, 0 8px 22px rgba(76,194,255,.25)}
button.primary:hover:not(:disabled){filter:brightness(1.06)}
button.ghost{background:transparent;box-shadow:none}
button.danger{border-color:rgba(255,122,136,.45);color:#ffc4cb;background:rgba(255,80,90,.08)}
button.danger:hover:not(:disabled){background:rgba(255,80,90,.18)}
button.wide{width:100%}
.seg{display:inline-flex;flex-wrap:wrap;background:rgba(0,0,0,.25);border:1px solid var(--hair);
  border-radius:12px;padding:3px;gap:3px}
.seg.wrap{display:flex}
.seg button{border:0;background:transparent;padding:7px 11px;border-radius:9px;font-size:.82rem;
  color:var(--ink2);min-height:36px;box-shadow:none}
.seg button[aria-pressed=true]{background:rgba(122,212,255,.9);color:var(--accent-ink);font-weight:800}
input,select{
  width:100%;padding:11px 12px;border:1px solid var(--hair);border-radius:12px;
  background:rgba(4,10,16,.45);color:var(--ink);font:inherit;
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
}
input[type=range]{padding:0;height:28px;accent-color:var(--accent);background:transparent;border:0;backdrop-filter:none}
input:focus,select:focus{border-color:var(--accent);outline:none}
label{display:block;font-size:.8rem;color:var(--ink2);margin:10px 0 5px;font-weight:600}
.chk{display:inline-flex;align-items:center;gap:7px;font-size:.84rem;margin:0;cursor:pointer;white-space:nowrap}
.chk input{width:auto;accent-color:var(--accent);backdrop-filter:none}
.pw{position:relative}
.pw input{padding-inline-end:60px}
.pw .toggle{position:absolute;inset-inline-end:5px;inset-block-start:5px;padding:6px 10px;font-size:.74rem;min-height:0}

.lock{position:fixed;inset:0;display:grid;place-items:center;padding:20px;z-index:100}
.lock[hidden]{display:none}
.lockcard{width:min(400px,100%);border-radius:22px;padding:26px}
.lockcard h1{margin:0 0 4px;font-size:1.25rem}
.lockcard p{margin:0 0 14px;color:var(--ink3);font-size:.84rem}
.or{display:flex;flex-direction:column;align-items:stretch;gap:10px;margin-top:16px}
.or>span{text-align:center;color:var(--ink3);font-size:.78rem;position:relative}
.sso, .google{
  display:flex;align-items:center;justify-content:center;min-height:var(--tap);
  border-radius:12px;background:rgba(255,255,255,.94);color:#202124;
  text-decoration:none;font-weight:700;border:1px solid var(--hair-hi);
}
.sso:hover, .google:hover{filter:brightness(.97)}
.storage{display:flex;align-items:center;gap:8px;min-width:132px;max-width:220px}
.storage-bar{flex:1;height:6px;border-radius:99px;background:rgba(255,255,255,.12);overflow:hidden;min-width:64px}
.storage-bar i{display:block;height:100%;width:0;background:linear-gradient(90deg,var(--accent),var(--ok));border-radius:inherit;transition:width .35s ease}
.storage.warn .storage-bar i{background:var(--warn)}
.storage.full .storage-bar i{background:var(--bad)}
.plans{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;padding:4px 4px 20px}
.plan-card{padding:16px;border-radius:18px}
.plan-card b{display:block;font-size:1.05rem}
.plan-card .kv{margin:6px 0 12px}
.plan-card.on{border-color:rgba(122,212,255,.55);box-shadow:0 0 0 1px rgba(122,212,255,.35)}
.locklogo{width:48px;height:48px;border-radius:14px;background:rgba(122,212,255,.12);
  border:1px solid var(--hair);display:grid;place-items:center;margin-bottom:14px;color:var(--accent)}

.top{
  display:flex;align-items:center;gap:12px;flex-wrap:nowrap;
  padding:10px clamp(12px,2vw,22px);
  padding-top:max(10px, env(safe-area-inset-top));
  position:sticky;top:0;z-index:40;border-radius:0;
  border-inline:0;border-top:0;
}
.brand{display:flex;align-items:center;gap:10px;flex:0 0 auto}
.brand b{font-size:1rem}
.brand small{display:block;color:var(--ink3);font:600 .72rem/1.2 var(--mono)}
.dot{width:10px;height:10px;border-radius:50%;background:var(--ink3)}
.dot.ok{background:var(--ok);box-shadow:0 0 10px var(--ok)}
.dot.warn{background:var(--warn)}
.dot.bad{background:var(--bad);box-shadow:0 0 12px var(--bad)}
.tabs{display:flex;gap:4px;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;flex:1 1 0;min-width:0}
.tabs::-webkit-scrollbar{display:none}
.tabs button{background:transparent;border:0;color:var(--ink2);padding:8px 13px;border-radius:11px;
  font-size:.86rem;white-space:nowrap;box-shadow:none;min-height:40px}
.tabs button[aria-pressed=true]{background:rgba(255,255,255,.1);color:var(--ink);border:1px solid var(--hair)}
.who{display:flex;align-items:center;gap:8px;margin-inline-start:auto;flex:0 1 auto;min-width:0}
.clock{font:700 .82rem/1 var(--mono);color:var(--ink2);min-width:7.5ch;direction:ltr;text-align:center}
.view{padding:clamp(12px,2vw,20px);padding-bottom:20px}
.bar{display:flex;gap:8px;align-items:center;flex-wrap:nowrap;overflow-x:auto;margin-bottom:14px;scrollbar-width:none}
.bar::-webkit-scrollbar{display:none}
.bar > *{flex:0 0 auto}
.bar-glass{padding:8px;border-radius:16px}
.bar input[type=search]{width:min(280px,100%)}
.bar input[type=date],.bar select{width:auto;min-width:140px}
.empty{color:var(--ink3);text-align:center;padding:40px 20px;display:grid;justify-items:center;gap:12px;border-radius:var(--radius)}
.empty[hidden]{display:none}

.livepill{font:700 .72rem var(--mono);border:1px solid var(--hair);border-radius:99px;padding:4px 10px;
  color:var(--ink3);background:rgba(0,0,0,.25)}
.livepill[data-state=live]{color:var(--ok);border-color:rgba(62,224,160,.4);background:rgba(20,80,55,.35)}
.livepill[data-state=connecting]{color:var(--warn);border-color:rgba(245,196,81,.4)}
.livepill[data-state=degrade]{color:var(--warn);border-color:rgba(245,196,81,.4);background:rgba(80,60,10,.35)}
.livepill[data-state=off]{color:var(--bad);border-color:rgba(255,122,136,.35)}

.alarm-banner{display:flex;align-items:center;gap:12px;padding:10px clamp(12px,2vw,22px);
  border-radius:0;border-inline:0;color:#ffd6d6;background:rgba(90,20,28,.55)}
.alarm-banner[hidden]{display:none}
.pulse-dot{width:10px;height:10px;border-radius:50%;background:var(--bad);
  box-shadow:0 0 0 0 rgba(255,107,107,.7);animation:pulse 1.4s ease-out infinite}
@keyframes pulse{70%{box-shadow:0 0 0 10px transparent}100%{box-shadow:0 0 0 0 transparent}}
body.alarm-on{--bg:#12090c}

.wall{display:grid;gap:12px}
.wall.cols-1{grid-template-columns:1fr}
.wall.cols-2{grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr))}
.wall.cols-3{grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr))}
.wall.cols-4{grid-template-columns:repeat(auto-fit,minmax(min(100%,220px),1fr))}
.wall.cols-5{grid-template-columns:repeat(auto-fit,minmax(min(100%,170px),1fr))}
.wall.cols-6{grid-template-columns:repeat(auto-fit,minmax(min(100%,140px),1fr))}
.wall-heading{grid-column:1/-1;margin:8px 2px 0;font-size:.82rem;color:var(--ink2)}
.tile{
  border:1px solid var(--hair);border-radius:16px;overflow:hidden;background:rgba(8,14,22,.55);
  cursor:pointer;outline:none;box-shadow:var(--inset);
}
.tile:hover,.tile:focus-visible{border-color:var(--hair-hi)}
.tile.selected{border-color:rgba(122,212,255,.7);box-shadow:0 0 0 1px var(--accent)}
.tile.offline{opacity:.72}
.tile.motion{border-color:rgba(245,196,81,.7)}
.tile-view{position:relative;aspect-ratio:4/3;background:#000;display:grid;place-items:center}
.tile-view img{width:100%;height:100%;object-fit:contain;display:block}
.tile.linked{opacity:1;border-color:rgba(245,196,81,.55)}
.tile-badge{position:absolute;inset-block-start:8px;inset-inline-start:8px;background:rgba(4,10,15,.82);
  border:1px solid var(--hair);border-radius:8px;padding:3px 8px;font:700 .7rem var(--mono)}
.tile-badge.bad{color:#ffb3b3}.tile-badge.ok{color:var(--ok)}.tile-badge.warn{color:var(--warn)}
.wall-more{margin:10px 4px 0}
/* Sits opposite the state badge: a camera can look perfect and still be
   mis-set, out of card space, or holding footage the archive never collected. */
.tile-flag{position:absolute;inset-block-start:8px;inset-inline-end:8px;max-width:60%;
  background:rgba(60,45,10,.86);border:1px solid rgba(245,196,81,.45);color:var(--warn);
  border-radius:8px;padding:3px 8px;font:700 .68rem var(--mono);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile-flag[hidden]{display:none}
.tile-off{position:absolute;inset:0;display:grid;place-content:center;justify-items:center;gap:6px;
  background:rgba(4,9,13,.78);text-align:center;padding:14px;font-size:.85rem;color:var(--ink2)}
.tile-off.strip{inset:auto 0 0 0;place-content:center;padding:6px 10px;font-size:.76rem;
  background:linear-gradient(transparent,rgba(4,9,13,.85) 40%);color:var(--warn)}
.tile-foot{display:flex;align-items:center;gap:8px;padding:9px 11px;border-top:1px solid var(--hair);
  background:rgba(10,16,24,.4)}
.tile-foot b{font-size:.88rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile-foot .kv{margin-inline-start:auto;white-space:nowrap}
body.compact .tile-foot{display:none}
body.compact .tile{border-radius:10px}
body.compact .wall{gap:6px}

body.immersive{padding-bottom:0}
body.immersive .top{position:absolute;inset-inline:0;top:0;opacity:0;pointer-events:none}
body.immersive .top:hover,body.immersive .top:focus-within{opacity:1;pointer-events:auto}
body.immersive .dock{display:none}
body.immersive #view-wall{padding:8px;min-height:100dvh}

.fleet{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr));gap:12px}
.fleet-card{
  border-radius:16px;padding:14px;display:flex;flex-direction:column;gap:8px;
  background:var(--glass-2);border:1px solid var(--hair);box-shadow:var(--inset);
  backdrop-filter:blur(16px) saturate(1.3);-webkit-backdrop-filter:blur(16px) saturate(1.3);
}
.fleet-card h3{margin:0;font-size:1rem}
.fleet-card .meta{color:var(--ink3);font-size:.8rem}
.fleet-actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}
.pair-strip{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px}
.pair-chip{
  display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:14px;
  background:var(--glass);border:1px dashed var(--hair);
}
.pair-chip b{font-size:.9rem}
.chip-list{display:flex;flex-wrap:wrap;gap:8px}
.chip{
  display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border-radius:999px;
  border:1px solid var(--hair);background:rgba(255,255,255,.05);
}
.panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.panel-head h2{margin:0}

.tablewrap{overflow-x:auto;border:1px solid var(--hair);border-radius:var(--radius);background:var(--glass-2)}
table{width:100%;border-collapse:collapse;font-size:.87rem;min-width:520px}
th,td{text-align:start;padding:10px 14px;border-bottom:1px solid var(--hair);vertical-align:middle}
thead th{font:600 .7rem var(--mono);letter-spacing:.04em;color:var(--ink3);background:rgba(255,255,255,.04)}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:rgba(255,255,255,.04)}
td .btn,td button{padding:5px 11px;font-size:.78rem;min-height:34px}
.pill{display:inline-block;border:1px solid;padding:3px 9px;border-radius:99px;font-size:.72rem;white-space:nowrap}
.pill.ok{color:var(--ok);border-color:rgba(62,224,160,.4);background:rgba(18,70,50,.35)}
.pill.bad{color:var(--bad);border-color:rgba(255,122,136,.4);background:rgba(70,20,28,.35)}
.pill.warn{color:var(--warn);border-color:rgba(245,196,81,.4);background:rgba(60,45,10,.35)}
.pill.off{color:var(--ink3);border-color:var(--hair)}
.pill.sync{color:var(--accent);border-color:rgba(122,212,255,.4);background:rgba(20,50,70,.35)}

/* Event thumbnails. Small enough that a hundred rows still scroll, large
   enough to tell a person from a passing car without opening the clip. */
td.thumb{width:88px;padding:4px 8px}
td.thumb img{width:80px;height:45px;object-fit:cover;border-radius:6px;display:block;
  border:1px solid var(--hair);cursor:pointer;background:#0a1119}
td.thumb img:hover{border-color:var(--accent)}
th:empty{width:88px}
.row-actions{display:flex;gap:6px;flex-wrap:wrap}
dd.warn{color:var(--warn)}
.kv.warn{color:var(--warn)}
.warnbar{border-inline-start:3px solid var(--warn);color:var(--warn)}
#fwBanner{display:flex;align-items:center;gap:12px;padding:10px clamp(12px,2vw,22px)}
#fwBanner[hidden]{display:none}
#firmwarePanel .bar input[type=text], #firmwarePanel .bar input[type=file]{
  width:auto;min-width:10rem;flex:1 1 10rem;
}
td.warn{color:var(--warn)}

.panel{border-radius:var(--radius);padding:18px}
.panel h2{margin:0 0 12px;font-size:1rem}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,400px),1fr));gap:14px}

.drawer{position:fixed;inset:0;background:rgba(3,7,11,.55);display:grid;place-items:center;
  padding:16px;padding-bottom:max(16px, env(safe-area-inset-bottom));z-index:60;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px)}
.drawer[hidden]{display:none}
.drawer-card{width:min(1080px,100%);max-height:90dvh;display:flex;flex-direction:column;border-radius:20px;overflow:hidden}
.drawer-card.narrow{width:min(520px,100%)}
.drawer-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:14px 18px;border-bottom:1px solid var(--hair)}
.drawer-head h2{margin:0;font-size:1rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.drawer-head button{flex:none;white-space:nowrap}
.drawer-body{padding:16px 18px;overflow:auto}
.drawer-body.block{display:block}
.drawer-foot{display:flex;align-items:center;gap:12px;padding:12px 18px;border-top:1px solid var(--hair)}
.drawer-foot .err{flex:1 1 auto}
#detail .drawer-body{display:grid;grid-template-columns:minmax(0,1fr) min(340px,38%);gap:16px}
@media(max-width:860px){
  #detail .drawer-body{grid-template-columns:1fr}
  /* A phone gets the whole screen, and the picture - with its arrows - stays
     pinned at the top while the settings under it scroll. */
  #detail{padding:0}
  #detail .drawer-card{width:100%;height:100dvh;max-height:100dvh;border-radius:0}
  #detail .drawer-head{padding:8px 12px}
  #detail .drawer-body{padding:0 12px 12px;gap:12px}
  #detail .detail-live{position:sticky;top:0;z-index:4;aspect-ratio:auto;height:min(75vw,58dvh);
    margin:0 -12px;border-radius:0;border-inline:0;border-top:0}
}
.detail-live{position:relative;background:#000;border:1px solid var(--hair);border-radius:14px;overflow:hidden;
  aspect-ratio:4/3;display:grid;place-items:center}
.detail-live img{width:100%;height:100%;object-fit:contain}
.detail-live-actions{position:absolute;inset-inline-end:8px;inset-block-end:8px;display:flex;gap:6px}
.tele{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin:0 0 10px}
.tele div{background:rgba(0,0,0,.25);border:1px solid var(--hair);border-radius:12px;padding:8px 10px}
.tele dt{color:var(--ink3);font-size:.68rem;margin:0}
.tele dd{margin:4px 0 0;font:700 .86rem var(--mono);word-break:break-all}
.syncbox{border:1px dashed var(--hair);border-radius:14px;padding:10px 12px;margin-bottom:12px;background:rgba(0,0,0,.18)}
.path{display:block;direction:ltr;text-align:start;font:700 .72rem var(--mono);color:var(--accent);
  margin:6px 0;word-break:break-all}
/* Pan/tilt arrows laid on the picture, each at the edge it turns toward. Big
   enough for a thumb, dark glass so the view stays readable behind them. */
.ptz-pad{position:absolute;inset:0;pointer-events:none;z-index:2;direction:ltr}
.ptz-pad .pp{pointer-events:auto;position:absolute;width:52px;height:52px;border-radius:50%;
  display:grid;place-items:center;padding:0;font-size:1.15rem;line-height:1;color:#fff;
  background:rgba(6,12,18,.42);border:1px solid rgba(255,255,255,.28);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  touch-action:none;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;
  transition:background .12s,transform .12s,opacity .12s}
.ptz-pad .pp:hover{background:rgba(6,12,18,.62)}
.ptz-pad .pp.held{background:var(--accent);color:#04121b;transform:scale(.94)}
.ptz-pad .pp:disabled{opacity:.35}
.ptz-pad .up{top:10px;left:50%;margin-left:-26px}
.ptz-pad .down{bottom:10px;left:50%;margin-left:-26px}
.ptz-pad .left{left:10px;top:50%;margin-top:-26px}
.ptz-pad .right{right:10px;top:50%;margin-top:-26px}
.ptz-pad .home{top:10px;left:10px;width:44px;height:44px;font-size:1rem}
.ptz-pad .pp-read{position:absolute;top:14px;right:12px;font:700 .72rem var(--mono);color:#fff;
  background:rgba(6,12,18,.5);padding:3px 8px;border-radius:99px;pointer-events:none}
.ptz-pad .pp-read:empty{display:none}
.ptz-pad.busy .pp:not(.home){opacity:.8}
.detail-live-actions{z-index:3}
.detail-live-actions button{min-height:34px;padding:4px 10px;font-size:.76rem;white-space:nowrap;
  background:rgba(6,12,18,.5);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
@media (hover:hover) and (pointer:fine){
  .ptz-pad .pp{opacity:.72}
  .detail-live:hover .ptz-pad .pp,.focus-stage:hover .ptz-pad .pp,.ptz-pad .pp:focus-visible{opacity:1}
}
.presets{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.presets .preset{display:inline-flex;align-items:center;gap:2px}
.presets button{font-size:.78rem;padding:5px 10px;min-height:34px}

.toasts{position:fixed;inset-block-end:calc(var(--dock-h) + 12px);inset-inline-start:16px;
  display:flex;flex-direction:column;gap:8px;z-index:90;pointer-events:none}
.toast{background:var(--glass-strong);border:1px solid var(--hair);border-radius:12px;padding:10px 14px;
  font-size:.85rem;box-shadow:var(--inset),0 12px 34px #000a;max-width:min(90vw,380px);
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);transition:opacity .3s}
.toast.ok{border-color:rgba(62,224,160,.45)}.toast.bad{border-color:rgba(255,122,136,.45)}.toast.warn{border-color:rgba(245,196,81,.45)}

.equip{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));gap:12px}
.equip-card{border:1px solid var(--hair);border-radius:16px;background:var(--glass-2);padding:16px;
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);box-shadow:var(--inset)}
.equip-card.hot{border-color:rgba(255,122,136,.5);background:rgba(60,16,22,.45)}
.equip-card h3{margin:0 0 6px;font-size:1rem}
.equip-card .armed{color:var(--ok);font-weight:800}
.equip-card .triggered{color:var(--bad);font-weight:800}
.equip-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.zones{display:flex;flex-direction:column;gap:6px;margin-top:12px}
.zone{display:flex;align-items:center;gap:8px;background:rgba(0,0,0,.22);border:1px solid var(--hair);border-radius:10px;padding:8px 10px}
.zone b{font-size:.85rem}
.zone .kv{margin-inline-start:auto}
.zone-add{display:flex;gap:8px;margin-top:8px}
.zone-add input{flex:1}

.ext-list{display:flex;flex-direction:column;gap:10px}
.ext{display:flex;align-items:center;gap:12px;padding:12px;border:1px solid var(--hair);border-radius:14px;
  background:rgba(0,0,0,.18)}
.ext b{display:block}
.ext span{color:var(--ink3);font-size:.8rem}

.focus{position:fixed;inset:0;background:#000;z-index:80;display:flex;flex-direction:column}
.focus[hidden]{display:none}
.focus-bar{display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:0;border-inline:0;border-top:0}
.focus-stage{position:relative;flex:1;min-height:0;display:flex}
.focus img{flex:1;width:100%;min-height:0;object-fit:contain;background:#000}
.focus .ptz-pad .pp{width:60px;height:60px;margin-left:-30px;font-size:1.3rem}
.focus .ptz-pad .left,.focus .ptz-pad .right{margin-left:0;margin-top:-30px}
.focus .ptz-pad .home{width:48px;height:48px;margin:0}

.keys{display:grid;gap:8px;margin:0}
.keys div{display:flex;align-items:center;gap:12px;background:rgba(0,0,0,.22);border:1px solid var(--hair);border-radius:10px;padding:8px 12px}
.keys dt{font:700 .8rem var(--mono);min-width:4.5rem;direction:ltr;text-align:center;
  background:rgba(255,255,255,.06);border-radius:8px;padding:4px 8px}
.keys dd{margin:0;color:var(--ink2);font-size:.86rem}

.steps{display:flex;gap:8px;list-style:none;padding:0;margin:0 0 16px;font-size:.78rem;color:var(--ink3)}
.steps li{flex:1;text-align:center;padding:8px 4px;border-radius:10px;border:1px solid var(--hair)}
.steps li.on{color:var(--accent-ink);background:rgba(122,212,255,.85);border-color:transparent;font-weight:800}

.dock{
  display:none;position:fixed;inset-inline:10px;bottom:max(8px, env(safe-area-inset-bottom));
  z-index:45;border-radius:18px;padding:6px;gap:4px;justify-content:space-around;
}
.dock button{flex:1;flex-direction:column;gap:0;border:0;background:transparent;box-shadow:none;
  font-size:.72rem;min-height:var(--tap);color:var(--ink2);padding:6px 4px}
.dock button[aria-pressed=true]{color:var(--accent);background:rgba(122,212,255,.12);border-radius:12px}

.enroll-code {
  font: 700 clamp(22px, 6vw, 32px)/1.2 "Courier New", ui-monospace, monospace;
  letter-spacing: 6px;
  text-align: center;
  padding: 16px 8px;
  margin: 8px 0 4px;
  border-radius: 12px;
  color: var(--accent);
  background: rgba(0,0,0,.3);
  border: 1px dashed var(--hair);
  direction: ltr;
  user-select: all;
  word-break: break-all;
}
.enroll-url {
  font-size: clamp(14px, 3vw, 18px);
  letter-spacing: 0.5px;
  word-break: break-all;
}

.hide-wide{display:none}

@media(max-width:860px){
  .tabs{display:none}
  .dock{display:flex}
  .who .kv,.clock,#kbdBtn,#changePwBtn{display:none}
  .bar input[type=search]{width:100%}
  .hide-narrow{display:none}
  .top{padding-inline:10px}
  body{padding-bottom:calc(var(--dock-h) + 12px + env(safe-area-inset-bottom))}
}

@media(min-width:861px){
  body{padding-bottom:0}
  .dock{display:none}
}

@media(prefers-reduced-transparency:reduce), (prefers-reduced-motion:reduce){
  .glass,.fleet-card,.equip-card,.toast,.lockcard,.drawer,.bar-glass,.tile-badge,input,select{
    backdrop-filter:none;-webkit-backdrop-filter:none;
    background:rgba(14,22,34,.92);
  }
  .aura{display:none}
  *{animation:none!important;transition:none!important}
}

@media(prefers-reduced-motion:reduce){.pulse-dot{animation:none}}

/* One button per configured provider, stacked. */
#ssoButtons{display:flex;flex-direction:column;gap:8px}
.sso{text-align:center}

/* ---- playback ------------------------------------------------------- */
.player{padding:12px;margin-bottom:12px;border-radius:14px}
.player-stage{position:relative;background:#000;border-radius:10px;overflow:hidden;
  display:grid;place-items:center;min-height:320px}
.player-stage img{max-width:100%;max-height:60vh;display:block}
.player-badge{position:absolute;top:10px;inset-inline-start:10px;padding:4px 10px;
  border-radius:999px;background:rgba(0,0,0,.6);color:#e8eff5;font-size:.74rem;
  font-variant-numeric:tabular-nums;direction:ltr}

/* The timeline is the view of the archive that matters: where there is
   footage, where there is not, and where you are. */
.tframe{padding:12px 14px 10px;margin:0 16px 12px;border-radius:14px}
.tframe-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:8px}
.tframe-head b{font-size:.95rem}
.tframe-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}
.tframe-clock{font-variant-numeric:tabular-nums;direction:ltr;unicode-bidi:embed}
.hourstrip{display:grid;grid-template-columns:repeat(24,minmax(0,1fr));gap:2px;margin-bottom:8px}
.hourchip{position:relative;overflow:hidden;min-height:28px;padding:2px 0 6px;border-radius:6px;
  border:1px solid var(--hair);background:transparent;color:var(--ink3);font-size:.62rem;
  font-variant-numeric:tabular-nums;cursor:pointer}
.hourchip b{font-weight:600}
.hourheat{position:absolute;inset-inline-start:0;bottom:0;height:3px;background:var(--accent);opacity:.8}
.hourchip.has{color:var(--ink);border-color:rgba(122,212,255,.28);background:rgba(20,50,70,.28)}
.hourchip.on{color:var(--accent-ink);background:var(--accent);border-color:transparent;font-weight:700}
.hourchip.on .hourheat{background:var(--accent-ink)}
@media(max-width:700px){
  .hourstrip{display:flex;overflow-x:auto}
  .hourchip{flex:0 0 32px}
}
.timeline{position:relative;height:56px;margin:4px 0 4px;border-radius:8px;
  background:var(--panel-2, rgba(0,0,0,.22));border:1px solid var(--line, var(--hair));cursor:pointer;overflow:hidden}
.timeline:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.timeline-track{position:absolute;inset:0}
.timeline-seg{position:absolute;top:18px;bottom:8px;background:var(--accent);
  opacity:.7;border-radius:2px;min-width:1px}
.timeline-seg.partial{opacity:.35;background:var(--ink3)}
.timeline-head{position:absolute;top:0;bottom:0;width:2px;background:#fff;
  pointer-events:none;transform:translateX(-1px);z-index:2}
.timeline-now{position:absolute;top:0;bottom:0;width:1px;background:#ff8a65;
  pointer-events:none;z-index:3;box-shadow:0 0 8px rgba(255,138,101,.55)}
.filelist{margin:0 16px 12px;border-radius:14px;padding:8px 14px 10px}
.filelist summary{cursor:pointer;font-weight:700;list-style:none}
.filelist summary::-webkit-details-marker{display:none}
.filelist .tablewrap{margin-top:8px;background:transparent}
.timeline-tick{position:absolute;top:0;width:1px;background:var(--hair);opacity:.55}
.timeline-tick.major{bottom:0;opacity:.9}
.timeline-tick.minor{height:10px}
.timeline-label{position:absolute;top:2px;font-size:.62rem;color:var(--ink3);
  font-variant-numeric:tabular-nums;transform:translateX(-50%);pointer-events:none;white-space:nowrap}
.tframe-hover{margin:4px 0 0;font-variant-numeric:tabular-nums;min-height:1.2em}
.daystrip{display:flex;gap:6px;padding:0 16px 12px;overflow-x:auto}
.daychip small{display:block;font-size:.64rem;color:var(--ink3);margin-top:2px}
/* Shamsi date buttons and the calendar they open. */
.datebtn{flex-direction:column;align-items:flex-start;gap:0;min-width:128px;padding:4px 12px;line-height:1.35}
.datebtn small{font-size:.64rem;color:var(--ink3);font-weight:600}
.datebtn span{font-size:.84rem;white-space:nowrap}
.datebtn[aria-expanded=true]{border-color:rgba(122,212,255,.6);background:rgba(20,50,70,.45)}
.jcal{position:fixed;z-index:90;width:min(300px,calc(100vw - 12px));padding:10px;border-radius:16px;
  background:rgba(10,18,28,.96);box-shadow:0 18px 40px rgba(0,0,0,.45)}
.jcal-head{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-bottom:6px}
.jcal-head b{font-size:.92rem}
.jcal-head button{min-width:40px;font-size:1.2rem}
.jcal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:3px}
.jcal-grid .wd{text-align:center;font-size:.68rem;color:var(--ink3);padding:2px 0 4px}
.jcal-grid .day{position:relative;min-height:36px;padding:0;border-radius:10px;font-size:.84rem;
  background:transparent;box-shadow:none;border-color:transparent}
.jcal-grid .day.today{border-color:var(--hair-hi)}
.jcal-grid .day.on{background:var(--accent);color:var(--accent-ink);font-weight:800}
.jcal-grid .day.has::after,.dotmark{content:"";display:inline-block;width:5px;height:5px;border-radius:50%;
  background:var(--ok)}
.jcal-grid .day.has::after{position:absolute;bottom:4px;left:50%;margin-left:-2.5px}
.jcal-grid .day.on.has::after{background:var(--accent-ink)}
.jcal-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:8px}
.jcal-foot .kv{font-size:.7rem;display:inline-flex;align-items:center;gap:5px}
.daychip{flex:1;min-width:72px;border:1px solid var(--hair);background:var(--glass-2);border-radius:12px;
  padding:8px 6px;text-align:center;cursor:pointer;color:inherit}
.daychip b{display:block;font-size:.78rem}
.daychip span{display:block;font-size:.68rem;color:var(--ink3);margin-top:4px}
.daychip .heat{height:4px;border-radius:99px;background:rgba(122,212,255,.15);margin-top:6px;overflow:hidden}
.daychip .heat i{display:block;height:100%;background:var(--accent);width:0}
.daychip.on{border-color:rgba(122,212,255,.55);background:rgba(20,50,70,.35)}
/* Map on one side, every camera with its name on the other; on a phone the
   list follows the map. */
/* The list takes the first column - the right-hand one in this right-to-left page. */
.mapwrap{display:grid;grid-template-columns:300px minmax(0,1fr);gap:12px;margin:12px 16px;align-items:start}
.maptray{order:-1;padding:10px 12px;border-radius:16px;max-height:calc(min(62vh,560px) + 48px);overflow:auto}
@media(max-width:860px){
  .mapwrap{grid-template-columns:1fr;margin:8px}
  .maptray{order:0;max-height:none}
}
.mapcol{display:flex;flex-direction:column;gap:8px;min-width:0}
.maphint{display:flex;align-items:center;gap:8px;min-height:40px;padding:4px 10px;border-radius:12px;
  font-size:.8rem;color:var(--ink2);background:rgba(0,0,0,.18);border:1px solid var(--hair)}
.maphint span{flex:1 1 auto;min-width:0}
.maphint{scroll-margin-top:84px}
.maphint.on{color:var(--ink);border-color:rgba(122,212,255,.6);background:rgba(20,50,70,.5)}
.maphint button{min-height:32px;padding:4px 12px}
.traycam{display:grid;grid-template-columns:auto minmax(0,1fr);gap:4px 8px;align-items:center;
  padding:8px;border-radius:12px;border:1px solid transparent}
.traycam + .traycam{margin-top:4px}
.traycam.sel,.traycam.picking{border-color:rgba(122,212,255,.55);background:rgba(20,50,70,.35)}
.traycam .nodename{font-size:.9rem}
.traywhere,.trayacts{grid-column:2}
.traywhere{font-size:.72rem;color:var(--ink3)}
.trayacts{display:flex;flex-wrap:wrap;gap:6px}
.trayacts button,.pinpop .acts button{min-height:34px;padding:4px 10px;font-size:.78rem}
.namefield{width:100%;min-height:36px;padding:5px 10px;font-weight:700}
.namefield[readonly]{background:transparent;border-color:transparent;box-shadow:none;padding-inline:0}
.sitemap{position:relative;height:min(62vh,560px);margin:0;border-radius:16px;overflow:hidden;
  touch-action:manipulation;
  background:
    linear-gradient(rgba(255,255,255,.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.04) 1px, transparent 1px),
    var(--glass-2);
  background-size:40px 40px, 40px 40px, auto}
.sitemap.has-plan{
  background-color:#0a1218;
  background-repeat:no-repeat;
  background-position:center;
  background-size:contain}
.sitemap.picking{cursor:crosshair;outline:2px dashed rgba(122,212,255,.75);outline-offset:-3px}
.mapempty{position:absolute;inset:0;display:grid;place-items:center;margin:0;padding:20px;text-align:center;
  color:var(--ink3);font-size:.85rem;pointer-events:none}
/* A pin is a button for the keyboard, not a boxed one to the eye. */
/* The dot, not the label, marks the spot that was tapped. */
.mappin{position:absolute;transform:translate(-50%,-9px);cursor:grab;min-width:28px;min-height:0;
  padding:0;border:0;background:none;box-shadow:none;display:block;text-align:center;color:var(--ink);
  z-index:2;user-select:none;-webkit-user-select:none;touch-action:none}
.mappin:hover:not(:disabled){background:none}
.mappin .dot{display:block;width:18px;height:18px;border-radius:50%;margin:0 auto 4px;border:2px solid #fff;
  background:var(--accent);box-shadow:0 2px 8px rgba(0,0,0,.5)}
.mappin.ok .dot{background:var(--ok)}
.mappin.warn .dot{background:var(--warn)}
.mappin.bad .dot{background:var(--bad)}
.mappin.node .dot{border-radius:5px;background:var(--accent-2)}
.mappin b{display:block;font-size:.74rem;background:rgba(0,0,0,.62);padding:2px 8px;border-radius:8px;white-space:nowrap}
.mappin.sel .dot{box-shadow:0 0 0 5px rgba(122,212,255,.45)}
.mappin.sel b{background:rgba(20,60,85,.9)}
.mappin.dragging{cursor:grabbing;z-index:5}
.mappin.dragging .dot{transform:scale(1.3)}
.mappin:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:8px}
.pinpop{position:absolute;z-index:6;width:min(240px,calc(100% - 12px));padding:10px;border-radius:14px;
  display:grid;gap:6px;background:rgba(10,18,28,.92)}
.pinpop .meta{font-size:.72rem;color:var(--ink3)}
.pinpop .acts{display:flex;flex-wrap:wrap;gap:6px}
.sensor-read{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.sensor-read div{flex:1;min-width:90px;background:rgba(0,0,0,.22);border:1px solid var(--hair);border-radius:10px;padding:8px}
.sensor-read dt{margin:0;font-size:.68rem;color:var(--ink3)}
.sensor-read dd{margin:2px 0 0;font:700 .95rem var(--mono)}
.sensor-read .over{color:var(--bad)}
.spark-wrap{flex:1 0 100%;min-width:160px;margin-top:4px}
.spark-wrap .spark{display:block;width:100%;height:32px;color:var(--accent)}
.delay-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:8px}
.delay-row label{font-size:.72rem;color:var(--ink3);display:flex;gap:4px;align-items:center}
.delay-row input{width:4.5rem}
.entry{color:var(--warn);font-weight:700}
.exit{color:var(--accent);font-weight:700}
.io-state{font-weight:800;margin-top:6px}

/* --- spacing utilities -----------------------------------------------------
 * These exist because the console sets its Content-Security-Policy to
 * style-src 'self', and a browser enforcing that discards every style="..."
 * attribute on the page. Thirty-eight of them were being dropped silently: the
 * console rendered with the wrong spacing in a dozen places and the only trace
 * was a wall of CSP errors in a console nobody had open. Naming the handful of
 * spacings we actually use costs one class each and keeps the policy strict,
 * which is the right trade for a page that shows live camera feeds.
 */
.mt-0 { margin-top: 0; }
.mt-8 { margin-top: 8px; }
.mt-12 { margin-top: 12px; }
.mt-14 { margin-top: 14px; }
.mt-16 { margin-top: 16px; }
.mb-12 { margin-bottom: 12px; }
.mb-16 { margin-bottom: 16px; }
.m-0 { margin: 0; }
.m-inset { margin: 12px 16px; }
.p-head { padding: 10px 14px 0; }

/* ---- short screens ------------------------------------------------------
   A laptop with the browser docked, a phone on its side, a console pane: on a
   window 300-600 px tall the header, a wrapping toolbar and a floating tab dock
   used up everything above the first picture, so the wall showed no video at
   all until scrolled. One header row, one toolbar row that scrolls sideways,
   and the tabs back in the header instead of floating over the tiles. */
@media (max-height: 800px) {
  .top{padding-block:4px;gap:8px}
  .brand small{display:none}
  .view{padding-block:8px}
  .bar{margin-bottom:8px}
  .bar-glass{padding:4px}
  .bar input[type=search]{width:170px}
  /* Status first, so it is never the part scrolled out of sight. */
  .bar .livepill,.bar #wallCount{order:-1}
  .bar select{min-width:0}
  .top button,.bar button,.bar select,.bar input,.tabs button{min-height:34px;padding-block:4px}
}
@media (max-height: 800px) and (max-width: 860px) {
  .tabs{display:flex;flex:1 1 0;min-width:0}
  .dock{display:none}
  body{padding-bottom:0}
}

/* An image with nothing to show yet is a blank frame, not a broken-image icon. */
#detailImg:not([src]),#focusImg:not([src]),.tile-view img:not([src]){visibility:hidden}

/* The header meter's figure is hidden on narrow screens with the other .who
   labels, which left a bare 0% bar that read as a broken element. The storage
   tab shows the same figure in full. */
@media (max-width: 860px), (max-height: 800px) {
  .storage{display:none}
}

/* Small tiles: the camera's name keeps its place and the details give way,
   rather than the other way round. */
.tile-foot b{flex:1 1 auto;min-width:0}
.tile-foot .kv{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}

/* A tab strip that scrolls sideways fades out at its end, so a clipped
   letter of the next tab reads as "more this way", not as a glitch. */
.tabs{-webkit-mask-image:linear-gradient(to left,transparent 0,#000 28px);mask-image:linear-gradient(to left,transparent 0,#000 28px)}

/* Somebody at the door: fixed above everything, impossible to miss, and gone
   with one click either way. */
.ring{position:fixed;inset-inline:12px;top:12px;z-index:60;display:flex;align-items:center;gap:10px;
  padding:12px 14px;border-radius:14px;border:1px solid rgba(255,196,0,.6);
  background:rgba(40,30,0,.92);color:#fff;font-weight:700;box-shadow:0 8px 30px rgba(0,0,0,.45)}
.ring #ringText{flex:1}
.ring-bell{font-size:1.4rem;animation:ring-shake 1s ease-in-out infinite}
@keyframes ring-shake{0%,100%{transform:rotate(0)}20%{transform:rotate(14deg)}40%{transform:rotate(-12deg)}60%{transform:rotate(8deg)}}
@media (prefers-reduced-motion: reduce){.ring-bell{animation:none}}
