/* DGR UI kit 1.2.5 – the look and feel of the DGR software suite (Dinokeng ANPR, NetWatch, Operations Planner, ...).
   Master copy: OneDrive ...\10 - Claude\Programs\Master\ui. Do not edit a program's copy: change the Master and raise the version.
   1 Tokens · 2 Base · 3 Top bar and tabs · 4 Layout, tiles, cards · 5 Buttons and fields · 6 Pills · 7 Tables
   8 Dialogs, side panel, toasts, alarm banner · 9 Charts · 10 Sign-in, Ctrl+K · 11 Motion · 12 Print and wall display
   13 Program tools (1.1.0): maintenance status, display settings, top-bar extras, table tools, settings pages, logs, manual,
      version history, job progress, update banner, side panel sizing, import preview, diagrams and drag and drop, wall cards, footer
   14 Live toggles (1.1.1) · 15 Clickable links and requirements in diagrams (1.2.1) */

/* ==========================================================================================================
   1. Tokens – the Dinokeng ANPR values (the reference program); light, dark by the system, dark by choice
   ========================================================================================================== */
/* Dinokeng Game Reserve design system: Primary Green #253012, Light Green #cacaa6, Legacy Green #35491a,
   Earth Brown #6d3b18, Cream #ebece0, White, Black. Oswald (headings, uppercase) + Montserrat (text). */
:root {
  color-scheme: light;
  --bg: #ffffff;              /* surface */
  --surface-1: #ffffff;
  --surface-2: #ebece0;       /* surface-soft (cream) */
  --border: #cacaa6;          /* line */
  --line-strong: #35491a;
  --text-primary: #000000;    /* ink */
  --text-secondary: #35491a;  /* ink-muted */
  --text-muted: #35491a;
  --grid: #dcdec9;
  --series-1: #253012;        /* primary green */
  --series-2: #6d3b18;        /* earth brown */
  --chart-2: #cc7a33;         /* lighter brown for charts next to the dark green */
  --series-3: #8c8f5e;        /* deeper light-green tint */
  --reserve-fill: #ebece0;
  --reserve-line: #35491a;
  --good: #35491a;
  --warning: #6d3b18;
  --critical: #c0000c;
  --st-on-bg: #dcefd6; --st-on-fg: #1e5a17; --st-off-bg: #c0000c; --st-off-fg: #ffffff;
  --st-wait-bg: #fbe7c6; --st-wait-fg: #7a4500;
  --accent: #253012;
  --on-accent: #ffffff;
  --band: #cacaa6; --on-band: #253012;
  --bar: #253012; --on-bar: #ffffff; --bar-muted: #cacaa6;
  --focus-ring: #6d3b18;
  /* property map: even lightness steps (L* 95/86/74/57/39) in the brand's greens; "none" is neutral */
  --q0: #f2f2ec; --q1: #cfd99f; --q2: #a9bf6c; --q3: #76943d; --q4: #46641f;
  --map-bg: #ffffff; --map-line: #b9bba9; --map-edge: #253012; --map-halo: #ffffff;
  --road-main: #6d3b18; --road-minor: #9b7b5e; --map-dot: #6d3b18; --map-dot-ring: #ffffff; --map-cam: #ffffff; --map-cam-line: #000000; --map-hover: #6d3b18;
  --display: "Oswald", "Arial Narrow", sans-serif;
  --sans: "Montserrat", "Segoe UI", Arial, sans-serif;
  --r: 8px;                   /* corners of cards, tiles, buttons, fields, menus; pills are round */
  --ctl-h: 34px;              /* height of every field, list and button in a control row */
}
/* dark (1.2.0, "Night"): warm near-black charcoal; cards a step lighter; the brand green only on the top bar, the hero tile and accents.
   Text 14:1, secondary 9:1, muted 6:1 on cards; warning amber and alarm red far apart. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #101210; --surface-1: #1a1d18; --surface-2: #252923; --border: #353b31; --line-strong: #6b7560;
    --text-primary: #f1f0e8; --text-secondary: #c9cbb6; --text-muted: #9da18e; --grid: #2a2f26;
    --series-1: #cacaa6; --series-2: #d6a47a; --series-3: #a8c47a; --chart-2: #e8955a;
    --reserve-fill: #252923; --reserve-line: #6b7560;
    --good: #9fd88a; --warning: #f2b450; --critical: #ff6b5e;
    --st-on-bg: #1d3a18; --st-on-fg: #a9e59b; --st-off-bg: #c9302a; --st-off-fg: #ffffff;
    --st-wait-bg: #43340f; --st-wait-fg: #ffd27a; --st-maint-bg: #173450; --st-maint-fg: #a9d4f5;
    --accent: #cacaa6; --on-accent: #1b2410; --band: #2b3324; --on-band: #eceedd;
    --bar: #253012; --on-bar: #ffffff; --bar-muted: #cacaa6; --focus-ring: #f2b450;
    --map-bg: #141712; --map-line: #101210; --map-edge: #ebece0; --map-halo: #141712;
    --q0: #20241c; --q1: #3e5524; --q2: #5f8236; --q3: #93b45c; --q4: #d3e3a0;
    --road-main: #e09a62; --road-minor: #b9977a; --map-dot: #e09a62; --map-dot-ring: #141712; --map-cam: #1a1d18; --map-cam-line: #ffffff; --map-hover: #f2b450;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
    --bg: #101210; --surface-1: #1a1d18; --surface-2: #252923; --border: #353b31; --line-strong: #6b7560;
    --text-primary: #f1f0e8; --text-secondary: #c9cbb6; --text-muted: #9da18e; --grid: #2a2f26;
    --series-1: #cacaa6; --series-2: #d6a47a; --series-3: #a8c47a; --chart-2: #e8955a;
    --reserve-fill: #252923; --reserve-line: #6b7560;
    --good: #9fd88a; --warning: #f2b450; --critical: #ff6b5e;
    --st-on-bg: #1d3a18; --st-on-fg: #a9e59b; --st-off-bg: #c9302a; --st-off-fg: #ffffff;
    --st-wait-bg: #43340f; --st-wait-fg: #ffd27a; --st-maint-bg: #173450; --st-maint-fg: #a9d4f5;
    --accent: #cacaa6; --on-accent: #1b2410; --band: #2b3324; --on-band: #eceedd;
    --bar: #253012; --on-bar: #ffffff; --bar-muted: #cacaa6; --focus-ring: #f2b450;
    --map-bg: #141712; --map-line: #101210; --map-edge: #ebece0; --map-halo: #141712;
    --q0: #20241c; --q1: #3e5524; --q2: #5f8236; --q3: #93b45c; --q4: #d3e3a0;
    --road-main: #e09a62; --road-minor: #b9977a; --map-dot: #e09a62; --map-dot-ring: #141712; --map-cam: #1a1d18; --map-cam-line: #ffffff; --map-hover: #f2b450;
}
* { box-sizing: border-box; }
[hidden] { display: none !important; }

/* ==========================================================================================================
   2. Base
   ========================================================================================================== */
