/* ─── THEME VARIABLES ─── */
:root, [data-theme="light"] {
  --bg: #f5f7fb;
  --surface: #ffffff;
  --surface-2: #f0f3f9;
  --surface-3: #e8edf5;
  --border: #e0e5ee;
  --border-bright: #c5cfde;
  --text: #0a0e17;
  --text-muted: #5d6987;
  --text-dim: #8a96b3;
  --amber: #d97706;
  --amber-bg: #fef3c7;
  --amber-border: #fbbf24;
  --green: #059669;
  --green-bg: #d1fae5;
  --green-border: #6ee7b7;
  --red: #dc2626;
  --red-bg: #fee2e2;
  --red-bg-strong: #fecaca;
  --red-border: #f87171;
  --red-bright: #dc2626;
  --cyan: #0891b2;
  /* Tinted panels used by the onboarding view */
  --accent-bg: #eff6ff;
  --accent-border: #dbeafe;
  --violet: #7c3aed;
  --shadow: 0 1px 3px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04);
  --bg-pattern: none;
  --bg-fade: rgba(245, 247, 251, 0.35);
  --panel-shadow: 10px 0 30px rgba(15, 23, 42, 0.10);
  --map-fallback: #e8edf5;
  --tile-filter: none;
}

[data-theme="dark"] {
  --bg: #0a0e17;
  --surface: #131a2a;
  --surface-2: #1a2236;
  --surface-3: #222c44;
  --border: #243049;
  --border-bright: #324363;
  --text: #e8edf5;
  --text-muted: #8a96b3;
  --text-dim: #5d6987;
  --amber: #ffa940;
  --amber-bg: rgba(255, 169, 64, 0.12);
  --amber-border: rgba(255, 169, 64, 0.45);
  --green: #3ddc97;
  --green-bg: rgba(61, 220, 151, 0.12);
  --green-border: rgba(61, 220, 151, 0.45);
  --red: #ff5470;
  --red-bg: rgba(255, 84, 112, 0.12);
  --red-bg-strong: rgba(255, 84, 112, 0.18);
  --red-border: rgba(255, 84, 112, 0.45);
  --red-bright: #ff3355;
  --cyan: #4ecdc4;
  --accent-bg: rgba(78, 205, 196, 0.10);
  --accent-border: rgba(78, 205, 196, 0.28);
  --violet: #9b8aff;
  --shadow: 0 0 24px rgba(0, 0, 0, 0.4);
  --bg-pattern:
    radial-gradient(ellipse at top left, rgba(78, 205, 196, 0.04), transparent 50%),
    radial-gradient(ellipse at bottom right, rgba(155, 138, 255, 0.04), transparent 50%);
  --bg-fade: rgba(10, 14, 23, 0.4);
  --panel-shadow: 10px 0 30px rgba(0, 0, 0, 0.5);
  --map-fallback: #1a2236;
  --tile-filter: invert(100%) hue-rotate(180deg) brightness(95%) contrast(90%);
}

/* ─── RESET ─── */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: 'Bricolage Grotesque', system-ui, sans-serif;
  background: var(--bg);
  background-image: var(--bg-pattern);
  color: var(--text);
  min-height: 100vh;
  font-size: 14px;
  line-height: 1.5;
}
.mono { font-family: 'JetBrains Mono', ui-monospace, monospace; }
button { font-family: inherit; cursor: pointer; }
input, select { font-family: inherit; }

/* ─── TOPBAR ─── */
.topbar {
  display: flex; align-items: center; gap: 24px;
  padding: 14px 24px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.brand {
  display: flex; align-items: center; gap: 12px; flex-shrink: 0;
  text-decoration: none; color: inherit;
}
.logo { display: flex; align-items: center; flex-shrink: 0; }

/* Full logo lockup — the wordmark lives in the image, so no brand text beside it.
   Two files: one drawn for dark backgrounds, one for light. Light is the
   default, matching the default palette, so no wrong-logo flash on load. */
.brand-logo { height: 42px; width: auto; display: block; }
.brand-logo-dark { display: none; }
[data-theme="dark"] .brand-logo-light { display: none; }
[data-theme="dark"] .brand-logo-dark { display: block; }

.brand-dept {
  color: var(--text-dim); font-family: 'JetBrains Mono', monospace; font-size: 11px;
  font-weight: 400; text-transform: uppercase; letter-spacing: 0.06em;
  padding-left: 12px; border-left: 1px solid var(--border);
}

.tabs { display: flex; gap: 4px; }
.tab {
  padding: 8px 14px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  text-decoration: none;
}
.tab:hover { color: var(--text); }
.tab.active {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text);
}

.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px var(--green); }
.dot.red { background: var(--red); box-shadow: 0 0 8px var(--red); animation: pulse 1.2s infinite; }
.dot.amber { background: var(--amber); box-shadow: 0 0 6px var(--amber); }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }

.topbar-right { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.icon-btn {
  width: 36px; height: 36px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted);
  font-family: 'JetBrains Mono', monospace;
  text-decoration: none;
  font-size: 14px;
}
.icon-btn:hover { color: var(--text); border-color: var(--border-bright); }

/* A header button carrying a word instead of a single glyph. .icon-btn is a
   fixed 36px square, so text overflows it — this keeps the same visual family
   but sizes to its label. Both header rows already set their own gap, so no
   margins here. */
.text-btn {
  height: 36px;
  padding: 0 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--text-muted);
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px; font-weight: 600;
  text-decoration: none; white-space: nowrap;
  cursor: pointer;
}
.text-btn:hover { color: var(--text); border-color: var(--border-bright); }
.text-btn.danger {
  background: var(--red-bg); color: var(--red); border-color: transparent;
}
.text-btn.danger:hover { border-color: var(--red); color: var(--red); }
.time-stamp {
  font-family: 'JetBrains Mono', monospace; font-size: 12px;
  color: var(--text-muted);
  padding: 6px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.time-stamp b { color: var(--text); font-weight: 500; }

.ack-btn {
  padding: 6px 10px;
  background: var(--surface-2); border: 1px solid var(--border-bright);
  color: var(--text); border-radius: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.ack-btn:hover { border-color: var(--cyan); color: var(--cyan); }

/* ─── CONTAINER ─── */
.container { padding: 20px 24px; max-width: 1600px; margin: 0 auto; }

/* ─── KPI CARDS ─── */
.kpi-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 16px; }
.kpi-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 18px 20px;
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.kpi-card::before {
  content: ''; position: absolute; top: 0; left: 0;
  width: 3px; height: 100%; background: var(--cyan);
}
.kpi-card.green::before { background: var(--green); }
.kpi-card.red::before { background: var(--red); }
.kpi-card.red {
  background: linear-gradient(135deg, var(--surface) 0%, var(--red-bg) 100%);
  border-color: var(--red-border);
}
.kpi-label {
  font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 10px;
}
.kpi-value {
  font-size: 34px; font-weight: 600; letter-spacing: -0.03em;
  font-family: 'JetBrains Mono', monospace; line-height: 1; margin-bottom: 6px;
}
.kpi-card.red .kpi-value { color: var(--red); }
.kpi-delta { font-size: 12px; font-family: 'JetBrains Mono', monospace; color: var(--text-muted); }
.kpi-delta.red { color: var(--red); }

/* ─── CARD ─── */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  margin-bottom: 14px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.card-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex; justify-content: space-between; align-items: center;
}
.card-title { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }
.card-sub { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--text-dim); }

