:root{
  --bg:#04070e; --bg2:#070c16; --panel:rgba(14,22,36,.78); --panel-solid:#0c1422;
  --line:#1b2c44; --line2:#25405f;
  --text:#e8f0fb; --muted:#8ea6c4; --dim:#5b7089;
  --nato:#2f6fe0; --nato2:#4d8cff; --cyan:#37e0ff; --scan:#37e0ff;
  --green:#39d98a; --amber:#f2b43b; --red:#ff3b4e;
  --mono:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,monospace;
}
*{box-sizing:border-box}
html,body{margin:0}
body{
  background:
    radial-gradient(1200px 600px at 78% -10%, rgba(47,111,224,.14), transparent 60%),
    radial-gradient(900px 500px at 10% 110%, rgba(55,224,255,.08), transparent 55%),
    linear-gradient(#04070e,#04070e);
  color:var(--text); font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;
  line-height:1.5; min-height:100vh;
}
/* subtle moving scanlines for the ops-console feel */
body::after{content:"";position:fixed;inset:0;pointer-events:none;z-index:9;
  background:repeating-linear-gradient(0deg,rgba(255,255,255,.018) 0 1px,transparent 1px 3px);
  mix-blend-mode:overlay;opacity:.5;animation:scan 8s linear infinite}
@keyframes scan{to{background-position:0 240px}}
h1,h3{margin:0}
.muted{color:var(--muted)} .mono{font-family:var(--mono);font-size:.85em}

/* HEADER */
.top{display:flex;justify-content:space-between;align-items:center;gap:16px;
  padding:14px 22px;border-bottom:1px solid var(--line);
  background:linear-gradient(180deg,rgba(9,15,26,.96),rgba(6,10,18,.9));backdrop-filter:blur(6px);
  position:sticky;top:0;z-index:20}
.brand{display:flex;align-items:center;gap:14px}
.logo{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;
  border:1.5px solid var(--nato2);color:var(--cyan);font-size:20px;
  box-shadow:0 0 18px rgba(55,224,255,.35),inset 0 0 12px rgba(47,111,224,.3);animation:pulseLogo 3s ease-in-out infinite}
@keyframes pulseLogo{50%{box-shadow:0 0 26px rgba(55,224,255,.6),inset 0 0 16px rgba(47,111,224,.5)}}
.top h1{font-size:19px;letter-spacing:2.5px;font-weight:700}
.sub{margin:2px 0 0;color:var(--muted);font-size:12px;letter-spacing:.5px}
.controls{display:flex;gap:10px;align-items:center}
.btn{background:rgba(27,44,68,.7);color:var(--text);border:1px solid var(--line2);
  padding:9px 16px;border-radius:8px;cursor:pointer;font-size:13px;letter-spacing:.5px;
  transition:.15s;font-weight:600}
.btn:hover{border-color:var(--cyan);box-shadow:0 0 14px rgba(55,224,255,.25)}
.btn.primary{background:linear-gradient(180deg,var(--nato2),var(--nato));border-color:var(--nato2);color:#fff;
  box-shadow:0 0 16px rgba(47,111,224,.4)}

.disclaimer{background:linear-gradient(90deg,rgba(30,22,10,.9),rgba(20,16,10,.7));color:#f0cf9a;
  border-bottom:1px solid #3a2c16;padding:8px 22px;font-size:12px;text-align:center;letter-spacing:.3px}

main{max-width:1240px;margin:0 auto;padding:22px}

/* TOP GRID: radar + threat */
.opsgrid{display:grid;grid-template-columns:340px 1fr;gap:18px;margin-bottom:18px}

/* ===== SECTOR SCOPE =========================================================
   A tactical-display read, built from our own primitives. The angular axis is a real
   bearing; the RADIAL axis is detection CONFIDENCE and is labelled as such on the face,
   because the fused stream carries no range for most sources and a plausible-looking
   kilometre ring would be a measurement the system never took. */
.scope{border:1px solid var(--line2);border-radius:14px;background:var(--panel);
  backdrop-filter:blur(6px);overflow:hidden}
/* ⛔The panel clips overflow (rounded corners over the header/footer bars), so a face wider
   than panel_inner_width / 1.5 will have its outboard data blocks sliced off at the edge.
   Verified 2026-08-08: at 320px inside a 460px panel the "BRG" prefix was cut in half. */
.scope-hd,.scope-ft{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
  padding:9px 14px;font:600 10.5px var(--mono);letter-spacing:1px;color:var(--muted)}
.scope-hd{border-bottom:1px solid var(--line);background:rgba(8,14,24,.7)}
.scope-ft{border-top:1px solid var(--line);background:rgba(8,14,24,.7);justify-content:space-between}
.scope-tag{color:var(--cyan);font-weight:700}
.scope-axis{cursor:help;border-bottom:1px dotted var(--line2)}
.scope-live{margin-left:auto;color:var(--green);display:flex;align-items:center;gap:6px}
.scope-live i{width:6px;height:6px;border-radius:50%;background:var(--green);
  box-shadow:0 0 8px var(--green);animation:blink 1.6s steps(2) infinite}
.scope-key{display:flex;align-items:center;gap:6px}
.scope-key i{width:9px;height:9px;display:inline-block}
.scope-key i.k-auth{border-radius:50%;background:var(--green);box-shadow:0 0 7px var(--green)}
.scope-key i.k-unk{background:var(--red);box-shadow:0 0 7px var(--red);transform:rotate(45deg)}

.scope-face{position:relative;width:100%;max-width:420px;aspect-ratio:1;margin:14px auto;
  border-radius:50%;
  background:radial-gradient(circle,rgba(10,32,30,.85),rgba(3,8,12,.96) 72%);
  box-shadow:0 0 46px rgba(55,224,255,.13),inset 0 0 44px rgba(0,0,0,.65)}
.scope-face svg{position:absolute;top:0;left:-25%;width:150%;height:100%;overflow:visible}
/* Contacts arrive as a complete <svg> swapped into this wrapper. It must be a div: htmx
   creates nodes in the XHTML namespace, and bare SVG children land as unknown HTML elements
   that measure 0x0 and paint nothing, silently. */
.trkwrap{position:absolute;inset:0;pointer-events:none}
.scope-grid .band{fill:none;stroke:rgba(55,224,255,.16);stroke-width:1}
.scope-grid .cross{stroke:rgba(55,224,255,.12);stroke-width:1}
.scope-grid .tick{stroke:rgba(55,224,255,.30);stroke-width:1}
.scope-grid .tick.major{stroke:rgba(55,224,255,.70);stroke-width:1.6}
.scope-grid .tlab{fill:#a8c8e6;font:700 10px var(--mono)}
.scope-grid .bandlab{fill:#7f9dbd;font:600 8.5px var(--mono)}
.scope-grid .hub{fill:var(--cyan)}

/* Sweep: a leading edge with an afterglow trailing behind it, the way a real scope decays. */
.sweep{position:absolute;inset:0;border-radius:50%;pointer-events:none;
  background:conic-gradient(from 0deg,
    rgba(55,224,255,.42) 0deg,rgba(55,224,255,.14) 26deg,
    rgba(55,224,255,.04) 62deg,transparent 104deg,transparent 360deg);
  animation:spin 4.6s linear infinite;mix-blend-mode:screen}
.sweep::before{content:"";position:absolute;inset:0;border-radius:50%;
  background:linear-gradient(to top,transparent 50%,rgba(160,246,255,.85) 50%);
  clip-path:polygon(50% 50%,49.4% 0,50.6% 0)}
@keyframes spin{to{transform:rotate(360deg)}}

/* Contacts. Diamond = unregistered/unclassified, circle = authorised traffic (APP-6 grammar,
   drawn from our own geometry). A HOLLOW symbol means the bearing is a layout placeholder. */
.scope-trk .sym{fill:var(--green);stroke:none;filter:drop-shadow(0 0 6px var(--green))}
.scope-trk .trk.hostile .sym{fill:var(--red);filter:drop-shadow(0 0 8px var(--red));
  animation:blink 1s steps(2) infinite}
.scope-trk .trk.est .sym{fill:none;stroke:var(--green);stroke-width:1.6;stroke-dasharray:3 2.5}
.scope-trk .trk.est.hostile .sym{stroke:var(--red);fill:none}
.scope-trk .pulse{fill:none;stroke:var(--red);stroke-width:1;opacity:.9;
  transform-box:fill-box;transform-origin:center;animation:ripple 1.6s ease-out infinite}
.scope-trk .leader{stroke:rgba(168,200,230,.45);stroke-width:1;stroke-dasharray:2 2}
.scope-trk .blk{fill:#cfe3f7;font:700 9.5px var(--mono);letter-spacing:.4px}
.scope-trk .blk.sub{fill:#9db9d6;font-weight:600;font-size:8.5px}
.scope-trk .trk.hostile .blk{fill:#ffc2c8}
@keyframes ripple{from{transform:scale(.55);opacity:.85}to{transform:scale(2.3);opacity:0}}
@keyframes blink{50%{opacity:.4}}
@media(prefers-reduced-motion:reduce){
  .sweep,.scope-trk .pulse,.scope-trk .trk.hostile .sym,.scope-live i{animation:none}
}
/* Hero variant: same component, constrained so it sits under the CTA without pushing the
   honest statement below the fold. */
.heroscope{max-width:460px;margin:0;text-align:left}
.heroscope .scope-face{max-width:288px;margin:10px auto}
.heroscope .scope-ft{font-size:9.5px;letter-spacing:.6px}
@media(max-width:820px){.heroscope .scope-face{max-width:248px}
  .heroscope .scope-hd,.heroscope .scope-ft{font-size:9px;gap:8px}}

/* THREAT PANEL */
.threat-panel{border:1px solid var(--line2);border-radius:14px;padding:22px 26px;
  background:var(--panel);backdrop-filter:blur(6px);display:flex;flex-direction:column;justify-content:center;
  position:relative;overflow:hidden;transition:.4s}
.threat-panel.t-high{border-color:var(--red);box-shadow:0 0 0 1px var(--red) inset,0 0 60px -12px var(--red);
  animation:alarm 1.1s ease-in-out infinite}
.threat-panel.t-medium{border-color:var(--amber);box-shadow:0 0 0 1px var(--amber) inset,0 0 40px -18px var(--amber)}
@keyframes alarm{50%{box-shadow:0 0 0 1px var(--red) inset,0 0 90px -6px var(--red)}}
.tp-top{display:flex;align-items:baseline;gap:16px}
.tp-label{color:var(--muted);font:600 11px var(--mono);letter-spacing:2px}
.tp-value{font-size:56px;font-weight:800;line-height:1;letter-spacing:1px}
.tp-value.t-high{color:var(--red);text-shadow:0 0 24px rgba(255,59,78,.6)}
.tp-value.t-medium{color:var(--amber)} .tp-value.t-low,.tp-value.t-none{color:var(--green)}
.tp-zone{margin-top:12px;font-weight:600;letter-spacing:.5px}
.tp-rationale{margin-top:4px;color:#cfe0f4} .tp-sources{margin-top:6px;color:var(--muted);font-size:13px}
.tp-score{margin-top:14px;height:8px;border-radius:6px;background:rgba(255,255,255,.06);overflow:hidden}
.tp-score > i{display:block;height:100%;border-radius:6px;transition:width .5s}

/* KPI TILES */
.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:16px}
.kpi{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:15px 18px;backdrop-filter:blur(4px)}
.k-val{font-size:24px;font-weight:700;font-family:var(--mono)} .k-lab{color:var(--muted);font-size:12px;margin-top:3px;letter-spacing:.4px}

/* SOURCE STATUS */
.sources{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:18px}
.src{display:flex;align-items:center;gap:9px;background:var(--panel);border:1px solid var(--line);
  border-radius:10px;padding:8px 14px;font-size:13px;backdrop-filter:blur(4px)}
.src .dot{width:9px;height:9px;border-radius:50%;background:#31465f}
.src.on .dot{background:var(--green);box-shadow:0 0 10px var(--green);animation:led 1.6s ease-in-out infinite}
@keyframes led{50%{opacity:.45}}
.src .s-seen{color:var(--muted);font-size:11px;font-family:var(--mono)}

/* PANELS + TABLE */
.grid2{display:grid;grid-template-columns:1.35fr 1fr;gap:16px}
.card{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:16px 18px;backdrop-filter:blur(4px)}
.card h3{font:700 12px var(--mono);color:var(--cyan);text-transform:uppercase;letter-spacing:2px;margin-bottom:10px;opacity:.85}
table{width:100%;border-collapse:collapse;font-size:12.5px}
th{text-align:left;color:var(--muted);font-weight:600;padding:6px 8px;border-bottom:1px solid var(--line);letter-spacing:.5px}
td{padding:7px 8px;border-bottom:1px solid rgba(27,44,68,.5);vertical-align:top} td.detail{color:#cfe0f4}
tbody tr{animation:fadein .4s} @keyframes fadein{from{opacity:0;transform:translateY(-3px)}}
.tag{font:600 10px var(--mono);padding:2px 8px;border-radius:6px;background:rgba(27,44,68,.8);border:1px solid var(--line2)}
.t-rf{color:#79c0ff}.t-acoustic{color:#d2a8ff}.t-telemetry{color:#7ee787}.t-public_feed{color:#37e0ff}.t-human{color:#ffb761}
.flag{color:var(--red);font:700 10px var(--mono);border:1px solid var(--red);border-radius:5px;padding:0 5px;margin-left:4px;
  box-shadow:0 0 8px rgba(255,59,78,.4)}
.live-tag{color:var(--cyan);font:700 9px var(--mono);border:1px solid var(--cyan);border-radius:4px;padding:0 4px;margin-left:4px}

.alert{border:1px solid var(--line);border-left:4px solid var(--muted);border-radius:8px;padding:10px 12px;margin-bottom:9px;background:rgba(7,12,22,.7)}
.alert.a-high{border-left-color:var(--red);box-shadow:0 0 20px -8px var(--red)}
.alert.a-medium{border-left-color:var(--amber)}
.a-head{font-size:13px} .a-body{color:var(--muted);font-size:12.5px;margin-top:3px}

.report{margin-top:16px} .row{display:flex;gap:10px;flex-wrap:wrap}
.row select,.row input{background:var(--bg2);color:var(--text);border:1px solid var(--line2);border-radius:8px;padding:9px 12px;font-size:14px}
.row input{flex:1;min-width:220px}
.foot{color:var(--muted);text-align:center;font-size:12px;padding:22px;border-top:1px solid var(--line);margin-top:20px;letter-spacing:.4px}

/* full-screen red flash on new HIGH escalation */
#flash{position:fixed;inset:0;pointer-events:none;z-index:50;background:radial-gradient(circle,transparent 40%,rgba(255,59,78,.28));opacity:0}
#flash.go{animation:flash 1.2s ease-out}
@keyframes flash{0%{opacity:0}12%{opacity:1}100%{opacity:0}}

.threat-panel{width:100%}
.viewtoggle{display:flex;gap:8px;align-items:center;justify-content:center;margin:16px 0 14px;flex-wrap:wrap}
.viewtoggle .trackerlink{margin-left:6px;color:var(--cyan);font:600 11px var(--mono);text-decoration:none;border-bottom:1px dotted var(--cyan)}
.vbtn{background:rgba(7,12,22,.7);border:1px solid var(--line2);color:var(--muted);padding:9px 20px;border-radius:8px;cursor:pointer;font:700 11px var(--mono);letter-spacing:1.5px;transition:.15s}
.vbtn:hover{color:var(--text)}
.vbtn.active{background:linear-gradient(180deg,var(--nato2),var(--nato));color:#fff;border-color:var(--nato2);box-shadow:0 0 14px rgba(47,111,224,.4)}
#radarview{display:flex;justify-content:center;margin-bottom:16px}
#mapwrap{position:relative;width:100%;margin-bottom:16px}
#mapview{width:100%;height:520px;border-radius:14px;border:1px solid var(--line2);overflow:hidden}
.leaflet-container{background:#04070e!important;font-family:var(--mono)}
.leaflet-bar a{background:#0c1422;color:#e8f0fb;border-color:#25405f}
.leaflet-bar a:hover{background:#16233a}
.actt{background:#0c1422!important;border:1px solid #37e0ff!important;color:#fff!important;font:700 11px var(--mono);box-shadow:0 0 8px rgba(0,0,0,.7)}
.actt::before{display:none}
.mlabel{font:700 11px var(--mono);color:#fff;background:rgba(4,7,14,.82);border:1px solid #2f6fe0;border-radius:4px;padding:1px 6px;white-space:nowrap;text-shadow:0 1px 2px #000}
.mlabel.site{color:#a6ecff;border-color:#37e0ff}
.mlabel.hostile{color:#ff9aa3;border-color:#ff3b4e}
.mlabel.ref{color:#dbe6f4;border-color:#3a6ea8;background:rgba(4,7,14,.72);font-size:10px}
.mlabel.ring{color:#a9c0dd;border:0;background:transparent;font-size:9px;text-shadow:0 1px 3px #000,0 0 2px #000}
.maplegend{display:flex;gap:18px;flex-wrap:wrap;justify-content:center;margin-top:10px;padding:9px 12px;background:rgba(7,12,22,.85);border:1px solid var(--line);border-radius:8px;font:600 11.5px var(--mono);color:var(--text)}
.maplegend .sw{display:inline-block;width:11px;height:11px;margin-right:6px;vertical-align:-1px;border-radius:50%}
.maplegend .sw.site{background:#37e0ff}.maplegend .sw.ac{background:#54e08a}
.maplegend .sw.hostile{background:#ff3b4e;border-radius:2px}
.natohostile{width:13px;height:13px;background:#ff3b4e;transform:rotate(45deg);box-shadow:0 0 12px #ff3b4e;border:1px solid #fff;animation:tdot 1s ease-in-out infinite}
#maperr{display:none;position:absolute;inset:0;align-items:center;justify-content:center;color:var(--amber);font-size:13px;text-align:center;padding:0 20px;background:rgba(4,7,14,.92);border-radius:14px}
.threatdot{animation:tdot 1s ease-in-out infinite}@keyframes tdot{50%{opacity:.35}}
@media(max-width:900px){.opsgrid{grid-template-columns:1fr}.kpis{grid-template-columns:repeat(2,1fr)}.grid2{grid-template-columns:1fr}.radar{width:260px;height:260px}}

/* Demo-scenario running banner. Added 2026-08-03: the RUN button gave no feedback
   for the ~10s the scenario takes, and the first reading was "it is broken". */
.demobanner{display:flex;align-items:center;gap:12px;margin:0 0 10px;padding:10px 14px;
  border:1px solid #f0a020;border-left:4px solid #f0a020;border-radius:6px;
  background:rgba(240,160,32,.10);color:#ffd79a;font-size:13px;line-height:1.5}
.demobanner b{color:#ffc061}
.demostep{margin-left:auto;white-space:nowrap;font-variant-numeric:tabular-nums;
  font-size:12px;color:#ffca80;opacity:.95}
.demospin{flex:0 0 14px;width:14px;height:14px;border-radius:50%;
  border:2px solid rgba(240,160,32,.35);border-top-color:#f0a020;
  animation:dwspin .8s linear infinite}
@keyframes dwspin{to{transform:rotate(360deg)}}
#demobtn:disabled{opacity:.75;cursor:progress}
@media (prefers-reduced-motion: reduce){.demospin{animation:none}}

/* Running state for the demo button: unmistakably GREEN and alive, so a click
   never looks like nothing happened. Overrides .btn.primary's gradient. */
.btn.primary.running,
.btn.primary.running:disabled{
  background:linear-gradient(180deg,#2ea043,#238636)!important;
  border-color:#3fb950!important;color:#fff!important;opacity:1!important;
  cursor:progress;box-shadow:0 0 16px rgba(63,185,80,.45);
  animation:dwpulse 1.4s ease-in-out infinite}
@keyframes dwpulse{0%,100%{box-shadow:0 0 10px rgba(63,185,80,.35)}
                   50%{box-shadow:0 0 22px rgba(63,185,80,.75)}}
@media (prefers-reduced-motion: reduce){.btn.primary.running{animation:none}}

/* Banner turns green while the LOCAL model is generating the explanation, so the
   "nothing leaves the machine" claim is something a visitor can watch happen. */
.demobanner.model{border-color:#3fb950;border-left-color:#3fb950;
  background:rgba(63,185,80,.10);color:#b7f0c2}
.demobanner.model b{color:#5ce27a}
.demobanner.model .demospin{border-color:rgba(63,185,80,.35);border-top-color:#3fb950}
.demobanner.model .demostep{color:#8ce8a3}

/* Signed-in identity + role, so role separation is visible, not just claimed. */
.whoami{display:inline-flex;align-items:center;gap:6px;padding:6px 11px;border-radius:6px;
  border:1px solid var(--line2);background:rgba(27,44,68,.55);color:var(--text);
  font-size:12px;letter-spacing:.04em;text-transform:uppercase;opacity:.9}

/* dual clock: Zulu (the record) then site-local (the operator's clock) */
.dwclock{font-size:12px;letter-spacing:.04em;color:#8fb4d8;background:#0d1a2b;border:1px solid #1e3550;border-radius:6px;padding:7px 11px;white-space:nowrap}

/* ⭐STICKY CONSOLE HEADER (2026-08-05). Found by Marius: scrolling to the tactical map
   put RUN DEMO SCENARIO, the dual clock and the sound toggle out of reach, so an evaluator
   could not trigger the scenario and watch the map at the same time. On a real console the
   controls and the state line stay visible: they are what you reach for when something
   happens, and hunting for them by scrolling is exactly the wrong moment to be doing it. */
header.top{position:sticky;top:0;z-index:900;background:#0a1420;border-bottom:1px solid #1e3550;box-shadow:0 6px 18px rgba(0,0,0,.45)}
@media (max-width:720px){header.top{position:static;box-shadow:none}}