:root { --ease: cubic-bezier(.2, .7, .2, 1); --ease-out: cubic-bezier(.2, .8, .2, 1); --ease-in: cubic-bezier(.4, 0, 1, 1);
  --shimmer: linear-gradient(90deg, var(--surface-2) 25%, color-mix(in srgb, var(--surface-2) 35%, var(--surface-1)) 50%, var(--surface-2) 75%);
  interpolate-size: allow-keywords; }
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { margin: 0; background: var(--bg); color: var(--text-primary); font: 14px/1.5 var(--sans); }
:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
h1, h2, h3 { font-family: var(--display); text-transform: uppercase; letter-spacing: .02em; }
a { color: inherit; }
:where(main, dialog, .tip) a:where(:not(.btn)) { text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
.muted { color: var(--text-muted); }
.spacer { flex: 1; }
.num, td.num, th.num { font-variant-numeric: tabular-nums; }
.plate, td.plate, span.plate { font-weight: 700; letter-spacing: .04em; font-family: ui-monospace, Consolas, monospace; }
.sticky { position: sticky; top: 0; z-index: 5; }

/* ==========================================================================================================
   3. Top bar (header), main tabs, sub-tabs, period buttons
   ========================================================================================================== */
header { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; padding: 12px 24px; background: var(--bar); color: var(--on-bar); }
header .logo { height: 44px; width: auto; display: block; margin-right: 8px; }
header h1 { font: 700 22px/26px var(--display); text-transform: uppercase; margin: 0; letter-spacing: .02em; }
header .sub { color: var(--bar-muted); font-size: 12.5px; }
header .btn { border-color: var(--bar-muted); background: transparent; color: var(--on-bar); }
header .btn.icon { padding: 6px 8px; line-height: 0; }
header .btn.solid { background: var(--on-bar); color: var(--bar); border-color: var(--on-bar); }
header .user { color: var(--bar-muted); font-size: 12.5px; }
header .search { display: flex; gap: 6px; }
header .search input { width: 160px; padding: 7px 10px; border: 1px solid var(--bar-muted); border-radius: var(--r); background: transparent; color: var(--on-bar); font: 600 13px var(--sans); text-transform: uppercase; }
header .search input::placeholder { color: var(--bar-muted); text-transform: none; font-weight: 400; }
header .statusgrp { display: flex; align-items: center; gap: 12px; padding: 0 12px; border-left: 1px solid rgba(255,255,255,.18); border-right: 1px solid rgba(255,255,255,.18); }
header .btn.live-btn { display: inline-flex; align-items: center; gap: 7px; }
header .btn.live-btn::before { content: ""; flex: 0 0 9px; width: 9px; height: 9px; border-radius: 50%; background: #9aa0a6; }
header .btn.live-btn[aria-pressed="true"]::before { background: #2fbf5b; box-shadow: 0 0 0 3px rgba(47,191,91,.25); animation: dgr-livepulse 2s infinite; }
header .btn.live-btn[aria-pressed="false"] { opacity: .8; }
@keyframes dgr-livepulse { 50% { box-shadow: 0 0 0 5px rgba(47,191,91,.05); } }
header .menu-btn { display: none; }
/* phones: one row (logo, title, status, ☰); ☰ opens the rest */
@media (max-width: 640px) {
  header { padding: 8px 12px; gap: 8px; }
  header .logo { height: 28px; }
  header > .title { flex: 1; min-width: 0; }
  header h1 { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  header .sub { font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  header .statusgrp { border: 0; padding: 0; margin-left: auto; order: 2; }
  header .menu-btn { display: inline-flex; order: 3; }
  header .in-menu { display: none !important; }
  header.open .in-menu { display: inline-flex !important; order: 11; }
  header.open .search.in-menu { display: flex !important; flex-basis: 100%; order: 10; }
  header.open .search input { flex: 1; }
  header .spacer { display: none; }
}
nav.bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; padding: 0 24px; background: var(--surface-1); border-bottom: 1px solid var(--border); }
.tabs { display: flex; gap: 2px; max-width: 100%; overflow-x: auto; scrollbar-width: none; position: relative; }
.tabs button { border: 0; background: transparent; color: var(--text-secondary); cursor: pointer; font: 700 15px/20px var(--display); text-transform: uppercase;
  letter-spacing: .04em; padding: 14px 14px 11px; border-bottom: 3px solid transparent; transition: color .2s; }
.tabs button[aria-selected="true"] { color: var(--text-primary); border-bottom-color: var(--series-2); }
.tabcount { display: inline-block; min-width: 18px; padding: 0 6px; margin-left: 4px; border-radius: 9px; background: var(--st-off-bg); color: var(--st-off-fg); font: 700 11.5px/18px var(--sans); text-align: center; vertical-align: 1px; }
.subbar { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 24px; background: var(--surface-2); border-bottom: 1px solid var(--border); position: relative; }
.subbar:empty { display: none; }
.subbar button { position: relative; z-index: 1; border: 1px solid transparent; background: transparent; color: var(--text-secondary); font: 600 13.5px var(--sans); padding: 5px 12px; border-radius: 999px; cursor: pointer; transition: color .2s; }
.subbar button:hover { border-color: var(--line-strong); }
.subbar button[aria-selected="true"] { background: var(--surface-1); color: var(--text-primary); border-color: var(--line-strong); }
@media (max-width: 640px) { .tabs { flex-wrap: wrap; overflow: visible; } .tabs button { padding: 8px 10px; } .subbar { padding: 6px 12px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; } .subbar button { white-space: nowrap; } }
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: var(--r); overflow: hidden; margin: 8px 0; }
.seg button { border: 0; background: transparent; color: var(--text-secondary); padding: 6px 12px; font: 600 13px var(--sans); cursor: pointer; transition: background .2s, color .2s; }
.seg button + button { border-left: 1px solid var(--line-strong); }
.seg button[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }
/* sliding markers (dgr-ui.js adds them): the line under the main tabs, the pill behind the sub-tabs */
.dgr-uline { position: absolute; top: 0; height: 3px; border-radius: 2px; background: var(--series-2); transition: left .38s var(--ease-out), width .38s var(--ease-out), top .38s var(--ease-out); pointer-events: none; }
.dgr-pill { position: absolute; z-index: 0; border-radius: 999px; background: var(--surface-1); border: 1px solid var(--line-strong); transition: left .38s var(--ease-out), width .38s var(--ease-out), top .38s var(--ease-out); pointer-events: none; }
html.dgr-js .tabs button[aria-selected="true"] { border-bottom-color: transparent; }
html.dgr-js .subbar button[aria-selected="true"] { background: transparent; border-color: transparent; }
html.nomotion .tabs button[aria-selected="true"] { border-bottom-color: var(--series-2); }
html.nomotion .subbar button[aria-selected="true"] { background: var(--surface-1); border-color: var(--line-strong); }
html.nomotion .dgr-uline, html.nomotion .dgr-pill { display: none; }

/* ==========================================================================================================
   4. Layout: page grid, tiles (key figures), cards
   ========================================================================================================== */
main { padding: 24px 24px 48px; max-width: var(--page-max, 1440px); margin: 0 auto; display: grid; gap: 20px; }
main.dash { max-width: var(--page-max, none); grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr)); grid-auto-flow: row dense; align-items: stretch; gap: var(--gap, 20px); }
main.dash > * { min-width: 0; }
main.dash > [data-w="full"] { grid-column: 1 / -1; }
.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 20px; }
.grid2 > * { min-width: 0; }
@media (max-width: 640px) { main { padding: 14px 12px 40px; } main.dash { grid-template-columns: 1fr !important; } main.dash > * { grid-column: auto !important; } .grid2 { grid-template-columns: 1fr; } }
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.kpis > * { min-width: 0; overflow-wrap: anywhere; }
.tile, .card { background: var(--surface-1); border: 1px solid var(--border); border-radius: var(--r); }
.tile { padding: 14px 16px; border-top: 4px solid var(--border); transition: box-shadow .25s var(--ease-out), transform .25s var(--ease-out); }
.tile .label { font: 700 13px/18px var(--display); text-transform: uppercase; letter-spacing: .05em; color: var(--text-secondary); }
.tile .value { font: 700 34px/1.1 var(--display); margin-top: 6px; font-variant-numeric: tabular-nums; position: relative; }
.tile .note { color: var(--text-muted); font-size: 12px; line-height: 17px; margin-top: 4px; }
.tile.hero { background: var(--bar); border-color: var(--bar); color: var(--on-bar); }
.tile.hero .label, .tile.hero .note { color: var(--bar-muted); }
.tile.hero .value { font-size: 46px; }
.tile.alert { border-top-color: var(--series-2); }
.tile-link { cursor: pointer; }
.tile:hover, .tile-link:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(20, 30, 10, .12); }
.tile-link:hover { border-color: var(--series-1); }
.card { padding: 18px 20px; min-width: 0; transition: box-shadow .25s var(--ease-out), opacity .3s; }
.card h2 { font: 700 18px/24px var(--display); text-transform: uppercase; letter-spacing: .02em; margin: 0 0 2px; }
.card h3 { font: 700 15px/20px var(--display); text-transform: uppercase; letter-spacing: .03em; margin: 18px 0 6px; }
.card .desc { color: var(--text-muted); font-size: 13px; line-height: 19px; margin-bottom: 12px; }
.cardhead { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-start; }
.cardhead > .ch-main { flex: 1; min-width: 240px; }
.sys-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.sys-head h2 { margin: 0; }
.kvs { display: flex; flex-direction: column; margin-top: 6px; }
.kvs .kv { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.kvs .kv:last-child { border-bottom: 0; }
.kvs .kv > span:first-child { color: var(--text-secondary); font-size: 13px; flex: none; }
.kvs .kv > span:last-child { font-weight: 600; text-align: right; overflow-wrap: anywhere; min-width: 0; }
.kvs .kv .sub { display: block; font-weight: 400; font-size: 12px; color: var(--text-secondary); }
.mini { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 14px 0; }
.mini > div { border: 1px solid var(--border); border-top: 4px solid var(--border); border-radius: var(--r); padding: 8px 12px; }
.mini b { display: block; font: 700 13px/18px var(--display); text-transform: uppercase; letter-spacing: .05em; color: var(--text-secondary); }
.mini span { font-size: 15px; font-weight: 700; }
.notice { background: var(--surface-2); border-left: 4px solid var(--series-2); padding: 10px 14px; font-size: 13.5px; }
.notice.bad, .errbox { background: var(--surface-2); border-left: 4px solid var(--critical); padding: 10px 14px; }
.empty { color: var(--text-muted); padding: 18px 12px; }

/* ==========================================================================================================
   5. Buttons, fields, forms, save bar
   ========================================================================================================== */
.btn { padding: 7px 14px; border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--surface-1); color: var(--text-primary); font: 700 13px/18px var(--sans);
  cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap; transition: background .15s, box-shadow .15s, transform .1s; }