/* ─── TABLES ─── */
table { width: 100%; border-collapse: collapse; }
thead th {
  text-align: left; padding: 9px 18px;
  font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.1em; font-weight: 500;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
tbody td {
  padding: 10px 18px;
  font-size: 13px; vertical-align: middle;
  border-bottom: 1px solid var(--border);
}
tbody tr:last-child td { border-bottom: none; }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover td { background: var(--surface-2); }
tbody td.mono { font-family: 'JetBrains Mono', monospace; font-size: 12px; }

/* ─── PILLS & TAGS ─── */
.duration-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px;
  border-radius: 6px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px;
  font-weight: 600;
}
.duration-pill.ok { background: var(--green-bg); color: var(--green); }
.duration-pill.warn { background: var(--amber-bg); color: var(--amber); }
.duration-pill.alert { background: var(--red); color: #fff; }
.status-tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: 4px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.status-tag.alert { background: var(--red); color: #fff; }
.status-tag.warn { background: var(--amber-bg); color: var(--amber); border: 1px solid var(--amber-border); }
.status-tag.ok { background: var(--green-bg); color: var(--green); }
.status-tag.wl { background: rgba(155,138,255,0.15); color: var(--violet); border: 1px solid var(--violet); }
.tag-entry, .tag-exit, .tag-sighting {
  display: inline-block;
  padding: 2px 8px; border-radius: 4px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.tag-entry { background: var(--green-bg); color: var(--green); }
.tag-exit  { background: rgba(155,138,255,0.15); color: var(--violet); }
.tag-sighting { background: var(--surface-3); color: var(--text-muted); }

/* ─── THUMBNAIL ─── */
.thumb {
  width: 56px; height: 36px;
  border-radius: 4px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}
.thumb svg { width: 100%; height: 100%; }

/* ─── FILTER BAR ─── */
.filter-bar {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  padding: 14px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  margin-bottom: 14px;
  box-shadow: var(--shadow);
}
.filter-input, .filter-select {
  padding: 8px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-family: 'JetBrains Mono', monospace; font-size: 12px;
}
.filter-input:focus, .filter-select:focus { outline: none; border-color: var(--cyan); }
.filter-input.search { flex: 1; min-width: 220px; }
.filter-label {
  font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--text-dim);
  text-transform: uppercase; letter-spacing: 0.08em;
}
.export-btn {
  margin-left: auto;
  padding: 8px 14px;
  background: var(--cyan);
  color: #fff;
  border: none; border-radius: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.export-btn:hover { opacity: 0.9; }

/* ─── CHART ─── */
.chart-container { padding: 18px; }
.chart-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }

/* ─── MODAL ─── */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(5, 8, 15, 0.88);
  backdrop-filter: blur(8px);
  display: none; align-items: center; justify-content: center;
  z-index: 100; padding: 24px;
}
.modal-overlay.open { display: flex; }
.modal {
  background: var(--surface);
  border: 1px solid var(--border-bright);
  border-radius: 16px;
  width: 100%; max-width: 800px; max-height: 90vh;
  overflow: hidden;
}
.modal-header {
  padding: 18px 24px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 16px;
}
.modal-header h2 { font-size: 20px; font-weight: 600; letter-spacing: -0.02em; }
.modal-header .sub { font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--text-muted); }
.modal-close {
  margin-left: auto;
  padding: 6px 14px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  font-family: 'JetBrains Mono', monospace; font-size: 12px;
}
.modal-body { padding: 16px 24px; text-align: center; }
.modal-img {
  max-width: 100%; max-height: 60vh; border-radius: 8px;
  display: block; margin: 0 auto;
}
.modal-no-image {
  padding: 60px 20px; color: var(--text-dim);
  font-family: 'JetBrains Mono', monospace; font-size: 13px;
}

/* ─── WHITELIST PAGE ─── */
.admin-wrap { max-width: 800px; margin: 32px auto; padding: 0 24px; }
.admin-card {
  padding: 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow);
}
.admin-input { display: flex; gap: 8px; margin: 16px 0 24px; }
.admin-input input {
  flex: 1; padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text);
  font-family: 'JetBrains Mono', monospace; font-size: 13px;
}
.admin-input input:focus { outline: none; border-color: var(--cyan); }
.admin-input button {
  padding: 10px 18px;
  background: var(--cyan); color: #fff;
  border: none; border-radius: 6px;
  font-weight: 600; font-family: 'JetBrains Mono', monospace; font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.05em;
}
/* ─── Whitelist form ─── */
.wl-form { margin: 16px 0 24px; display: flex; flex-direction: column; gap: 12px; }
.wl-form-row { display: flex; gap: 10px; flex-wrap: wrap; }
.wl-form input[type="text"], .wl-form input:not([type]) {
  padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 6px; color: var(--text);
  font-family: 'JetBrains Mono', monospace; font-size: 13px;
}
.wl-form input:focus, .wl-form select:focus { outline: none; border-color: var(--cyan); }
.wl-form button {
  padding: 10px 18px;
  background: var(--cyan); color: #fff;
  border: none; border-radius: 6px; cursor: pointer;
  font-weight: 600; font-family: 'JetBrains Mono', monospace; font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.05em;
}
/* Typed plates are upper-cased for display; the hint stays normal case so it
   fits the field. */
#wl-badge::placeholder { text-transform: none; }

.wl-radio {
  display: flex; align-items: center; gap: 6px; cursor: pointer;
  font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--text-muted);
}
.wl-radio input { accent-color: var(--cyan); }
.wl-msg { font-family: 'JetBrains Mono', monospace; font-size: 12px; align-self: center; }
.wl-empty {
  text-align: center; padding: 30px;
  font-family: 'JetBrains Mono', monospace; font-size: 12px;
  color: var(--text-muted);
}

/* ─── Whitelist entry rows ─── */
.wl-state {
  font-family: 'JetBrains Mono', monospace; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  padding: 3px 8px; border-radius: 10px; border: 1px solid;
}
.wl-state.active    { background: var(--red-bg);   color: var(--red);       border-color: var(--red-border); }
.wl-state.scheduled { background: var(--amber-bg); color: var(--amber);     border-color: var(--amber-border); }
.wl-state.expired   { background: var(--surface-3); color: var(--text-dim); border-color: var(--border); }
.wl-state.off       { background: var(--surface-3); color: var(--text-dim); border-color: var(--border); }

/* on/off switch */
.wl-switch { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
.wl-switch input { display: none; }
.wl-switch .track {
  width: 38px; height: 20px; border-radius: 10px;
  background: var(--surface-3); border: 1px solid var(--border);
  position: relative; transition: background 0.15s, border-color 0.15s;
}
.wl-switch .track::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--text-dim); transition: transform 0.15s, background 0.15s;
}
.wl-switch input:checked + .track { background: var(--green-bg); border-color: var(--green-border); }
.wl-switch input:checked + .track::after { transform: translateX(18px); background: var(--green); }

.wl-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 8px;
}
.wl-row .label { font-family: 'JetBrains Mono', monospace; font-size: 13px; font-weight: 600; }
.wl-row .reason { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--text-muted); margin-left: 16px; }
.wl-row .added { font-family: 'JetBrains Mono', monospace; font-size: 10px; color: var(--text-dim); margin-right: 12px; }
.wl-row .window { font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--text-muted); display: block; margin-top: 4px; }
.wl-row .remove {
  padding: 6px 12px; background: var(--red-bg); color: var(--red);
  border: 1px solid var(--red-border); border-radius: 6px;
  font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em;
}
.notice {
  margin-top: 20px; padding: 14px 16px;
  background: var(--amber-bg);
  border: 1px solid var(--amber-border);
  border-radius: 8px;
  font-size: 12px;
  color: var(--text);
}
.notice b {
  color: var(--amber); font-family: 'JetBrains Mono', monospace;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
}

/* ─── MAIN GRID (premises + notifications side by side) ───────────────── */
.main-grid {
  display: grid;
  grid-template-columns: 1fr 380px;
  gap: 14px;
  margin-bottom: 14px;
}

/* ─── LIVE NOTIFICATIONS PANEL ────────────────────────────────────────── */
.notif-card {
  padding: 0;
  display: flex;
  flex-direction: column;
  max-height: 900px;
}
.notif-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.notif-list {
  overflow-y: auto;
  flex: 1;
}
.notif-item {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  display: flex;
  gap: 10px;
  align-items: center;
  cursor: pointer;
}
.notif-item:hover { background: var(--surface-2); }
.notif-item:last-child { border-bottom: none; }
.notif-item .thumb {
  width: 48px;
  height: 32px;
  flex-shrink: 0;
}
.notif-item .info { flex: 1; min-width: 0; }
.notif-item .title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
}
.notif-item .meta {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 2px;
}
.notif-time {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--text-dim);
  flex-shrink: 0;
}
.notif-empty {
  padding: 24px;
  text-align: center;
  color: var(--text-dim);
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
}