.btn:hover { background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: default; }
.btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn.primary:hover { filter: brightness(1.12); }
.btn.danger { border-color: var(--critical); color: var(--critical); }
.btn.small { padding: 4px 10px; font-size: 12px; line-height: 16px; }
.btn.icon { padding: 6px 8px; line-height: 0; }
.btn.is-busy::before { content: ""; display: inline-block; width: 11px; height: 11px; margin-right: 2px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: dgr-spin .7s linear infinite; }
.btn.is-done::before { content: "✓"; margin-right: 2px; } .btn.is-fail { border-color: var(--critical); color: var(--critical); } .btn.is-fail::before { content: "✕"; margin-right: 2px; }
@keyframes dgr-spin { to { transform: rotate(360deg); } }
input.in, select.in, textarea.in { width: 100%; padding: 0 10px; border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--surface-1); color: var(--text-primary); font: 13.5px var(--sans); }
input.in:not([type=checkbox]):not([type=radio]), select.in { height: var(--ctl-h); }
textarea.in { padding: 8px 10px; min-height: 72px; resize: vertical; }
input.in[readonly] { background: var(--surface-2); border-color: var(--border); }
input.in.bad { border-color: var(--critical); border-width: 2px; }
input[type=file]::file-selector-button { margin-right: 10px; padding: 7px 14px; border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--surface-1); color: var(--text-primary); font: 700 13px var(--sans); cursor: pointer; }
.form { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px 16px; }
.field label { display: block; font-size: 12.5px; font-weight: 700; color: var(--text-secondary); margin-bottom: 4px; }
.field .hint { font-size: 12px; color: var(--text-muted); margin-top: 3px; line-height: 16px; }
.chk { display: flex; align-items: center; gap: 8px; font-size: 13.5px; padding-top: 22px; }
.controls, .filters, .toolbar { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; margin: 0 0 10px; }
.savebar { position: sticky; bottom: 0; z-index: 4; display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; background: var(--surface-1); border-top: 3px solid var(--series-2); padding: 12px 24px; }
.savebar .msg { font-size: 13.5px; font-weight: 600; } .savebar .msg.err { color: var(--critical); }
details summary { cursor: pointer; color: var(--text-secondary); margin-top: 8px; font-size: 13px; font-weight: 600; }
details::details-content { block-size: 0; overflow: clip; transition: block-size .32s var(--ease-out), content-visibility .32s allow-discrete; }
details[open]::details-content { block-size: auto; }
.popmenu { position: fixed; z-index: 1100; background: var(--surface-1); border: 1px solid var(--line-strong); border-radius: 8px; box-shadow: 0 6px 24px rgba(0,0,0,.18); padding: 4px; min-width: 220px; animation: dgr-rise .2s var(--ease); }
.popmenu button { display: block; width: 100%; text-align: left; border: 0; background: none; padding: 8px 12px; border-radius: 6px; font: inherit; color: inherit; cursor: pointer; }
.popmenu button:hover, .popmenu button:focus { background: var(--surface-2); outline: none; }

/* ==========================================================================================================
   6. Pills: who a vehicle / person is, and status (always colour + symbol + word)
   ========================================================================================================== */