/* ─── BADGE DETAIL MODAL (image + log history) ────────────────────────── */
.modal.modal-detail .modal-img {
  max-height: 380px;
}
.modal-log-list-header {
  padding: 10px 24px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}
.modal-log-list {
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface-2);
}
.modal-log-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 24px;
  border-top: 1px solid var(--border);
  cursor: pointer;
}
.modal-log-item:first-child { border-top: none; }
.modal-log-item:hover { background: var(--surface); }
.modal-log-item.active {
  background: var(--surface);
  border-left: 3px solid var(--cyan);
  padding-left: 21px;
}
.modal-log-item .thumb {
  width: 48px;
  height: 32px;
  flex-shrink: 0;
}
.modal-log-item .info { flex: 1; min-width: 0; }
.modal-log-item .time {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  color: var(--text);
  font-weight: 600;
}
.modal-log-item .meta {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* ─── CAMERA CHIPS (visits page) ─── */
.cam-chip {
  display: inline-block;
  padding: 2px 8px;
  margin: 2px 4px 2px 0;
  border-radius: 4px;
  background: var(--surface-3);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--text-muted);
  border: 1px solid var(--border);
}
.cam-chip-count {
  display: inline-block;
  padding: 0 4px;
  margin-left: 4px;
  border-radius: 3px;
  background: var(--cyan);
  color: var(--bg);
  font-weight: 600;
  min-width: 14px;
  text-align: center;
}

/* ─── RESPONSIVE ─── */
@media (max-width: 1100px) {
  .kpi-row { grid-template-columns: repeat(1, 1fr); }
  .chart-grid { grid-template-columns: 1fr; }
  .main-grid { grid-template-columns: 1fr; }
  .topbar { flex-wrap: wrap; gap: 12px; }
}


/* ─── ONBOARDING ─────────────────────────────────────────────────────────────
   Location + camera intake form. Uses the app's theme tokens throughout so it
   works in light and dark rather than hardcoding the mock's blues. */

.ob-wrap { flex: 1; overflow-y: auto; padding: 24px 26px 34px; }

/* Page heading */
.ob-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 18px; }
.ob-head-icon {
  width: 46px; height: 46px; flex: none;
  display: grid; place-items: center;
  border-radius: 10px; font-size: 22px;
  background: var(--accent-bg); border: 1px solid var(--accent-border);
}
.ob-head h1 { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
.ob-head p { margin-top: 3px; font-size: 13px; color: var(--text-muted); }

/* Two columns: form on the left, guidance + actions on the right */
.ob-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 20px;
  align-items: start;
}
.ob-side { display: flex; flex-direction: column; gap: 16px; position: sticky; top: 0; }

/* Sections */
.ob-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
.ob-section { padding: 20px; border-bottom: 1px solid var(--border); }
.ob-section:last-child { border-bottom: 0; }
.ob-section-head { display: flex; align-items: center; gap: 9px; margin-bottom: 16px; }
.ob-section-icon {
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center;
  border-radius: 7px; font-size: 14px;
  background: var(--accent-bg); border: 1px solid var(--accent-border);
}
.ob-section-head h2 { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.ob-section-head .opt { font-size: 12px; font-weight: 400; color: var(--text-dim); }

/* Fields */
.ob-row { display: grid; gap: 14px; margin-bottom: 14px; }
.ob-row:last-child { margin-bottom: 0; }
.ob-row.c2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.ob-row.c3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ob-row.c4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.ob-label {
  display: block; margin-bottom: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--text);
}
.ob-label .req { color: var(--red); margin-left: 2px; }
.ob-label .opt { font-weight: 400; color: var(--text-dim); margin-left: 3px; }

.ob-input, .ob-select, .ob-textarea {
  width: 100%;
  padding: 9px 12px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font-family: inherit; font-size: 13px;
}
/* Location Name and Address sit side by side. The single-line input is
   stretched to match the textarea so the two boxes read as one uniform row,
   and the character counter sits inside the box rather than adding a third
   line of height below it. */
.ob-textarea { resize: vertical; min-height: 92px; line-height: 1.45; padding-bottom: 20px; }
.ob-textarea-wrap { position: relative; }
.ob-textarea-wrap .ob-counter { position: absolute; right: 10px; bottom: 7px; margin: 0; }
.ob-row.align-boxes { align-items: start; }
.ob-row.align-boxes .ob-input { min-height: 92px; }
.ob-input::placeholder, .ob-textarea::placeholder { color: var(--text-dim); }
.ob-input:focus, .ob-select:focus, .ob-textarea:focus {
  outline: none; border-color: var(--cyan);
}
.ob-input.bad, .ob-select.bad, .ob-textarea.bad, .ob-ms.bad { border-color: var(--red); }
.ob-hint { margin-top: 5px; font-size: 11px; color: var(--text-dim); }
.ob-err { margin-top: 5px; font-size: 11px; color: var(--red); }
.ob-counter {
  display: block; margin-top: 4px; text-align: right;
  font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--text-dim);
  pointer-events: none;
}
.ob-counter.over { color: var(--red); }

/* Multi-select (camera types) */
.ob-ms-wrap { position: relative; }
.ob-ms {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 9px 12px; text-align: left;
  background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 8px;
  color: var(--text); font-family: inherit; font-size: 13px; cursor: pointer;
}
.ob-ms.placeholder { color: var(--text-dim); }
.ob-ms:hover, .ob-ms[aria-expanded="true"] { border-color: var(--cyan); }
.ob-ms .chev { font-size: 10px; color: var(--text-dim); flex: none; }
.ob-ms-menu {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 4px);
  background: var(--surface);
  border: 1px solid var(--border-bright); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.14);
  padding: 6px; max-height: 230px; overflow-y: auto;
}
.ob-ms-menu label {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; border-radius: 6px;
  font-size: 13px; cursor: pointer;
}
.ob-ms-menu label:hover { background: var(--surface-2); }

/* Use-case checkboxes */
.ob-checks {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px 14px; margin-bottom: 14px;
}
.ob-check { display: flex; align-items: center; gap: 8px; font-size: 13px; cursor: pointer; }
.ob-check input { width: 15px; height: 15px; accent-color: var(--cyan); cursor: pointer; }

/* Right-hand guidance panel */
.ob-aside {
  border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
  background: var(--surface);
}
.ob-aside-art {
  padding: 18px; background: var(--accent-bg);
  border-bottom: 1px solid var(--accent-border);
}
.ob-aside-art svg { display: block; width: 100%; height: auto; }
.ob-aside-body { padding: 18px; }
.ob-aside-body h3 { font-size: 16px; font-weight: 700; letter-spacing: -0.01em; }
.ob-aside-body p { margin-top: 7px; font-size: 12.5px; line-height: 1.55; color: var(--text-muted); }
.ob-note {
  display: flex; gap: 10px; margin-top: 16px; padding: 12px;
  background: var(--accent-bg); border: 1px solid var(--accent-border); border-radius: 9px;
}
.ob-note-icon { flex: none; font-size: 14px; }
.ob-note b { display: block; font-size: 12.5px; margin-bottom: 3px; }
.ob-note span { font-size: 12px; line-height: 1.5; color: var(--text-muted); }

/* Actions */
.ob-actions { display: flex; justify-content: flex-end; gap: 10px; }
.ob-btn {
  padding: 10px 20px; border-radius: 8px;
  font-family: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer; border: 1px solid var(--border);
  display: inline-flex; align-items: center; gap: 7px;
}
.ob-btn-cancel { background: var(--surface); color: var(--text-muted); }
.ob-btn-cancel:hover { color: var(--text); border-color: var(--border-bright); }
.ob-btn-submit { background: var(--cyan); color: #fff; border-color: transparent; }
.ob-btn-submit:hover { filter: brightness(1.08); }
.ob-btn-submit:disabled { opacity: 0.6; cursor: not-allowed; filter: none; }

.ob-msg { font-size: 12.5px; margin-bottom: 10px; text-align: right; }
.ob-msg.ok { color: var(--green, #16a34a); }
.ob-msg.error { color: var(--red); }

/* Onboarding tabs */
.ob-tabs { display: flex; gap: 6px; margin-bottom: 16px; border-bottom: 1px solid var(--border); }
.ob-tab {
  padding: 9px 16px; margin-bottom: -1px;
  background: none; border: 1px solid transparent; border-radius: 8px 8px 0 0;
  color: var(--text-muted); font-family: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.ob-tab:hover { color: var(--text); }
.ob-tab.active { color: var(--text); background: var(--surface); border-color: var(--border); border-bottom-color: var(--surface); }

/* ─── DeepStream Pipeline panel (js/pipeline.js) ───────────────────────────────
   Built only from the theme tokens above, so light and dark mode both work. */
#tab-pipeline [hidden] { display: none !important; }
.ds { --ds-r: 12px; --ds-mono: 'JetBrains Mono', ui-monospace, monospace; }
.ds .mono { font-family: var(--ds-mono); }
.ds svg { width: 15px; height: 15px; fill: currentColor; flex: none; }

.ds-banner {
  margin-bottom: 16px; padding: 11px 15px; border-radius: 10px; font-size: 12.5px; line-height: 1.5;
  background: var(--amber-bg); border: 1px solid var(--amber-border); color: var(--text);
}
.ds-banner.error { background: var(--red-bg); border-color: var(--red-border); }
.ds-banner code { font-family: var(--ds-mono); font-size: 11.5px; }

/* Buttons */
.ds-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 38px; padding: 0 16px; border-radius: 9px; border: 1px solid var(--border);
  background: var(--surface); color: var(--text); font-size: 13px; font-weight: 600; letter-spacing: -0.005em;
  transition: background .15s, border-color .15s, color .15s, box-shadow .15s, transform .05s; white-space: nowrap;
}
.ds-btn:hover:not(:disabled) { border-color: var(--border-bright); background: var(--surface-2); }
.ds-btn:active:not(:disabled) { transform: translateY(1px); }
.ds-btn:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.ds-btn:disabled { opacity: .45; cursor: not-allowed; }
.ds-btn-ghost { background: var(--surface); }
.ds-btn-primary {
  background: linear-gradient(135deg, var(--cyan), color-mix(in srgb, var(--cyan) 70%, var(--violet)));
  color: #fff; border-color: transparent; box-shadow: 0 6px 18px -8px var(--cyan);
}
.ds-btn-primary:hover:not(:disabled) { filter: brightness(1.07); background: linear-gradient(135deg, var(--cyan), color-mix(in srgb, var(--cyan) 70%, var(--violet))); }
.ds-btn-danger { color: var(--red); border-color: var(--red-border); background: var(--surface); }
.ds-btn-danger:hover:not(:disabled) { background: var(--red-bg); border-color: var(--red); }
.ds-sm { height: 32px; padding: 0 11px; font-size: 12px; }
.ds-lg { height: 46px; width: 100%; font-size: 14px; border-radius: 10px; }
.ds-link { background: none; border: 0; color: var(--cyan); font-size: 12.5px; font-weight: 600; padding: 4px 0; }
.ds-link:hover { text-decoration: underline; }

/* Hero: status + KPIs */
.ds-hero {
  position: relative; overflow: hidden; margin-bottom: 18px; padding: 20px 22px 18px;
  border: 1px solid var(--border); border-radius: 14px; box-shadow: var(--shadow);
  background:
    radial-gradient(900px 220px at 100% 0%, var(--accent-bg), transparent 70%),
    linear-gradient(180deg, var(--surface), var(--surface));
}
.ds-hero::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--cyan), var(--violet));
}
.ds-hero-top { display: flex; justify-content: space-between; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.ds-hero-text h2 { font-size: 21px; font-weight: 700; letter-spacing: -0.02em; margin-top: 9px; }
.ds-hero-text p { margin-top: 3px; font-size: 13px; color: var(--text-muted); }
.ds-hero-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.ds-pill {
  display: inline-flex; align-items: center; gap: 8px; height: 26px; padding: 0 11px 0 9px; border-radius: 99px;
  font-size: 12px; font-weight: 600; border: 1px solid var(--border); background: var(--surface-2); color: var(--text-muted);
}
.ds-pill i { width: 8px; height: 8px; border-radius: 50%; background: var(--text-dim); }
.ds-pill.running { color: var(--green); background: var(--green-bg); border-color: var(--green-border); }
.ds-pill.running i { background: var(--green); box-shadow: 0 0 0 4px color-mix(in srgb, var(--green) 22%, transparent); animation: ds-pulse 2s infinite; }
.ds-pill.building, .ds-pill.busy { color: var(--amber); background: var(--amber-bg); border-color: var(--amber-border); }
.ds-pill.building i, .ds-pill.busy i { background: var(--amber); animation: ds-pulse 1.1s infinite; }
.ds-pill.failed { color: var(--red); background: var(--red-bg); border-color: var(--red-border); }
.ds-pill.failed i { background: var(--red); }
.ds-hero-error {
  margin-top: 14px; padding: 11px 14px; border-radius: 10px; font-size: 12.5px; line-height: 1.5;
  background: var(--red-bg); border: 1px solid var(--red-border); color: var(--text);
}
.ds-hero-error b { color: var(--red); }
@keyframes ds-pulse { 50% { opacity: .35; } }

.ds-kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1.6fr); gap: 12px; margin-top: 18px; }
.ds-kpi {
  padding: 12px 14px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border); min-width: 0;
}
.ds-kpi span { display: block; font-size: 10.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--text-dim); }
.ds-kpi b { display: block; margin-top: 5px; font-family: var(--ds-mono); font-size: 20px; font-weight: 600; letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-kpi small { display: block; margin-top: 2px; font-size: 11.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-kpi-wide b { font-size: 14.5px; margin-top: 8px; }

/* Layout */
.ds-grid { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 18px; align-items: start; }
.ds-main { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.ds-rail { display: flex; flex-direction: column; gap: 18px; position: sticky; top: 0; }

/* Cards */
.ds-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--ds-r); box-shadow: var(--shadow); padding: 20px; min-width: 0; }
.ds-card h3 { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.ds-card-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 16px; }
.ds-num {
  width: 28px; height: 28px; flex: none; display: grid; place-items: center; border-radius: 8px;
  font-family: var(--ds-mono); font-size: 13px; font-weight: 700; color: var(--cyan);
  background: var(--accent-bg); border: 1px solid var(--accent-border);
}
.ds-card-title { flex: 1; min-width: 0; }
.ds-card-title p { margin-top: 2px; font-size: 12.5px; color: var(--text-muted); }
.ds-card-tools { display: flex; gap: 6px; flex-wrap: wrap; }

/* Fields */
.ds-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ds-field > label { font-size: 12px; font-weight: 600; color: var(--text); display: flex; align-items: baseline; gap: 8px; }
.ds-field > label em { font-style: normal; font-weight: 400; color: var(--text-dim); font-size: 11.5px; }
.ds-grow { flex: 1; }
.ds-input {
  width: 100%; height: 38px; padding: 0 12px; border-radius: 9px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text); font-size: 13px; transition: border-color .15s, box-shadow .15s, background .15s;
}
textarea.ds-input { height: auto; padding: 10px 12px; line-height: 1.5; resize: vertical; }
.ds-input:hover { border-color: var(--border-bright); }
.ds-input:focus { outline: none; border-color: var(--cyan); background: var(--surface); box-shadow: 0 0 0 3px var(--accent-bg); }
.ds-input.bad, .ds-input.bad:focus { border-color: var(--red); box-shadow: 0 0 0 3px var(--red-bg); }
.ds-hint { font-size: 11.5px; line-height: 1.45; color: var(--text-muted); min-height: 1em; }
.ds-hint.ok { color: var(--green); }
.ds-hint.bad { color: var(--red); }
.ds-hint.warn { color: var(--amber); }
.ds-group { display: flex; }
.ds-group .ds-input { border-radius: 9px 0 0 9px; font-size: 12px; }
.ds-group .ds-btn { border-radius: 0 9px 9px 0; margin-left: -1px; }