.badge { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; padding: 1px 9px; border-radius: 9999px; border: 1px solid var(--line-strong); color: var(--text-secondary); white-space: nowrap; }
.badge.res { background: color-mix(in srgb, #7fb24a 30%, transparent); border-color: color-mix(in srgb, #7fb24a 55%, transparent); color: var(--text-primary); }
.badge.vis { background: color-mix(in srgb, #b98a5a 28%, transparent); border-color: color-mix(in srgb, #b98a5a 55%, transparent); color: var(--text-primary); }
.badge.flag { background: var(--st-off-bg); border-color: var(--st-off-bg); color: var(--st-off-fg); }   /* solid red with white text in both themes */
.badge.watch { background: color-mix(in srgb, #a9aeb5 35%, transparent); border-color: #a9aeb5; color: var(--text-primary); }
.badge.bus { background: #1f3f8a; border-color: #1f3f8a; color: #fff; }
.badge.school { background: color-mix(in srgb, #5aa9e6 35%, transparent); border-color: #5aa9e6; color: var(--text-primary); }
.badge.svc { background: color-mix(in srgb, #f2d64b 40%, transparent); border-color: #d9bb2a; color: var(--text-primary); }
.badge.warn { border-color: var(--series-2); color: var(--series-2); }
.badge.ok { border-color: var(--series-2); color: var(--text-primary); }
.badge.act { background: var(--st-off-bg); border-color: var(--st-off-bg); color: var(--st-off-fg); }
.badge.inside { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.badge.flag::before { content: "⚑ "; } .badge.res::before { content: "⌂ "; } .badge.watch::before { content: "◉ "; }
.st { display: inline-flex; align-items: center; gap: 6px; min-width: 104px; justify-content: center; padding: 4px 12px; border-radius: 9999px; font-weight: 700; font-size: 13px; letter-spacing: .02em; text-transform: uppercase; white-space: nowrap; }
.st::before { font-size: 12px; line-height: 1; }
.st.on { background: var(--st-on-bg); color: var(--st-on-fg); } .st.on::before { content: "●"; }
.st.off { background: var(--st-off-bg); color: var(--st-off-fg); } .st.off::before { content: "✕"; font-weight: 900; }
.st.wait { background: var(--st-wait-bg); color: var(--st-wait-fg); } .st.wait::before { content: "◌"; }
.st.none { background: var(--surface-2); color: var(--text-muted); }
.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot.good { background: var(--good); } .dot.warn { background: var(--warning); } .dot.bad { background: var(--critical); }

/* ==========================================================================================================
   7. Tables (rows as cards on phones)
   ========================================================================================================== */
.tablewrap { overflow-x: auto; max-height: var(--tbl-h, 440px); overflow-y: auto; border: 1px solid var(--border); }
.tablewrap.tall { max-height: var(--tbl-h-tall, max(560px, calc(100vh - 360px))); }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
th { background: var(--band); color: var(--on-band); font-weight: 700; position: sticky; top: 0; z-index: 1; }
tbody tr { transition: background-color .18s; }
tbody tr.click { cursor: pointer; } tbody tr.click:hover, tbody tr:hover { background: color-mix(in srgb, var(--surface-2) 70%, transparent); }
tr.this td { background: var(--surface-2); font-weight: 600; }
tr.rowin > td { animation: dgr-row .8s var(--ease-out); }
@keyframes dgr-row { from { opacity: 0; transform: translateY(-8px); background: color-mix(in srgb, var(--series-1) 26%, transparent); } 60% { background: color-mix(in srgb, var(--series-1) 14%, transparent); } }
.rd-new { display: inline-block; padding: 0 6px; border-radius: 9999px; background: var(--st-on-bg); color: var(--st-on-fg); font-size: 11px; font-weight: 700; text-transform: uppercase; }
@media (max-width: 640px) {
  table.cards thead { display: none; }
  table.cards tr { display: block; border-bottom: 1px solid var(--border); padding: 6px 0; }
  table.cards td { display: flex; justify-content: space-between; gap: 12px; border: 0; padding: 4px 12px; white-space: normal; }
  table.cards td::before { content: attr(data-l); color: var(--text-muted); font-size: 12px; }
}

/* ==========================================================================================================
   8. Dialogs, the side panel, confirmations, toasts, the alarm banner, the busy bar, skeletons
   ========================================================================================================== */
dialog { border: 1px solid var(--line-strong); border-radius: 8px; padding: 0; background: var(--surface-1); color: var(--text-primary); width: min(520px, calc(100vw - 32px)); }
dialog::backdrop { background: rgba(10, 14, 5, .55); }
dialog .dh { background: var(--bar); color: var(--on-bar); padding: 12px 18px; font: 700 17px/22px var(--display); text-transform: uppercase; letter-spacing: .03em; }
dialog .db { padding: 18px; display: grid; gap: 12px; }
dialog .df { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; padding: 0 18px 18px; }
dialog .derr { color: var(--critical); font-weight: 600; font-size: 13px; min-height: 18px; }
dialog.wide { width: min(900px, calc(100vw - 32px)); } dialog.xwide { width: min(1180px, calc(100vw - 32px)); max-width: none; }
dialog.confirm { width: min(460px, calc(100vw - 32px)); }
dialog[open]:not(.side) { animation: dgr-dlg-in .3s var(--ease-out) both; }
dialog[open]::backdrop { animation: dgr-fade-in .3s ease both; }
dialog.dgr-closing:not(.side) { animation: dgr-dlg-out .2s var(--ease-in) both; }
dialog.dgr-closing::backdrop { animation: dgr-fade-out .2s ease both; }
dialog.side { position: fixed; inset: 0 0 0 auto; margin: 0; height: 100vh; max-height: 100vh; width: min(560px, 100vw); border-radius: 0; z-index: 60;
  border-width: 0 0 0 1px; box-shadow: -8px 0 32px rgba(0,0,0,.2); overflow: auto; flex-direction: column; }
dialog.side[open] { display: flex; animation: dgr-side-in .42s var(--ease-out) both; }
dialog.side.dgr-closing { animation: dgr-side-out .26s var(--ease-in) both; }
dialog.side .db { flex: 1; align-content: start; }
dialog.side .df { position: sticky; bottom: 0; background: var(--surface-1); padding-top: 12px; border-top: 1px solid var(--border); }
dialog.side[open] .db > * { animation: dgr-rise .4s var(--ease-out) both; }
dialog.side[open] .db > :nth-child(2) { animation-delay: 60ms; } dialog.side[open] .db > :nth-child(3) { animation-delay: 110ms; }
dialog.side[open] .db > :nth-child(4) { animation-delay: 160ms; } dialog.side[open] .db > :nth-child(n+5) { animation-delay: 200ms; }
.dgr-scrim { position: fixed; inset: 0; z-index: 59; background: rgba(12, 16, 6, .28); opacity: 0; pointer-events: none; transition: opacity .3s var(--ease-out); }
.dgr-scrim.on { opacity: 1; pointer-events: auto; }
@media (max-width: 640px) { dialog[open]:not(.side) { margin: auto 0 0; width: 100vw; max-width: 100vw; border-radius: 14px 14px 0 0; animation: dgr-sheet-in .3s var(--ease-out) both; } }
#toasts { position: fixed; inset: auto auto 20px 50%; transform: translateX(-50%); margin: 0; border: 0; padding: 0; background: transparent; overflow: visible;
  display: flex; flex-direction: column; gap: 8px; align-items: center; z-index: 1200; max-width: 92vw; }
#toasts:empty { display: none; }
.toastmsg { display: flex; gap: 12px; align-items: flex-start; background: var(--accent); color: var(--on-accent); padding: 10px 16px; border-radius: 8px; box-shadow: 0 4px 16px rgba(0,0,0,.2); max-width: 90vw;
  animation: dgr-toast-in .38s var(--ease-out) both; }
.toastmsg.err { background: var(--st-off-bg); color: var(--st-off-fg); }
.toastmsg.dgr-leaving { animation: dgr-toast-out .25s var(--ease-in) both; }
.toastmsg .tx { background: none; border: 0; color: inherit; cursor: pointer; font-size: 14px; padding: 0 2px; opacity: .8; }
.alarmbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 9px 24px; background: var(--st-off-bg); color: var(--st-off-fg); font-size: 14.5px; overflow: hidden; animation: dgr-drop .45s var(--ease-out) both; }
.alarmbar.dgr-leaving { animation: dgr-lift .3s var(--ease-in) both; }
.alarmbar .btn { background: transparent; color: #fff; border-color: rgba(255,255,255,.7); }
.alarmbar .btn:hover { background: rgba(255,255,255,.15); }
.alarmbar .ab-txt { flex: 1; min-width: 200px; }
.tabcount.dgr-pop { animation: dgr-pop .6s var(--ease-out); }
.connbar { padding: 8px 24px; background: var(--st-off-bg); color: var(--st-off-fg); font-weight: 600; font-size: 13.5px; }
.busybar { position: fixed; left: 0; right: 0; top: 0; height: 3px; z-index: 1000; pointer-events: none; overflow: hidden; }
.busybar::before { content: ""; position: absolute; top: 0; bottom: 0; width: 35%; background: var(--series-1); animation: dgr-busy 1.1s ease-in-out infinite; }
.card.loading { opacity: .62; cursor: progress; }
.skel { display: block; height: 12px; border-radius: 6px; background: var(--shimmer); background-size: 200% 100%; animation: dgr-shimmer 1.3s linear infinite; }

/* ==========================================================================================================
   9. Charts (dgr-ui.js draws them): grid, axes, lines, bars, tooltip, legend
   ========================================================================================================== */
.chart { position: relative; width: 100%; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.chart text { fill: var(--text-muted); font: 11px var(--sans); }
.chart .gl { stroke: var(--grid); stroke-width: 1; }
.chart .ln { fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.drawin .ln { stroke-dasharray: 1; stroke-dashoffset: 1; animation: dgr-draw 1s var(--ease) forwards; }
.drawin .br { transform-box: fill-box; transform-origin: 50% 100%; animation: dgr-grow .65s var(--ease) both; }
.drawin .bx { transform-box: fill-box; transform-origin: 0 50%; animation: dgr-growx .65s var(--ease) both; }
.drawin .end { animation: dgr-fade-in .3s .75s both; }
.legend { display: flex; flex-wrap: wrap; gap: 16px; font-size: 12.5px; color: var(--text-secondary); margin-bottom: 6px; }
.legend i { display: inline-block; width: 10px; height: 10px; margin-right: 6px; vertical-align: -1px; border-radius: 2px; }
.tip { position: absolute; pointer-events: none; background: var(--surface-1); border: 1px solid var(--line-strong); border-radius: 4px; padding: 8px 10px; font-size: 12.5px; white-space: nowrap; z-index: 3; color: var(--text-primary); opacity: 0; transition: opacity .15s; }
.tip.on { opacity: 1; }
.tip b { font-variant-numeric: tabular-nums; }
.hbars { display: flex; flex-direction: column; gap: 7px; }
.hbars .r { display: grid; grid-template-columns: 110px 1fr 54px; gap: 10px; align-items: center; font-size: 13px; }
.hbars .t { height: 12px; background: var(--surface-2); border-radius: 6px; overflow: hidden; }
.hbars .t i { display: block; height: 100%; border-radius: 0 6px 6px 0; background: var(--series-1); }
.hbars b { text-align: right; font-variant-numeric: tabular-nums; }
/* the kit's heat map is boxes (.heat > .r > i); a program's <table class="heat"> keeps its table layout (1.2.6) */
.heat:not(table) { display: flex; flex-direction: column; gap: 2px; }
.heat .r { display: grid; grid-template-columns: 34px repeat(24, 1fr); gap: 2px; align-items: center; }
.heat .r span { font-size: 11px; color: var(--text-muted); }
.heat .r i { height: 16px; border-radius: 3px; }

/* ==========================================================================================================
   10. Sign-in page, Ctrl + K finder
   ========================================================================================================== */
.signin { min-height: 100vh; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.signin .brand { background: var(--bar); display: flex; align-items: center; justify-content: center; padding: 64px; }
.signin .brand img { width: min(360px, 80%); height: auto; }
.signin .panel { display: flex; align-items: center; justify-content: center; padding: 48px 24px; }
.signin form { width: 100%; max-width: 380px; display: grid; gap: 4px; }
.signin h1 { font: 700 36px/42px var(--display); margin: 0 0 4px; }
.signin .lead { color: var(--text-secondary); font-weight: 600; margin: 0 0 28px; }
.signin label { font-weight: 600; font-size: 14px; margin-top: 12px; }
.signin input { width: 100%; padding: 11px 12px; font: 16px var(--sans); color: var(--text-primary); background: var(--surface-1); border: 1px solid var(--line-strong); border-radius: 4px; }
.signin button[type=submit] { margin-top: 20px; padding: 12px; border: 0; border-radius: 8px; background: var(--accent); color: var(--on-accent); font: 700 16px var(--sans); cursor: pointer; }
.signin .note { color: var(--text-muted); font-size: 13px; margin-top: 20px; }
@media (max-width: 760px) { .signin { grid-template-columns: 1fr; grid-template-rows: auto 1fr; } .signin .brand { padding: 32px; } .signin .brand img { width: min(220px, 70%); } }
.dgr-finder { position: fixed; left: 50%; top: 12vh; z-index: 1300; width: min(620px, calc(100% - 24px)); background: var(--surface-1); color: var(--text-primary); border: 1px solid var(--line-strong); border-radius: 14px;
  box-shadow: 0 20px 60px rgba(0,0,0,.3); overflow: hidden; transform: translate(-50%, -8px) scale(.98); opacity: 0; pointer-events: none; transition: all .25s var(--ease-out); }
.dgr-finder.on { transform: translate(-50%, 0); opacity: 1; pointer-events: auto; }
.dgr-finder input { width: 100%; height: 56px; border: 0; border-bottom: 1px solid var(--border); padding: 0 18px; font: 600 17px var(--sans); background: transparent; color: inherit; outline: none; }
.dgr-finder .r { max-height: 50vh; overflow-y: auto; padding: 6px 0; }
.dgr-finder .g { font: 700 11px var(--display); letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); padding: 8px 18px 4px; }
.dgr-finder button { display: flex; gap: 10px; align-items: center; width: 100%; border: 0; background: none; color: inherit; padding: 9px 18px; text-align: left; cursor: pointer; font: 14px var(--sans); }
.dgr-finder button.sel, .dgr-finder button:hover { background: var(--surface-2); }
.dgr-finder .k { margin-left: auto; color: var(--text-muted); font-size: 12px; }
.dgr-finderbg { position: fixed; inset: 0; z-index: 1299; background: rgba(12, 16, 6, .3); opacity: 0; pointer-events: none; transition: opacity .25s; }
.dgr-finderbg.on { opacity: 1; pointer-events: auto; }

/* ==========================================================================================================
   11. Motion: pages, things that appear and leave. All off with html.nomotion or Windows' "fewer animations"
   ========================================================================================================== */
main.dgr-in > :not([hidden]) { animation: dgr-rise .42s var(--ease-out) both; }
main.dgr-in > :nth-child(2) { animation-delay: 30ms; } main.dgr-in > :nth-child(3) { animation-delay: 60ms; } main.dgr-in > :nth-child(4) { animation-delay: 90ms; }
main.dgr-in > :nth-child(5) { animation-delay: 120ms; } main.dgr-in > :nth-child(6) { animation-delay: 150ms; } main.dgr-in > :nth-child(n+7) { animation-delay: 180ms; }
.dgr-appear:not([hidden]) { animation: dgr-rise .4s var(--ease-out) both; }
details[open] > :not(summary) { animation: dgr-fade-in .35s ease both; }
::view-transition-old(root) { animation: dgr-fade-out .18s var(--ease-in) both; }
::view-transition-new(root) { animation: dgr-fade-in .32s var(--ease-out) both; }
@keyframes dgr-rise { from { opacity: 0; transform: translateY(12px); } }
@keyframes dgr-fade-in { from { opacity: 0; } } @keyframes dgr-fade-out { to { opacity: 0; } }
@keyframes dgr-dlg-in { from { opacity: 0; transform: translateY(14px) scale(.96); } }
@keyframes dgr-dlg-out { to { opacity: 0; transform: translateY(8px) scale(.97); } }
@keyframes dgr-sheet-in { from { opacity: 0; transform: translateY(40px); } }
@keyframes dgr-side-in { from { transform: translateX(100%); } } @keyframes dgr-side-out { to { transform: translateX(100%); } }
@keyframes dgr-toast-in { from { opacity: 0; transform: translateY(14px); } } @keyframes dgr-toast-out { to { opacity: 0; transform: translateY(10px); } }
@keyframes dgr-drop { from { opacity: 0; max-height: 0; padding-top: 0; padding-bottom: 0; } to { max-height: 90px; } }
@keyframes dgr-lift { from { max-height: 90px; } to { opacity: 0; max-height: 0; padding-top: 0; padding-bottom: 0; } }
@keyframes dgr-pop { 0% { transform: scale(.4); } 55% { transform: scale(1.35); } 100% { transform: scale(1); } }
@keyframes dgr-draw { to { stroke-dashoffset: 0; } } @keyframes dgr-grow { from { transform: scaleY(0); } } @keyframes dgr-growx { from { transform: scaleX(0); } }
@keyframes dgr-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@keyframes dgr-busy { from { left: -35%; } to { left: 100%; } }
html.nomotion *, html.nomotion *::before, html.nomotion *::after, html.nomotion ::view-transition-group(*) { animation: none !important; transition: none !important; }
html.nomotion .drawin .ln { stroke-dashoffset: 0; }
html.nomotion { scroll-behavior: auto; }
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) *, html:not(.motion-on) *::before, html:not(.motion-on) *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; }
  html:not(.motion-on) .drawin .ln { stroke-dashoffset: 0; } html:not(.motion-on) { scroll-behavior: auto; }
}

/* ==========================================================================================================
   12. Print and wall display
   ========================================================================================================== */
@media print { header, nav.bar, .subbar, .savebar, .btn, #toasts, .dgr-finder { display: none !important; } .card, .tile { break-inside: avoid; box-shadow: none; } }
body.wall header .in-menu, body.wall nav.bar, body.wall .subbar { display: none !important; }
body.wall .tile .value { font-size: 56px; }

/* ==========================================================================================================
   13. Program tools (1.1.0, from Dinokeng NetWatch): status colours for devices, maintenance, display settings,
       top-bar extras, table tools, settings pages, long text (logs, code, manual, version history), job progress,
       update banner, side panel sizing, import preview, diagrams (network map, site plan, drag and drop), wall cards
   ========================================================================================================== */
/* --- extra tokens: maintenance (blue) and the small status marks (dots, stripes) used on the green top bar and in diagrams.
       The marks use the same values in light and dark because they always sit next to their word or on the dark bar. */
:root { --maint: #5aa9e6; --st-maint-bg: #d6e9f8; --st-maint-fg: #0f4c7a;
  --mark-on: #2fbf5b; --mark-wait: #f2b33d; --mark-off: #ff5a4f; --mark-maint: #5aa9e6; --mark-none: #9aa0a6; }

/* --- display settings (Settings → Display): table height and spacing, set on <html> */
:root[data-tables="tall"] { --tbl-h: 60vh; --tbl-h-tall: 75vh; }
:root[data-tables="screen"] { --tbl-h: calc(100vh - 300px); --tbl-h-tall: calc(100vh - 220px); }
:root[data-density="compact"] { --gap: 12px; }
:root[data-density="compact"] .card { padding: 12px 14px; }
:root[data-density="compact"] main { padding-top: 14px; }
:root[data-density="compact"] th, :root[data-density="compact"] td { padding: 5px 8px; }
:root[data-density="compact"] .card .desc { margin-bottom: 8px; }
.dispform { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px 16px; }

/* --- page layout helpers: a card over the full width; a card hidden by a sub-tab; one card alone fills the row */
.full { grid-column: 1 / -1; }
.offsub { display: none !important; }
main.dash.solo > section.card:not(.offsub) { grid-column: 1 / -1 !important; }

/* --- top bar extras: version (click for the version history), server load meter, status dots, links to the other programs */
header .ver { color: var(--bar-muted); font-size: 12.5px; white-space: nowrap; cursor: pointer; }
header .ver:empty { display: none; }
header .ver:hover { color: var(--on-bar); text-decoration: underline; }
header .livegrp { display: flex; align-items: center; gap: 10px; }
@media (max-width: 1600px) { header .ver { display: none; } }
.pcw { display: inline-grid; grid-template-columns: auto 30px auto; align-items: center; gap: 1px 6px; padding: 3px 8px; background: transparent;
  border: 1px solid rgba(255,255,255,.18); border-radius: 6px; color: var(--bar-muted); font: 600 10.5px/1.15 var(--sans); cursor: pointer; font-variant-numeric: tabular-nums; }
.pcw:hover { border-color: rgba(255,255,255,.45); color: var(--on-bar); }
.pcw[hidden] { display: none; }
.pcw .l { text-align: left; } .pcw .v { text-align: right; min-width: 28px; }
.pcw .b { height: 4px; border-radius: 2px; background: rgba(255,255,255,.18); overflow: hidden; }
.pcw .b i { display: block; height: 100%; background: var(--mark-on); }
.pcw .b.hi i { background: var(--mark-wait); } .pcw .b.top i { background: var(--mark-off); }
.dots { display: flex; flex-wrap: wrap; gap: 3px; align-items: center; max-width: 170px; cursor: pointer; padding: 5px 7px; border-radius: 6px; border: 1px solid rgba(255,255,255,.25); }
.dots:empty { display: none; }
.dots:hover { border-color: rgba(255,255,255,.6); }
.dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--mark-on); }
.dots i.off { background: var(--mark-off); border-radius: 1px; }
.dots i.wait { background: var(--mark-wait); border-radius: 1px; transform: rotate(45deg) scale(.8); }
.dots i.maint { background: var(--mark-maint); } .dots i.none { background: var(--mark-none); }
header .peer { padding-left: 10px; padding-right: 10px; }
@media (max-width: 1750px) { header .peer, header .user { display: none; } }
@media (max-width: 1400px) { .dots { display: none !important; } header .search input { width: 130px; } }
@media (max-width: 900px) { .pcw { display: none !important; } }
body.wall .pcw, body.wall .dots { display: none !important; }

/* --- status: maintenance is the fifth state (↻, blue); a small pill for lists */
.st.maint { background: var(--st-maint-bg); color: var(--st-maint-fg); } .st.maint::before { content: "↻"; }
.st.sm { min-width: 0; padding: 2px 9px; font-size: 11.5px; }
.badge.add { border-color: var(--st-on-fg); color: var(--st-on-fg); }
.badge.upd { border-color: var(--series-2); color: var(--series-2); }
.badge.err { border-color: var(--critical); color: var(--critical); }

/* --- tiles that are buttons (filter the list below), the status edge of a tile, the chosen tile, skeleton and changed values */
button.tile { font: inherit; color: inherit; text-align: left; cursor: pointer; width: 100%; }
button.tile:hover { border-color: var(--line-strong); }
.tile.k-down { border-top-color: var(--critical); } .tile.k-warn { border-top-color: var(--warning); }
.tile.k-maint { border-top-color: var(--maint); } .tile.k-events { border-top-color: var(--series-2); }
.tile.hero.k-up { border-top-color: var(--bar); }
.tile.sel { outline: 3px solid var(--focus-ring); outline-offset: -1px; }
.tile .value.bump { animation: dgr-bump 1.4s var(--ease); }
@keyframes dgr-bump { 0%, 25% { color: var(--series-1); } }
.tile .value.skelv { color: transparent; position: relative; }
.tile .value.skelv::after { content: ""; position: absolute; left: 0; top: 6px; width: 72px; height: 28px; border-radius: 6px; background: var(--shimmer); background-size: 200% 100%; animation: dgr-shimmer 1.3s linear infinite; }
.skel-lines { display: grid; gap: 10px; padding: 8px 0; }
.skel-lines .skel:nth-child(3n) { width: 62%; } .skel-lines .skel:nth-child(3n+2) { width: 84%; }

/* --- a list of things with a status (devices, cameras, people): status · name and detail · key figures; a reason line under it */
.devlist { display: grid; gap: 0; margin-top: 8px; }
.devrow { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 4px 12px; align-items: center; text-align: left; padding: 9px 4px;
  border: 0; border-bottom: 1px solid var(--border); background: none; color: inherit; font: inherit; cursor: pointer; width: 100%; }
.devrow:last-child { border-bottom: 0; }
.devrow:hover { background: var(--surface-2); }
.devrow .st { align-self: start; margin-top: 2px; }
.devrow .dn { display: block; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.devrow .ds { display: block; font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.devrow .dm { font-size: 12px; color: var(--text-secondary); text-align: right; white-space: nowrap; }
.devrow .dm b { color: var(--text-primary); }
.devrow .dr { grid-column: 2 / -1; font-size: 12px; font-weight: 600; color: var(--warning); }
.devrow .dr.bad { color: var(--critical); }
.card.site h2, .card h2.withsub { display: flex; align-items: baseline; gap: 10px; }
.card h2 small { font: 600 12.5px var(--sans); text-transform: none; letter-spacing: 0; color: var(--text-secondary); }

/* --- table tools: search and count, column picker, sortable headers, edit-in-place tables, selected and grouped rows */
.tbar { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; margin: 0 0 10px; }
:is(.controls, .filters, .toolbar, .tbar) > label:not(.chk) { font-size: 13px; font-weight: 600; color: var(--text-secondary); margin: 0; }
:is(.controls, .filters, .toolbar, .tbar) > span:not(.muted):not(.badge) { font-size: 13px; color: var(--text-secondary); }
:is(.controls, .filters, .toolbar, .tbar) .muted { font-size: 13px; }
:is(.controls, .filters, .toolbar, .tbar) .chk { padding: 0; }
:is(.controls, .filters, .toolbar, .tbar) :is(.btn, .colpick > summary) { min-height: var(--ctl-h); }
:is(.controls, .filters, .toolbar, .tbar) > label:not(.chk) + :is(input, select) { margin-left: -4px; }
@media (max-width: 640px) {
  :is(.controls, .filters, .toolbar, .tbar) > label:not(.chk) { flex: 0 0 100%; margin: 2px 0 -4px; }
  :is(.controls, .filters, .toolbar, .tbar) > :is(input, select) { flex: 1 1 100%; width: 100% !important; margin-left: 0; }
}
.tbar .tq { width: 220px; max-width: 100%; }
.tbar .tcount { font-size: 12.5px; }
.colpick { position: relative; display: inline-block; flex: none; }
.colpick > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; margin-top: 0; font: 700 12px/16px var(--sans); padding: 4px 10px;
  border: 1px solid var(--line-strong); border-radius: var(--r); color: var(--text-primary); background: var(--surface-1); }
.colpick > summary .muted { font-weight: 600; }
.colpick > summary::-webkit-details-marker { display: none; }
.colpick[open] > summary { background: var(--surface-2); }
.colpick .cp { position: absolute; z-index: 20; top: calc(100% + 4px); right: 0; left: auto; max-width: calc(100vw - 32px); background: var(--surface-1); border: 1px solid var(--line-strong);
  border-radius: var(--r); padding: 8px 12px; min-width: 190px; box-shadow: 0 4px 14px rgba(0,0,0,.15); }
.colpick .cp label { display: flex; gap: 8px; align-items: center; font-size: 13px; padding: 3px 0; white-space: nowrap; cursor: pointer; }
.colpick .cp .muted { font-size: 12px; display: block; margin-top: 6px; }
th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover, th.sortable:focus-visible { text-decoration: underline; outline: none; }
th .sarr { font-size: 10px; }
table.edit td { padding: 4px 6px; }
table.edit input.in, table.edit select.in { padding: 0 7px; min-width: 70px; height: 30px; }
td.empty .eh { display: block; font-size: 12.5px; margin-top: 4px; }
table.keys td { padding: 5px 10px 5px 0; white-space: normal; }
tr.sel td { background: color-mix(in srgb, var(--accent) 12%, transparent); }
tr.sel td:first-child { box-shadow: inset 4px 0 0 var(--accent); }
tr.runsep td { border-top: 2px solid var(--line-strong); }
time.rel { white-space: nowrap; border-bottom: 1px dotted var(--line-strong); cursor: help; }
.over { font-weight: 700; color: var(--series-2); }

/* --- settings pages: section pills on the left of the settings, day picker, a button that wants attention */
.subnav { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 18px; }
.subnav button { border: 1px solid var(--line-strong); background: var(--surface-1); color: var(--text-secondary); border-radius: 9999px; padding: 6px 14px; font: 600 13.5px var(--sans); cursor: pointer; }
.subnav button[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
@media (max-width: 900px) { .subnav { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; } .subnav button { white-space: nowrap; flex: none; } }
.daypick { display: flex; flex-wrap: wrap; gap: 4px 12px; } .daypick label { display: inline-flex; gap: 4px; align-items: center; font-size: 13.5px; }
.btn.primary.attn { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent); }
textarea.in.mono { min-height: 160px; font: 12.5px/1.4 ui-monospace, Consolas, monospace; }

/* --- long text: log viewer, code and command output, numbered steps */
.logview { margin: 0; max-height: 560px; overflow: auto; background: var(--surface-2); border: 1px solid var(--line-strong); border-radius: var(--r); padding: 10px 12px;
  font: 12px/1.45 ui-monospace, Consolas, monospace; white-space: pre-wrap; word-break: break-word; }
.logview .lv-w { color: var(--series-2); font-weight: 600; } .logview .lv-e { color: var(--critical); font-weight: 700; } .logview .lv-d { opacity: .7; }
.logview mark { background: var(--accent); color: var(--on-accent); border-radius: 2px; }
.code { font: 12px/17px ui-monospace, Consolas, monospace; white-space: pre-wrap; background: var(--surface-2); padding: 10px; border-radius: 4px; max-height: 420px; overflow: auto; }
.steps { margin: 6px 0 12px; padding-left: 20px; } .steps li { margin: 4px 0; }
mark.d { background: var(--series-2); color: #fff; padding: 0 1px; }

/* --- version history (dialog and page) */
.changelog { font-size: 14px; line-height: 21px; max-height: 70vh; overflow: auto; }
.changelog h3 { font: 700 18px/24px var(--display); text-transform: uppercase; margin: 18px 0 6px; }
.changelog h3:first-child { margin-top: 0; }
.changelog .cur { font: 600 11px/16px var(--sans); text-transform: none; border: 1px solid var(--line-strong); border-radius: 9999px; padding: 1px 8px; margin-left: 8px; vertical-align: middle; }
.changelog ul { margin: 4px 0 8px; padding-left: 20px; } .changelog li { margin: 2px 0; } .changelog p { margin: 6px 0; }
.changelog code { font-size: 12.5px; background: var(--surface-2); padding: 0 4px; border-radius: 3px; }
.changelog table { border-collapse: collapse; margin: 8px 0; font-size: 13px; }
.changelog td, .changelog th { border: 1px solid var(--border); padding: 3px 8px; text-align: left; }
.cl-page { max-height: none; }
.cl-page details { border-bottom: 1px solid var(--border); padding: 6px 0; }
.cl-page summary { cursor: pointer; font: 700 16px/24px var(--display); text-transform: uppercase; color: var(--text-primary); }

/* --- the manual: contents with search on the left, the text on the right; prints on its own */
.man { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 24px; align-items: start; }
.man-toc { position: sticky; top: 12px; display: flex; flex-direction: column; gap: 10px; max-height: calc(100vh - 24px); overflow: auto; }
.man-toc nav a { display: block; padding: 4px 8px; border-radius: 6px; color: var(--text-secondary); text-decoration: none; font-size: 14px; }
.man-toc nav a:hover, .man-toc nav a.on { background: var(--surface-2); color: var(--text-primary); }
.man-toc nav a.sub { padding-left: 20px; font-size: 13px; }
.man-body { max-width: 980px; line-height: 1.55; }
.man-body h2 { margin: 28px 0 8px; padding-top: 6px; border-top: 1px solid var(--border); }
.man-body h2:first-child { border-top: 0; margin-top: 0; }
.man-body h3 { margin: 18px 0 6px; font-size: 15px; }
.man-body table { border-collapse: collapse; margin: 8px 0 12px; width: 100%; }
.man-body th, .man-body td { border: 1px solid var(--border); padding: 6px 10px; text-align: left; vertical-align: top; white-space: normal; }
.man-body th { background: var(--surface-2); color: var(--text-primary); position: static; }
.man-body ul { margin: 6px 0 10px 20px; padding: 0; }
.man-body code { background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }
.man-note { color: var(--text-muted); font-size: 13px; }
.man-sec[hidden] { display: none; }
mark.mhit { background: #ffe58a; color: #222; border-radius: 2px; }
main.manual { max-width: var(--page-max, none); margin: 0 auto; padding: 20px 24px 40px; display: block; }
@media (max-width: 760px) { .man { grid-template-columns: 1fr; } .man-toc { position: static; max-height: none; } }
@media print {
  .man-toc, .upd-banner, body[data-view="manual"] main:not(.manual) { display: none !important; }
  body[data-view="manual"] main.manual { display: block !important; padding: 0; }
  .man { display: block; } .man-body { border: 0; box-shadow: none; max-width: none; }
  .man-sec[hidden] { display: block !important; }
  .man-body h2 { break-before: auto; break-after: avoid; } .man-body table { table-layout: fixed; }
  .man-body td, .man-body th { overflow-wrap: anywhere; }
}

/* --- update banner (a new version is installed: reload) and a notice line under the tabs */
.upd-banner { display: flex; gap: 10px; align-items: center; justify-content: center; padding: 6px 12px; background: var(--st-on-bg); color: var(--st-on-fg); font-size: 14px; }
.upd-banner a { color: inherit; font-weight: 700; cursor: pointer; text-decoration: underline; }
.noticebar:empty { display: none; }

/* --- the busy bar shows itself while the page waits for the server (body.busy); cards dim a little */
.busybar.auto { display: none; }
body.busy .busybar.auto { display: block; }
body.busy main:not([hidden]) .card { transition: opacity .2s; opacity: .62; }

/* --- progress: a bar with stripes while it runs, and the job bar under the tabs (what runs now, its steps, its waits) */
.im-bar { flex: 0 0 auto; width: 640px; max-width: 100%; height: 10px; border-radius: 5px; background: color-mix(in srgb, var(--series-1) 15%, transparent); overflow: hidden; }
.im-bar i { display: block; height: 100%; width: 0; background: var(--series-1); transition: width .4s;
  background-image: linear-gradient(45deg, rgba(255,255,255,.18) 25%, transparent 25% 50%, rgba(255,255,255,.18) 50% 75%, transparent 75%); background-size: 16px 16px; animation: dgr-stripes 1s linear infinite; }
@keyframes dgr-stripes { to { background-position: 16px 0; } }
.jobbar { display: none; padding: 6px 24px; font-size: 13px; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.jobbar.on { display: flex; flex-direction: column; gap: 4px; }
.jobbar .jb { display: grid; grid-template-columns: minmax(0, 360px) minmax(0, 640px) auto; align-items: center; gap: 10px; }
.jobbar .jb > b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jobbar .jb .btn { margin-left: 6px; }
.jobbar .im-bar { max-width: 640px; }
.jobbar .jb-now { display: flex; align-items: center; gap: 8px; font-weight: 600; min-width: 0; }
.jobbar .jb-now > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.jobbar .jb-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--series-2); flex: none; animation: dgr-blink 1.4s ease-in-out infinite; }
@keyframes dgr-blink { 50% { opacity: .25; } }
.jobbar .jb-wbar { display: inline-block; width: 120px; height: 6px; border-radius: 3px; background: var(--border); vertical-align: middle; overflow: hidden; margin-left: 4px; }
.jobbar .jb-wbar i { display: block; height: 100%; background: var(--series-2); transition: width 1s linear; }
.jobbar .jb-log summary { cursor: pointer; font-size: 12.5px; color: var(--text-muted); margin-top: 0; }
.jobbar .jb-log ol { list-style: none; margin: 4px 0 2px; padding: 0; font-size: 12.5px; display: grid; gap: 2px; }
.jobbar .jb-log li { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jobbar .jb-log li.bad { color: var(--critical); }
@media (max-width: 900px) { .jobbar { padding: 6px 12px; } .jobbar .jb { grid-template-columns: 1fr; } }

/* --- the side panel can be made wider (drag its edge, or ‹ ›); its content never gets wider than the panel */
dialog .db { grid-template-columns: minmax(0, 1fr); }
dialog .db > * { min-width: 0; }
dialog.side { width: min(var(--qv-w, 560px), 100vw); max-width: 100vw; }
.qv-grip { position: absolute; left: 0; top: 0; bottom: 0; width: 8px; cursor: ew-resize; z-index: 2; touch-action: none; }
.qv-grip:hover, .qv-grip.on { background: color-mix(in srgb, var(--series-2) 35%, transparent); }
.qv-dh { display: flex; align-items: center; gap: 10px; }
.qv-dh > .qv-title { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; overflow-wrap: anywhere; }
.qv-title .st { font-family: var(--sans); text-transform: none; letter-spacing: 0; }
.qv-size { display: inline-flex; gap: 4px; flex: none; }
.qv-size .btn { border-color: var(--bar-muted); background: transparent; color: var(--on-bar); padding: 2px 9px; line-height: 1.2; font-size: 16px; }
@media (max-width: 640px) { .qv-size, .qv-grip { display: none; } dialog.side { width: 100vw; } }
dialog.side .kvs .kv > span:last-child { white-space: normal; }
dialog.side th, dialog.side td { padding: 6px 8px; }
dialog.side .tablewrap { max-height: none; }
/* readings you can click to see their history; the path from here to the core */
.qv-metrics { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(130px, 100%), 1fr)); gap: 8px; }
.qv-metrics button { text-align: left; border: 1px solid var(--border); border-top: 4px solid var(--border); border-radius: var(--r); padding: 6px 10px; background: var(--surface-1); color: inherit; font: inherit; cursor: pointer; }
.qv-metrics button[aria-pressed="true"] { border-top-color: var(--series-2); }
.qv-metrics button:disabled { cursor: default; }
.qv-metrics b { display: block; font: 700 12px/16px var(--display); text-transform: uppercase; letter-spacing: .05em; color: var(--text-secondary); }
.qv-metrics span { font-size: 15px; font-weight: 700; }
.qv-path { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; font-size: 13px; }
.qv-path a { cursor: pointer; }
.ifmore { margin-top: 6px; }

/* --- import preview: counts of new / update / skipped above the table */
.imp-sum { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 10px; }

/* --- diagrams (network map, site plan): a pannable canvas, boxes with a status stripe, lines, flows, groups, legend */
.mapwrap { position: relative; overflow: auto; height: max(460px, calc(100vh - 340px)); border: 1px solid var(--border); border-radius: var(--r); background: var(--surface-2); cursor: grab; touch-action: none; }
.mapwrap.drag { cursor: grabbing; user-select: none; }
.mapwrap svg { display: block; }
.mapwrap .empty { padding: 40px; text-align: center; }
.maplegend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 12.5px; color: var(--text-secondary); margin: 0 0 8px; }
.maplegend span { display: inline-flex; align-items: center; gap: 6px; }
.maplegend svg { overflow: visible; }
.maplegend i { display: inline-block; width: 10px; height: 10px; border-radius: 50%; }
.mp-node, .pl-node { cursor: pointer; }
.mp-node rect.box, .pl-node rect.box { fill: var(--surface-1); stroke: var(--line-strong); stroke-width: 1; }
.mp-node:hover rect.box, .mp-node:focus rect.box, .pl-node:hover rect.box { stroke: var(--series-2); stroke-width: 2; }
.mp-node.hit rect.box { stroke: var(--focus-ring); stroke-width: 3; }
.mp-node.core rect.box { fill: var(--accent); stroke: var(--accent); }
.mp-node.core text { fill: var(--on-accent) !important; }
.mp-node text.n, .pl-node text.n { font: 700 12.5px var(--sans); fill: var(--text-primary); }
.mp-node text.s, .pl-node text.s { font: 11px var(--sans); fill: var(--text-muted); }
rect.stripe.up { fill: var(--mark-on); } rect.stripe.warn { fill: var(--mark-wait); } rect.stripe.down { fill: var(--mark-off); }
rect.stripe.maint { fill: var(--mark-maint); } rect.stripe.unknown { fill: var(--mark-none); }
.mp-edge { fill: none; stroke: var(--line-strong); stroke-linecap: round; opacity: .75; }
.mp-edge.down { stroke: var(--critical); stroke-dasharray: 6 5; opacity: 1; }
.mp-edge.manual { stroke-dasharray: 2 6; opacity: .6; }
.mp-edge.site { stroke-dasharray: 8 6; opacity: .6; }
.mp-extra { fill: none; stroke: var(--maint); stroke-width: 2.5px; stroke-dasharray: 7 5; opacity: .9; }
.mp-flow { fill: none; stroke: var(--series-2); stroke-linecap: round; stroke-dasharray: 2 14; animation: dgr-flow 1.4s linear infinite; opacity: .9; }
.mp-flow.up { animation-direction: reverse; }
@keyframes dgr-flow { to { stroke-dashoffset: -16; } }
.mp-lbl { font: 600 10.5px var(--sans); fill: var(--text-secondary); paint-order: stroke; stroke: var(--surface-2); stroke-width: 4px; stroke-linejoin: round; }
.mp-sec, .pl-head { font: 700 12px var(--display); letter-spacing: .05em; text-transform: uppercase; fill: var(--text-muted); }
.mp-site rect { fill: var(--surface-1); fill-opacity: .55; stroke: var(--border); stroke-width: 1.5; }
.mp-site.core rect { stroke: var(--accent); stroke-width: 2; }
.mp-site text { font: 700 12px var(--display); letter-spacing: .05em; text-transform: uppercase; fill: var(--text-secondary); }
.mp-site .cnt { font: 600 11px var(--sans); letter-spacing: 0; text-transform: none; fill: var(--text-muted); }
.mp-sitelbl { paint-order: stroke; stroke: var(--surface-2); stroke-width: 4px; stroke-linejoin: round; }
/* the plan of one group (site): the groups on the left, the drawing, then the add row */
.plan { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 18px; align-items: start; }
.plan-sites { display: flex; flex-direction: column; gap: 4px; position: sticky; top: 140px; max-height: calc(100vh - 160px); overflow: auto; }
.plan-sites button { display: flex; justify-content: space-between; gap: 8px; text-align: left; border: 1px solid var(--border); background: var(--surface-1); color: var(--text-primary);
  border-radius: var(--r); padding: 7px 10px; font: 600 13.5px var(--sans); cursor: pointer; }
.plan-sites button[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.plan-sites button small { font-weight: 600; opacity: .75; }
@media (max-width: 900px) { .plan { grid-template-columns: 1fr; } .plan-sites { flex-direction: row; flex-wrap: wrap; position: static; max-height: none; } }
.plan-svg { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface-2); overflow-x: auto; margin: 6px 0 14px; }
.plan-svg svg { display: block; touch-action: pan-y; user-select: none; }
.pl-node.remote rect.box { fill: var(--surface-2); stroke-dasharray: 4 3; }
.pl-node.switch rect.box { stroke-dasharray: 6 3; stroke-width: 1.5; }
.pl-link { fill: none; stroke: var(--line-strong); stroke-width: 2.2px; }
.pl-link.radio { stroke-dasharray: 8 5; }
.pl-link.failover { stroke: var(--maint); stroke-dasharray: 3 5; }
.plan-add { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; margin-top: 10px; }
.plan-add select, .plan-add input { width: auto; min-width: 160px; }
/* drag and drop to link two boxes: the box you drag from, the box you drop on, the line while dragging */
.dragsrc rect.box { stroke: var(--series-2); stroke-width: 2.5; }
.droptgt rect.box { stroke: var(--accent); stroke-width: 3; fill: var(--surface-2); }
.pl-drag { stroke: var(--accent); stroke-width: 2.5; stroke-dasharray: 6 4; fill: none; pointer-events: none; }
.dragging, .dragging .pl-node { cursor: crosshair; }

/* --- wall display: one card per problem with a coloured edge; a big "all fine" when there is none */
.wallbar { display: none; }
body.wall .wallbar { display: flex; align-items: center; gap: 16px; }
body.wall .wallbar .clock { font: 700 30px/1 var(--display); color: var(--on-bar); }
body.wall header .btn:not(.wall-exit), body.wall header .user, body.wall header .ver, body.wall .tbar { display: none !important; }
.wallgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 12px; }
.wallcard { border: 1px solid var(--border); border-left: 6px solid var(--warning); border-radius: var(--r); padding: 12px 16px; background: var(--surface-1); }
.wallcard.down { border-left-color: var(--critical); } .wallcard.maint { border-left-color: var(--maint); }
.wallcard b { display: block; font: 700 22px/28px var(--display); text-transform: uppercase; }
.wallok { font: 700 40px/50px var(--display); text-transform: uppercase; color: var(--st-on-fg); text-align: center; padding: 60px 0; }
@media print { .jobbar, .tbar, header .ver, .live-btn { display: none !important; } }

/* --- the band at the foot of every page: "Dinokeng Game Reserve: <program>" */
footer.band { background: var(--band); color: var(--on-band); padding: 12px 24px; font: 700 14px/20px var(--display); text-transform: uppercase; letter-spacing: .03em; display: flex; flex-wrap: wrap; gap: 6px; }
footer.band span { font-weight: 300; }

/* --- from Dinokeng ANPR, kept for every program (1.1.0): dashboard cards line up, empty tables, clickable rows, keys, touch, tablets */
main.dash > .card { display: flex; flex-direction: column; }
main.dash > .card > .chart { margin-top: auto; }
main.dash > .card > .desc { min-height: 38px; }
.kpis svg { max-width: 100%; }
.cardhead > .btn, .cardhead > a.btn, .cardhead > label { margin-top: 2px; }
td.empty { padding: 26px 16px !important; text-align: center; color: var(--text-muted); white-space: normal; }
td.empty::before { content: "∅"; display: block; font-size: 22px; opacity: .45; margin-bottom: 2px; }
tr.click { cursor: pointer; }
tr.click:hover td { background: var(--surface-2); }
.badge.in { color: var(--text-primary); border-color: var(--series-2); }
.btn.is-busy { cursor: progress; }
.btn.is-done:not(.primary):not(.danger):not(.solid) { border-color: var(--st-on-fg); color: var(--st-on-fg); }
kbd { font: 600 12px ui-monospace, Consolas, monospace; border: 1px solid var(--line-strong); border-bottom-width: 2px; border-radius: 4px; padding: 1px 6px; background: var(--surface-2); }
input[type=file] { font: 13px var(--sans); color: var(--text-secondary); }
dialog.side form { display: flex; flex-direction: column; min-height: 100%; }
@media (max-width: 1500px) { header { column-gap: 14px; } header .user { display: none; } }
@media (max-width: 760px) {
  header, nav.bar, main { padding-left: 16px; padding-right: 16px; }
  .kpis { grid-template-columns: 1fr 1fr; } .tile.hero { grid-column: 1 / -1; }
  .tile .value { font-size: 28px; } .tile.hero .value { font-size: 36px; }
  .sticky { position: static; }
  .savebar { margin: 0 -16px -48px; padding: 12px 16px; }
}
@media (max-width: 640px) {
  table.cards, table.cards tbody { display: block; width: 100%; }
  table.cards td[data-l=""]::before { content: none; }
  table.cards td.empty { text-align: center; justify-content: center; }
  main.dash .tablewrap { max-height: none; border: 0; }
}
@media (pointer: coarse) { .btn { min-height: 40px; } .btn.small { min-height: 34px; } .in { min-height: 40px; } }
body.wall header .search, body.wall .subbar, body.wall footer, body.wall .filters, body.wall .savebar { display: none !important; }
body.wall main { zoom: 1.2; }
/* fields in a filter row without .in still look like fields */
.filters select, .filters input:not([type=checkbox]):not([type=radio]) { height: var(--ctl-h); padding: 0 10px; border: 1px solid var(--line-strong); border-radius: var(--r);
  background: var(--surface-1); color: var(--text-primary); font: 13.5px var(--sans); }
@media (max-width: 640px) { header.open .user.in-menu { display: block !important; order: 12; flex-basis: 100%; } }

/* ==========================================================================================================
   14. Live toggles (1.1.1): a Live switch anywhere on a page (not only in the top bar) and what it changes
   ========================================================================================================== */
/* the switch: grey dot when off; green pulsing dot and the pressed look when on */
.btn.live-btn { display: inline-flex; align-items: center; gap: 7px; }
.btn.live-btn::before { content: ""; flex: 0 0 9px; width: 9px; height: 9px; border-radius: 50%; background: var(--mark-none); }
.btn.live-btn[aria-pressed="true"]::before { background: var(--mark-on); box-shadow: 0 0 0 3px rgba(47,191,91,.25); animation: dgr-livepulse 2s infinite; }
main .btn.live-btn[aria-pressed="true"] { border-color: var(--st-on-fg); background: var(--st-on-bg); color: var(--st-on-fg); }
/* the line that says it is live: "live: 14 links every 5 s · 12:31:05" */
.live-note { display: inline-flex; align-items: center; gap: 6px; color: var(--st-on-fg); font-weight: 600; }
.live-note::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--mark-on); animation: dgr-blink 1.4s ease-in-out infinite; }
/* lines with a live reading are drawn full strength; a number that just changed flashes once */
.mp-edge.live { opacity: 1; }
.mp-chg { animation: dgr-chg 1.2s var(--ease-out); }
@keyframes dgr-chg { 0%, 30% { fill: var(--series-2); } }

/* ==========================================================================================================
   15. Clickable links and requirements in diagrams (1.2.1)
   ========================================================================================================== */
/* a wide invisible line on top of each link takes the click; the link brightens on hover */
.mp-hit { fill: none; stroke: transparent; stroke-width: 14px; pointer-events: stroke; cursor: pointer; }
.mp-link:hover .mp-edge, .mp-link:focus .mp-edge, .mp-link:hover .mp-extra { opacity: 1; stroke: var(--series-2); }
.mp-link:focus { outline: none; }
/* a link that cannot carry what it must: amber, dashed, its label says by how much */
.mp-edge.short, .mp-extra.short { stroke: var(--mark-wait); stroke-dasharray: 10 4; opacity: 1; }   /* amber in both themes: brown is the normal line colour in light mode */
.mp-need { font-weight: 700; fill: var(--text-secondary); }
.mp-need.short { fill: var(--warning); }
/* (1.2.2) the link type in the middle of a link: radio = circle with waves, cable = a small plug */
.mp-med circle, .mp-med rect { fill: var(--surface-1); stroke: var(--line-strong); stroke-width: 1.2; }
.mp-med path { fill: none; stroke: var(--text-secondary); stroke-width: 1.4; stroke-linecap: round; }
.mp-med .dot { fill: var(--text-secondary); stroke: none; }
.mp-med.radio circle:not(.dot) { stroke: var(--series-2); }
.mp-med { pointer-events: none; }
/* folding a group (site) into one tile: click its name; the folded tile is dashed and says how many it holds */
.mp-fold { cursor: pointer; }
.mp-fold:hover text, .mp-fold:focus text { fill: var(--text-primary); text-decoration: underline; }
.mp-fold:focus { outline: none; }
.mp-node.folded rect.box { stroke-dasharray: 5 3; stroke-width: 1.6; fill: var(--surface-2); }
/* the same clickable links and requirement colour on a plan */
.pl-lk { cursor: pointer; }
.pl-lk:hover .pl-link { stroke: var(--series-2); }
.pl-link.short { stroke: var(--mark-wait); stroke-dasharray: 10 4; }
/* (1.2.2) the add button at the end of a list of groups */
.plan-sites .pl-siteadd { justify-content: center; border-style: dashed; color: var(--text-secondary); background: transparent; }
.plan-sites .pl-siteadd:hover { color: var(--text-primary); border-color: var(--line-strong); }

/* ==========================================================================================================
   16. Unreachable (1.2.3): a device that is down only because something on its path is down.
       Neutral and dashed – not a second alarm – and always says what it is behind.
   ========================================================================================================== */
.st.unreach { background: transparent; color: var(--text-secondary); box-shadow: inset 0 0 0 1px var(--line-strong); } .st.unreach::before { content: "⇣"; }
.dots i.unreach { background: transparent; box-shadow: inset 0 0 0 1.5px var(--mark-off); }
rect.stripe.unreach { fill: var(--mark-none); }
.mp-node.unreach rect.box, .mp-node:has(rect.stripe.unreach) rect.box { stroke-dasharray: 4 3; opacity: .8; }
.tile.k-unreach { border-top-color: var(--line-strong); border-top-style: dashed; }

/* ==========================================================================================================
   17. Statistics pages (1.2.4): ranking bars with a target line, values with decimals, print as a report
   ========================================================================================================== */
.hbars .t { position: relative; }
.hbars .t .tg { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--text-primary); opacity: .55; border-radius: 1px; }
.hbars .t i.low { background: var(--warning); }
.hbars .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.hbars .r small { font-size: 11px; }
.st-av .r, #stBusy .hbars .r { grid-template-columns: minmax(90px, 32%) 1fr 74px; }
@media print {
  body[data-view="stats"] main:not(#view-stats) { display: none !important; }
  body[data-view="stats"] #view-stats { display: grid !important; grid-template-columns: 1fr 1fr; padding: 0; }
  body[data-view="stats"] #view-stats .seg, body[data-view="stats"] #view-stats .cardhead .btn { display: none !important; }
}

/* ==========================================================================================================
   18. Motion that tells (1.2.5): a row that changed flashes once; a failure runs down the lines behind it
   ========================================================================================================== */
.devrow.chg-bad { animation: dgr-chg-bad 1.8s var(--ease-out); }
.devrow.chg-good { animation: dgr-chg-good 1.8s var(--ease-out); }
@keyframes dgr-chg-bad { 0%, 25% { background: color-mix(in srgb, var(--critical) 22%, transparent); } }
@keyframes dgr-chg-good { 0%, 25% { background: color-mix(in srgb, var(--mark-on) 22%, transparent); } }
/* the red dashes run from the failed device outwards along every link behind it */
.mp-ripple { fill: none; stroke: var(--critical); stroke-width: 2.5px; stroke-linecap: round; stroke-dasharray: 3 13; opacity: .85; animation: dgr-flow 1.1s linear infinite; pointer-events: none; }
.mp-edge.unreach { stroke: var(--line-strong); stroke-dasharray: 3 5; opacity: .7; }
.wallok { animation: dgr-rise .6s var(--ease-out) both; }
.rl-msg { white-space: normal; font-family: ui-monospace, Consolas, monospace; font-size: 12.5px; }