.ds-stepper { display: inline-flex; height: 38px; border: 1px solid var(--border); border-radius: 9px; overflow: hidden; background: var(--surface-2); width: fit-content; }
.ds-stepper button { width: 34px; border: 0; background: transparent; color: var(--text-muted); font-size: 16px; }
.ds-stepper button:hover { background: var(--surface-3); color: var(--text); }
.ds-stepper input {
  width: 54px; border: 0; border-left: 1px solid var(--border); border-right: 1px solid var(--border);
  background: var(--surface); color: var(--text); text-align: center; font-family: var(--ds-mono); font-size: 14px; font-weight: 600;
  -moz-appearance: textfield;
}
.ds-stepper input::-webkit-outer-spin-button, .ds-stepper input::-webkit-inner-spin-button { -webkit-appearance: none; }
.ds-stepper input:focus { outline: none; background: var(--accent-bg); }
.ds-stepper.bad { border-color: var(--red); }

.ds-seg { display: inline-flex; padding: 3px; gap: 2px; border-radius: 9px; background: var(--surface-2); border: 1px solid var(--border); width: fit-content; }
.ds-seg button {
  height: 30px; padding: 0 12px; border: 0; border-radius: 7px; background: transparent;
  color: var(--text-muted); font-size: 12.5px; font-weight: 600;
}
.ds-seg button:hover { color: var(--text); }
.ds-seg button.on { background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,.12), 0 0 0 1px var(--border); }

.ds-range { width: 100%; accent-color: var(--cyan); height: 38px; }
.ds-out { margin-left: auto; font-family: var(--ds-mono); font-size: 12px; font-weight: 600; color: var(--cyan); padding: 1px 8px; border-radius: 6px; background: var(--accent-bg); }

.ds-switch { position: relative; display: flex; align-items: center; gap: 10px; font-size: 12.5px; color: var(--text-muted); cursor: pointer; user-select: none; }
/* The real checkbox stays inside its switch (1x1 px, invisible). Without position:relative on the switch it was
   placed against a far ancestor, and focusing it on click scrolled the fixed page layout (half-blank page). */
.ds-switch input { position: absolute; top: 0; left: 0; width: 1px; height: 1px; margin: 0; opacity: 0; pointer-events: none; }
.ds-switch-ui { width: 34px; height: 20px; flex: none; border-radius: 99px; background: var(--surface-3); border: 1px solid var(--border-bright); position: relative; transition: background .15s; }
.ds-switch-ui::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: transform .15s; }
.ds-switch input:checked + .ds-switch-ui { background: var(--cyan); border-color: var(--cyan); }
.ds-switch input:checked + .ds-switch-ui::after { transform: translateX(14px); }
.ds-switch input:focus-visible + .ds-switch-ui { outline: 2px solid var(--cyan); outline-offset: 2px; }
.ds-switch input:disabled + .ds-switch-ui { opacity: .5; }

/* Streams */
.ds-toolbar { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-end; margin-bottom: 14px; }
.ds-bulk { margin-bottom: 14px; padding: 14px; border-radius: 10px; background: var(--surface-2); border: 1px dashed var(--border-bright); }
.ds-bulk label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 8px; }
.ds-bulk code { font-family: var(--ds-mono); font-size: 11.5px; padding: 1px 5px; border-radius: 4px; background: var(--surface-3); }
.ds-bulk-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 10px; }

.ds-table-wrap { max-height: 470px; overflow: auto; border: 1px solid var(--border); border-radius: 10px; }
.ds-table { width: 100%; min-width: 720px; table-layout: fixed; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
.ds-table thead th {
  position: sticky; top: 0; z-index: 2; background: var(--surface-2); padding: 9px 10px; text-align: left;
  font-size: 10.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--text-dim);
  border-bottom: 1px solid var(--border);
}
.ds-table td { padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: middle; background: var(--surface); }
.ds-table tbody tr:last-child td { border-bottom: 0; }
.ds-table tbody tr:hover td { background: color-mix(in srgb, var(--surface-2) 60%, var(--surface)); }
.ds-table th:nth-child(1) { width: 40px; }
.ds-table th:nth-child(2) { width: 124px; }
.ds-table th:nth-child(3) { width: 104px; }
.ds-table th:nth-child(5) { width: 196px; }
.ds-table th:nth-child(6) { width: 54px; }
.ds-table th:nth-child(7) { width: 36px; }
.ds-table td.n { text-align: right; color: var(--text-dim); font-family: var(--ds-mono); font-size: 11.5px; }
.ds-table td.on, .ds-table td.del { text-align: center; }
.ds-table td.on .ds-switch { justify-content: center; }
.ds-table .ds-input { height: 34px; padding: 0 10px; font-size: 12.5px; }
.ds-table .ds-url { font-family: var(--ds-mono); font-size: 11.5px; }
.ds-table .ds-seg button { height: 26px; padding: 0 9px; font-size: 11.5px; }
.ds-table tr.off td:not(.on) > * { opacity: .45; }
.ds-x { width: 26px; height: 26px; border-radius: 7px; border: 0; background: none; color: var(--text-dim); font-size: 15px; line-height: 1; }
.ds-x:hover { background: var(--red-bg); color: var(--red); }

.ds-chip {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 4px 9px; border-radius: 7px;
  font-family: var(--ds-mono); font-size: 11px; line-height: 1.3; border: 1px solid var(--border); background: var(--surface-2); color: var(--text-muted);
}
.ds-chip b { font-weight: 600; color: var(--text); }
.ds-chip.ok { border-color: var(--green-border); background: var(--green-bg); color: var(--text-muted); }
.ds-chip.bad { border-color: var(--red-border); background: var(--red-bg); color: var(--red); font-family: inherit; }
.ds-chip.warn { border-color: var(--amber-border); background: var(--amber-bg); color: var(--amber); font-family: inherit; }
.ds-chip.wait::before { content: ""; width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--border-bright); border-top-color: var(--cyan); animation: ds-spin .8s linear infinite; }
.ds-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@keyframes ds-spin { to { transform: rotate(360deg); } }

.ds-table-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 10px; }
.ds-foot-note { font-size: 12px; color: var(--text-muted); }
.ds-foot-note.bad { color: var(--red); }
.ds-auto {
  margin-top: 14px; padding: 12px 14px; border-radius: 10px; display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center;
  background: var(--accent-bg); border: 1px solid var(--accent-border); font-size: 12.5px;
}
.ds-auto:empty { display: none; }
.ds-auto .t { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--cyan); }
.ds-auto .v { font-family: var(--ds-mono); font-weight: 600; }
.ds-auto .notes { flex-basis: 100%; color: var(--text-muted); font-size: 12px; line-height: 1.5; }

/* Detector / detection */
.ds-form-grid { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1.25fr) auto; gap: 16px; }
.ds-form-grid.two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.ds-readonly {
  height: 38px; display: flex; align-items: center; padding: 0 12px; border-radius: 9px;
  border: 1px dashed var(--border-bright); background: var(--surface); font-family: var(--ds-mono); font-size: 13px; font-weight: 600;
}
.ds-plan { margin-top: 16px; display: grid; gap: 8px; }
.ds-plan:empty { display: none; }
.ds-plan-row {
  display: grid; grid-template-columns: 74px minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 10px 12px; border-radius: 10px; border: 1px solid var(--border); background: var(--surface-2); font-size: 12.5px;
}
.ds-plan-row .k { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-dim); }
.ds-plan-row .f { font-family: var(--ds-mono); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ds-tag { font-size: 11.5px; font-weight: 600; padding: 3px 9px; border-radius: 99px; white-space: nowrap; border: 1px solid; }
.ds-tag.ok { color: var(--green); background: var(--green-bg); border-color: var(--green-border); }
.ds-tag.make { color: var(--amber); background: var(--amber-bg); border-color: var(--amber-border); }

/* Run rail */
.ds-run h3, .ds-progress h3 { margin-bottom: 12px; }
.ds-ready { list-style: none; display: flex; flex-direction: column; gap: 7px; margin-bottom: 16px; font-size: 12.5px; }
.ds-ready li { display: flex; gap: 9px; align-items: flex-start; line-height: 1.4; color: var(--text-muted); }
.ds-ready li::before { content: "✓"; flex: none; width: 18px; height: 18px; display: grid; place-items: center; border-radius: 50%; font-size: 10.5px; font-weight: 700; color: var(--green); background: var(--green-bg); }
.ds-ready li.bad { color: var(--text); }
.ds-ready li.bad::before { content: "!"; color: var(--red); background: var(--red-bg); }
.ds-ready li.warn::before { content: "!"; color: var(--amber); background: var(--amber-bg); }
.ds-btn-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 8px; }
.ds-run .ds-switch { margin-top: 14px; }
.ds-restore { display: flex; gap: 8px; margin-top: 12px; padding-top: 14px; border-top: 1px solid var(--border); }
.ds-restore .ds-input { flex: 1; min-width: 0; font-size: 12px; height: 34px; }
.ds-restore .ds-btn { height: 34px; }
.ds-msgs { margin-top: 12px; font-size: 12px; line-height: 1.5; }
.ds-msgs:empty { display: none; }
.ds-msgs > div { padding: 10px 12px; border-radius: 9px; margin-top: 8px; }
.ds-msgs ul { margin: 4px 0 0 16px; }
.ds-msgs .err { background: var(--red-bg); color: var(--red); border: 1px solid var(--red-border); }
.ds-msgs .warn { background: var(--amber-bg); color: var(--text); border: 1px solid var(--amber-border); }
.ds-msgs .ok { background: var(--green-bg); color: var(--text); border: 1px solid var(--green-border); }

.ds-progress-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.ds-label { font-size: 10.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--text-dim); }
.ds-progress-head h3 { margin: 3px 0 12px; font-size: 14px; }
.ds-elapsed { font-family: var(--ds-mono); font-size: 12px; color: var(--text-muted); padding: 3px 8px; border-radius: 6px; background: var(--surface-2); }
.ds-elapsed:empty { display: none; }
.ds-timeline { list-style: none; position: relative; }
.ds-timeline li { position: relative; display: flex; gap: 12px; padding-bottom: 14px; font-size: 12.5px; color: var(--text-dim); }
.ds-timeline li:last-child { padding-bottom: 0; }
.ds-timeline li::after { content: ""; position: absolute; left: 10px; top: 22px; bottom: 0; width: 2px; background: var(--border); }
.ds-timeline li:last-child::after { display: none; }
.ds-timeline .dot { width: 22px; height: 22px; flex: none; border-radius: 50%; display: grid; place-items: center; font-size: 11px; font-weight: 700; background: var(--surface-2); border: 2px solid var(--border); z-index: 1; }
.ds-timeline li.done { color: var(--text); }
.ds-timeline li.done .dot { background: var(--green); border-color: var(--green); color: #fff; }
.ds-timeline li.done::after { background: var(--green-border); }
.ds-timeline li.running { color: var(--text); font-weight: 600; }
.ds-timeline li.running .dot { border-color: var(--cyan); border-top-color: transparent; animation: ds-spin .9s linear infinite; }
.ds-timeline li.failed { color: var(--red); }
.ds-timeline li.failed .dot { background: var(--red); border-color: var(--red); color: #fff; }
.ds-timeline .lbl { padding-top: 2px; line-height: 1.4; }
.ds-timeline .det { display: block; font-size: 11.5px; font-weight: 400; color: var(--text-muted); margin-top: 2px; }
.ds-empty { font-size: 12.5px; color: var(--text-dim); }

/* Console */
.ds-console { margin-top: 18px; border-radius: var(--ds-r); overflow: hidden; border: 1px solid #1d2638; box-shadow: var(--shadow); background: #0b1020; }
.ds-console header { display: flex; align-items: center; gap: 12px; padding: 9px 12px; background: #111a2e; border-bottom: 1px solid #1d2638; flex-wrap: wrap; }
.ds-console code { flex: 1; min-width: 0; font-family: var(--ds-mono); font-size: 11px; color: #6c7a99; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-seg-dark { background: #0b1020; border-color: #1d2638; }
.ds-seg-dark button { color: #8a96b3; }
.ds-seg-dark button:hover { color: #e8edf5; }
.ds-seg-dark button.on { background: #1d2a45; color: #e8edf5; box-shadow: none; }
.ds-switch.dark { color: #8a96b3; }
.ds-switch.dark .ds-switch-ui { background: #1d2638; border-color: #2c3a58; }
.ds-btn-console { height: 30px; padding: 0 12px; font-size: 12px; background: #1a2440; border-color: #2c3a58; color: #cfd8ea; }
.ds-btn-console:hover:not(:disabled) { background: #22305a; border-color: #3a4c74; }
.ds-console pre {
  margin: 0; height: 400px; overflow: auto; padding: 14px 16px; color: #cfd8ea;
  font-family: var(--ds-mono); font-size: 11.5px; line-height: 1.55; white-space: pre-wrap; word-break: break-word;
}
.ds-console pre::-webkit-scrollbar { width: 10px; }
.ds-console pre::-webkit-scrollbar-thumb { background: #243049; border-radius: 6px; }

@media (max-width: 1280px) {
  .ds-grid { grid-template-columns: 1fr; }
  .ds-rail { position: static; display: grid; grid-template-columns: 1fr 1fr; }
}
@media (max-width: 900px) {
  .ds-kpis { grid-template-columns: 1fr 1fr; }
  .ds-form-grid, .ds-form-grid.two, .ds-rail { grid-template-columns: 1fr; }
}

@media (max-width: 1150px) {
  .ob-layout { grid-template-columns: 1fr; }
  .ob-side { position: static; }
  .ob-checks { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
  .ob-row.c2, .ob-row.c3, .ob-row.c4 { grid-template-columns: 1fr; }
  .ob-checks { grid-template-columns: 1fr; }
}

/* ─── PLATE ALERTS ─── */
.al-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 9px;
  margin-bottom: 8px;
  background: var(--surface-2);
}
.al-row:last-child { margin-bottom: 0; }
.al-row.off { opacity: 0.62; }
.al-main { flex: 1; min-width: 0; }
.al-plate {
  font-family: 'JetBrains Mono', monospace; font-size: 14px; font-weight: 700;
  letter-spacing: 0.02em;
}
.al-note {
  margin-top: 2px; font-size: 12px; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.al-added { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--text-dim); }
.al-state {
  font-family: 'JetBrains Mono', monospace; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em;
  padding: 3px 8px; border-radius: 4px; white-space: nowrap;
}
.al-state.on  { background: var(--green-bg); color: var(--green); border: 1px solid var(--green-border); }
.al-state.off { background: var(--surface-3); color: var(--text-dim); border: 1px solid var(--border); }
.al-remove {
  background: none; border: 1px solid var(--border); border-radius: 6px;
  color: var(--text-dim); cursor: pointer;
  width: 28px; height: 28px; flex: none; font-size: 13px; line-height: 1;
}
.al-remove:hover { color: var(--red); border-color: var(--red); }
.al-empty {
  padding: 26px; text-align: center;
  font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--text-dim);
}
@media (max-width: 620px) {
  .al-row { flex-wrap: wrap; }
  .al-main { flex-basis: 100%; }
}

/* ─── COVERAGE REPORT ─── */
.rp-controls {
  display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap;
  margin-bottom: 16px;
}
.rp-controls .ob-select { min-width: 190px; }
.rp-spacer { flex: 1; }

.rp-kpis { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 12px; margin-bottom: 16px; }
.rp-kpi {
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--border-bright);
  border-radius: 10px; padding: 14px 16px;
}
.rp-kpi.good { border-left-color: var(--green); }
.rp-kpi.warn { border-left-color: #f59e0b; }
.rp-kpi.bad  { border-left-color: var(--red); }
.rp-kpi-val { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
.rp-kpi-label {
  margin-top: 2px; font-family: 'JetBrains Mono', monospace; font-size: 10px;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted);
}
.rp-kpi-sub { margin-top: 4px; font-size: 11.5px; color: var(--text-dim); }

.rp-layout { display: grid; grid-template-columns: minmax(0,1fr) 360px; gap: 16px; align-items: start; }
.rp-map-card { display: flex; flex-direction: column; overflow: hidden; }
.rp-map-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 11px 16px; border-bottom: 1px solid var(--border); background: var(--surface-2);
  font-size: 13px; font-weight: 600;
}
.rp-status { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--text-dim); font-weight: 400; }
#rp-map { height: 560px; width: 100%; z-index: 0; }
.rp-legend {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 16px;
  padding: 11px 16px; border-top: 1px solid var(--border); background: var(--surface-2);
}
.rp-legend-title {
  font-family: 'JetBrains Mono', monospace; font-size: 10px;
  text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted);
}
.rp-key { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--text-muted); }
.rp-key i { width: 14px; height: 14px; border-radius: 3px; display: inline-block; }
.rp-key i.rp-cam { background: #fff; border: 1.5px solid #0f172a; border-radius: 50%; width: 10px; height: 10px; }

.rp-hint { font-size: 11.5px; color: var(--text-dim); margin-bottom: 12px; }
.rp-area { padding: 11px 0; border-bottom: 1px solid var(--border); }
.rp-area:last-child { border-bottom: 0; }
.rp-area-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.rp-area-name { font-size: 13px; font-weight: 600; }
.rp-area-pct { font-family: 'JetBrains Mono', monospace; font-size: 11px; font-weight: 700; white-space: nowrap; }
.rp-area-pct.good { color: var(--green); }
.rp-area-pct.warn { color: #d97706; }
.rp-area-pct.bad  { color: var(--red); }
.rp-bar { height: 6px; border-radius: 3px; background: var(--surface-3); margin: 7px 0 5px; overflow: hidden; }
.rp-bar i { display: block; height: 100%; border-radius: 3px; }
.rp-bar i.good { background: var(--green); }
.rp-bar i.warn { background: #f59e0b; }
.rp-bar i.bad  { background: var(--red); }
.rp-area-meta { font-family: 'JetBrains Mono', monospace; font-size: 10.5px; color: var(--text-dim); }

@media (max-width: 1250px) {
  .rp-layout { grid-template-columns: 1fr; }
  .rp-kpis { grid-template-columns: repeat(2, minmax(0,1fr)); }
}
@media (max-width: 620px) {
  .rp-kpis { grid-template-columns: 1fr; }
  #rp-map { height: 420px; }
}

/* ─── LARGER TEXT SCOPE ───
   Opt-in via <body class="text-lg">. The base scale is tuned for the dense
   map/monitoring views; Visits and Whitelist are read rather than glanced at,
   so they size up. Add the class to another page's <body> to bring it along,
   or drop the `body.text-lg ` prefix to make the larger scale app-wide. */
body.text-lg .card-title      { font-size: 17px; }
body.text-lg .card-sub        { font-size: 13px; }

body.text-lg thead th         { font-size: 12px; padding: 11px 18px; }
body.text-lg tbody td         { font-size: 15px; padding: 12px 18px; }
body.text-lg tbody td.mono    { font-size: 14px; }

body.text-lg .filter-input,
body.text-lg .filter-select   { font-size: 14px; padding: 9px 13px; }
body.text-lg .filter-label    { font-size: 12px; }

body.text-lg .cam-chip        { font-size: 12px; padding: 3px 9px; }

/* Whitelist rows */
body.text-lg .wl-row .label   { font-size: 15px; }
body.text-lg .wl-row .reason  { font-size: 13px; }
body.text-lg .wl-row .added   { font-size: 12px; }
body.text-lg .wl-row .window  { font-size: 13px; }
body.text-lg .wl-msg          { font-size: 14px; }
body.text-lg .wl-form input,
body.text-lg .wl-form select  { font-size: 14px; }

/* Visit timeline modal */
body.text-lg .modal-log-list-header { font-size: 12px; }
body.text-lg .modal-log-item .time  { font-size: 14px; }
body.text-lg .modal-log-item .meta  { font-size: 13px; }
body.text-lg .modal-header .sub     { font-size: 13px; }

/* ─── READABILITY (Visits + Whitelist) ───
   --text-dim is ~3:1 against the light surface, under the 4.5:1 needed for
   body text. Inside .text-lg, secondary content moves up a step and the values
   people actually scan for — plates, cameras, areas, dates — carry weight. */

/* Table chrome */
body.text-lg thead th        { color: var(--text-muted); font-weight: 700; }
body.text-lg .card-sub       { color: var(--text-muted); font-weight: 500; }
body.text-lg .filter-label   { color: var(--text-muted); font-weight: 700; }
body.text-lg #visits-meta    { color: var(--text-muted); font-weight: 600; }

/* Row values */
body.text-lg tbody td        { color: var(--text); }
body.text-lg tbody td.mono   { font-weight: 500; }
body.text-lg .row-id         { color: var(--text-muted); font-weight: 600; }
body.text-lg .cell-empty     { color: var(--text-muted); }

/* Chips: darker text and a defined edge so they read as data, not decoration */
body.text-lg .cam-chip {
  color: var(--text);
  font-weight: 600;
  background: var(--surface-2);
  border-color: var(--border-bright);
}
body.text-lg .cam-chip-count { font-weight: 700; }
body.text-lg .cam-chip-area {
  background: var(--accent-bg);
  border-color: var(--accent-border);
  color: var(--text);
}
/* Was opacity:0.65, which made it the least legible thing in the row. Now it
   is fully opaque and signals "no area assigned" with a dashed edge instead. */
body.text-lg .cam-chip-unassigned {
  background: transparent;
  border-style: dashed;
  color: var(--text-muted);
  font-weight: 500;
}

/* Whitelist rows */
body.text-lg .wl-row .label  { font-weight: 700; letter-spacing: 0.02em; }
body.text-lg .wl-row .reason { color: var(--text); font-weight: 500; }
body.text-lg .wl-row .window { color: var(--text-muted); font-weight: 500; }
body.text-lg .wl-row .added  { color: var(--text-muted); font-weight: 600; }
body.text-lg .wl-note        { color: var(--text-muted); }

/* Visit timeline modal */
body.text-lg .modal-log-item .time { font-weight: 700; }
body.text-lg .modal-log-item .meta { color: var(--text-muted); font-weight: 500; }
body.text-lg .modal-log-list-header { color: var(--text-muted); font-weight: 700; }
body.text-lg .modal-header .sub     { color: var(--text-muted); font-weight: 500; }

/* Bolder, larger text needs the columns to stop wrapping mid-value. Headers,
   the id, the count and the timestamp all stay on one line; the Cameras column
   is the flexible one, since chips wrap gracefully and the rest do not. */
body.text-lg thead th               { white-space: nowrap; }
body.text-lg tbody td:first-child,
body.text-lg tbody td:nth-child(2),
body.text-lg tbody td:nth-child(3),
body.text-lg tbody td:last-child    { white-space: nowrap; }
body.text-lg tbody td:nth-child(4)  { white-space: nowrap; }
body.text-lg tbody td:nth-child(5)  { width: 100%; }

/* The row is a flex line; at the larger scale the date and status pill were
   being squeezed into two lines. Pin them and let the reason take the slack. */
body.text-lg .wl-row > div:first-child { min-width: 0; flex: 1; }
body.text-lg .wl-row .added            { white-space: nowrap; }
body.text-lg .wl-row .state,
body.text-lg .wl-row .wl-state         { white-space: nowrap; }
body.text-lg .wl-row .reason           { margin-left: 12px; }

/* ─── FULL-WIDTH PAGES ───
   .container caps at 1600px and centres, which leaves large gutters on wide
   monitors. Visits is a dense table that benefits from every pixel — the
   Cameras column in particular — so it opts out of the cap and spans the page.
   A modest side gutter stays so content never touches the window edge. */
body.full-bleed .container { max-width: none; width: 100%; margin: 0; }
body.full-bleed .filter-bar,
body.full-bleed .card { width: 100%; }

/* .admin-wrap caps at 800px — far tighter than .container — so the whitelist
   card needs its own release. Vertical rhythm is kept; only the cap goes. */
body.full-bleed .admin-wrap {
  max-width: none; width: 100%; margin: 24px 0; padding: 0 24px;
}
body.full-bleed .admin-card { width: 100%; }

/* The card spans the page, but running prose does not get more readable past
   ~95 characters — it gets harder to track from one line to the next. The
   blurb and the notice keep a comfortable measure; the form, list and data
   all use the full width. */
/* Only the unboxed blurb keeps a reading measure. The notice has a border and
   a fill, so a short box floating at a third of the width reads as a mistake —
   it spans, and its own padding keeps the lines from running edge to edge. */
body.full-bleed .admin-card > .card-sub { max-width: 95ch; }
body.full-bleed .admin-card > .notice   { width: 100%; padding: 16px 20px; }

/* ─── WHITELIST TEXT (match the Visits treatment) ───
   Same rule as the visits table: content sits on --text with weight, and only
   genuinely secondary metadata stays muted. Sizes track the .text-lg scale. */

/* The explainer is the main body copy on this page, not a caption. */
body.text-lg .admin-card > .card-sub {
  color: var(--text); font-weight: 500; font-size: 13.5px; line-height: 1.65;
}

/* Form controls and their labels */
body.text-lg .wl-radio       { font-size: 14px; font-weight: 600; color: var(--text); }
body.text-lg .wl-form input  { color: var(--text); font-weight: 500; }
body.text-lg .wl-form input::placeholder { color: var(--text-muted); }
body.text-lg .wl-form button { font-size: 13px; }
body.text-lg .wl-msg         { font-weight: 600; }
body.text-lg .filter-label   { color: var(--text-muted); font-weight: 700; }

/* Row content — plate and reason are values, the mode line is content too */
body.text-lg .wl-row .label  { color: var(--text); font-weight: 700; }
body.text-lg .wl-row .reason { color: var(--text); font-weight: 500; }
body.text-lg .wl-row .window { color: var(--text); font-weight: 500; }
body.text-lg .wl-row .added  { color: var(--text-muted); font-weight: 600; }
body.text-lg .wl-row .remove { font-weight: 700; }

/* Empty state, previously dimmed inline from JS */
body.text-lg .wl-empty {
  text-align: center; padding: 30px;
  font-family: 'JetBrains Mono', monospace; font-size: 13px;
  color: var(--text-muted); font-weight: 500;
}

/* The amber notice is instructional copy — it needs to be read, not skimmed */
body.text-lg .notice   { font-size: 13px; line-height: 1.7; color: var(--text); }
body.text-lg .notice b { font-size: 12px; }

/* Timeline entries carry the full date as well as the time — a visit can span
   midnight, and a bare "05:29 AM" above a "06:57 PM" gives no way to tell the
   two apart. The date is set slightly back so the time still leads. */
.modal-log-item .log-date { color: var(--text-muted); font-weight: 500; }
.modal-log-item .log-sep  { color: var(--text-dim); margin: 0 3px; }
body.text-lg .modal-log-item .log-date { color: var(--text-muted); font-weight: 600; }

/* ─── Zoomable frame viewer (visit timeline) ─── */
.zv { outline: none; }
.zv-toolbar {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-bottom: 8px;
  font-family: 'JetBrains Mono', monospace; font-size: 12px;
}
.zv-btn {
  min-width: 32px; height: 30px; padding: 0 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  font-family: 'JetBrains Mono', monospace; font-size: 13px; cursor: pointer;
  text-decoration: none;
}
.zv-btn:hover { border-color: var(--cyan); color: var(--cyan); }
.zv-btn:focus-visible, .zv:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.zv-level { min-width: 44px; text-align: center; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.zv-hint { color: var(--text-dim); font-size: 11px; margin-left: 6px; }
.zv-download { margin-left: auto; font-size: 12px; }
.zv-stage {
  position: relative; overflow: hidden;
  height: 60vh; border-radius: 8px;
  background: var(--surface-2);
  display: flex; align-items: center; justify-content: center;
  cursor: zoom-in; touch-action: none; user-select: none;
}
.zv-stage.zoomed { cursor: grab; }
.zv-stage.zoomed:active { cursor: grabbing; }
.zv-img {
  max-width: 100%; max-height: 100%;
  transform-origin: center center;
  will-change: transform;
}
@media (max-width: 640px) {
  .zv-hint { display: none; }
  .zv-stage { height: auto; aspect-ratio: 4 / 3; max-height: 50vh; }
}

/* ─── Visit modal layout: frame on top, timeline fills the rest and scrolls ───
   The modal is capped at 90vh with overflow hidden, so the frame viewer gets a height that always leaves room for
   the timeline (at least ~150 px), and the timeline list takes the remaining height with its own scrollbar. */
.modal.modal-visit { display: flex; flex-direction: column; }
.modal.modal-visit .modal-header { flex: 0 0 auto; }
.modal.modal-visit .modal-body {
  flex: 1 1 auto; min-height: 0; padding: 0;
  display: flex; flex-direction: column;
}
.modal.modal-visit .visit-frame { flex: 0 0 auto; padding: 12px 24px; }
.modal.modal-visit .zv-stage { height: max(200px, min(60vh, calc(90vh - 380px))); }
.modal.modal-visit .modal-log-list-header { flex: 0 0 auto; }
.modal.modal-visit .modal-log-list {
  flex: 1 1 auto; min-height: 150px; max-height: none;
  overflow-y: auto; overscroll-behavior: contain;
}
@media (max-width: 640px) {
  .modal.modal-visit .zv-stage { height: auto; aspect-ratio: 4 / 3; max-height: 38vh; }
}


/* ─── PHONES ──────────────────────────────────────────────────────────────────
   Below 720px: compact top bar, wide tables scroll sideways inside their card
   instead of being cut off, form controls sized for fingers. Desktop unchanged. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 720px) {
  .container { padding-left: 12px; padding-right: 12px; }
  .topbar { padding: 10px 12px; gap: 8px 10px; }
  .brand-logo { height: 32px; }
  .brand-dept { font-size: 10px; padding-left: 8px; }
  .tabs { order: 3; width: 100%; overflow-x: auto; }
  .topbar-right { gap: 6px; flex-wrap: wrap; margin-left: 0; width: 100%; }
  .ob-layout > * { min-width: 0; }                  /* grid columns may shrink: long text wraps or ellipsizes */
  .time-stamp { font-size: 11px; padding: 6px 8px; white-space: nowrap; }
  .table-scroll table { min-width: 600px; }
  .card-header { flex-wrap: wrap; gap: 4px 12px; }
  .filter-bar { flex-wrap: wrap; gap: 10px; padding: 12px !important; }
  .filter-bar > div { flex-wrap: wrap; }
  .filter-bar select { min-width: 0 !important; flex: 1; }
  input, select, textarea { font-size: 16px; }      /* iOS: no auto-zoom when a field is tapped */
  /* DeepStream panel: field label hints wrap; an input with its button shrinks instead of overflowing */
  .ds-field > label { flex-wrap: wrap; }
  .ds-field label em { white-space: normal; }
  .ds-group { min-width: 0; }
  .ds-group .ds-input { min-width: 0; flex: 1 1 auto; font-size: 16px; }
  .ds-field, .ds-grow { min-width: 0; }
  .ds-toolbar .ds-grow { flex: 1 1 100%; }         /* the RTSP template + "Fill URLs" get their own full line */
  .ds-card-head { flex-wrap: wrap; }
  .ds-card-tools { flex-basis: 100%; }             /* card buttons under the title, not squeezing its text */
  /* Visits / Logs filters: each label stays beside its own field; search and export get full rows */
  .filter-bar:not([style]) { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px 10px; padding: 12px; }
  .filter-bar:not([style]) .filter-input.search,
  .filter-bar:not([style]) .export-btn { grid-column: 1 / -1; min-width: 0; }
  .filter-bar:not([style]) .filter-input,
  .filter-bar:not([style]) .filter-select { width: 100%; min-width: 0; }
}
