/*
 * Calyston VMS — v0.1 dashboard stylesheet.
 *
 * Hand-maintained (not Tailwind-built). Keeps the dev VM browsable on a
 * fresh clone without running `make css`. When `make css` runs from
 * tooling/tailwind/, it overwrites this file with the Tailwind-built
 * equivalent — the tokens here mirror tailwind.config.js so the visual
 * output is identical.
 *
 * Structure:
 *   1. Tokens (CSS variables) + base reset
 *   2. CRT overlay (body::before)
 *   3. App shell + header + subnav + sidebar
 *   4. Camera grid + tile states + drawer
 *   5. License panel + events feed
 *   6. Add Camera modal + discovery + form + slot picker
 *   7. Toasts
 *   8. Legacy Tailwind-style utility classes — used by pages not yet
 *      repainted to the named-component classes. Will shrink as pages
 *      migrate.
 */

/* ============================================================
   1. TOKENS + RESET
   ============================================================ */

:root {
  /* Brand palette — "Tactical / Industrial" (dark). Deep slate base (never flat
     black), muted technical-hardware cerulean accent, and *stilled* status
     colours (brick / burnt-amber / matte-emerald, not neon) for hours-long
     monitoring without retina fatigue. Chosen against the field: blue is the
     crowded VMS lane, so the accent is kept deliberately muted + utilitarian
     rather than "startup blue". See also the flat-surface rules below (no
     button gradients, no big coloured shadows, 1px borders). */
  --bg-0: #0a0f1c;
  --bg-1: #0f172a;
  --bg-2: #1e293b;
  --bg-3: #273548;
  --bg-4: #334155;
  --border-1: #1e293b;
  --border-2: #334155;
  --border-3: #475569;
  --text-1: #f1f5f9;
  --text-2: #cbd5e1;
  --text-3: #94a3b8;
  --text-4: #64748b;
  --accent: #0284c7;
  --accent-2: #0369a1;
  --accent-dim: #075985;
  /* Small text over dark image overlays — the base cerulean is too dark
     to read at caption sizes on rgba-black bars. */
  --accent-bright: #38bdf8;
  --accent-glow: rgba(2, 132, 199, 0.16);
  /* Event-statistics categorical series — validated as a set (CVD +
     contrast) against bg-1, in STACK order person→vehicle→animal→motion→
     alarm (violet/rose interleave the warm hues; orange next to yellow
     fails protanopia). Deliberately warm — no accent blue in the chart.
     Alarm deliberately IS the danger red: an alarm is status. */
  --chart-person: #ea580c;
  --chart-animal: #a16207;
  --chart-vehicle: #6d28d9;
  --chart-motion: #be185d;
  --chart-alarm: #dc2626;
  --ok: #059669;
  --ok-dim: #065f46;
  --warn: #d97706;
  --warn-dim: #92400e;
  --danger: #b91c1c;
  --danger-dim: #7f1d1d;
  --rec: #dc2626;

  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --font-display: 'Rajdhani', 'Inter', sans-serif;
  --font-body: 'Inter', system-ui, sans-serif;
}

*, ::before, ::after { box-sizing: border-box; border-width: 0; border-style: solid; }
html, body { margin: 0; padding: 0; }
html { height: 100%; -webkit-text-size-adjust: 100%; }
body {
  height: 100%;
  background: var(--bg-0);
  color: var(--text-1);
  font-family: var(--font-body);
  font-feature-settings: 'ss01', 'cv11';
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  line-height: 1.5;
}
button { font-family: inherit; cursor: pointer; background: none; color: inherit; }
a { color: inherit; text-decoration: none; }
input, select, textarea { font-family: inherit; font-size: 100%; line-height: inherit; color: inherit; }
h1, h2, h3, h4, p { margin: 0; font-size: inherit; font-weight: inherit; }
code { font-family: var(--font-mono); font-size: 0.875em; }
[x-cloak] { display: none !important; }

/* ============================================================
   2. CRT SCANLINES OVERLAY — sits over the whole app, under modals/toasts
   ============================================================ */

body::before {
  content: '';
  position: fixed; inset: 0;
  background: repeating-linear-gradient(
    0deg,
    transparent 0,
    transparent 2px,
    rgba(0, 0, 0, 0.18) 2px,
    rgba(0, 0, 0, 0.18) 3px
  );
  pointer-events: none;
  z-index: 9000;
  opacity: 0.35;
  mix-blend-mode: multiply;
}

/* ============================================================
   3. APP SHELL
   ============================================================ */

/* Outer app shell — single column. Dashboard inserts its own 2-column
   grid inside .app-main to put the sidebar next to the camera grid. */
.app {
  display: grid;
  /* Two auto rows between subnav and main host the storage + license
     banners; they collapse to 0 when hidden/absent. Children carry explicit
     grid-row assignments below — WITHOUT them a visible banner auto-places
     into the 1fr row and stretches full-height, shoving the page content
     into an implicit row (seen live: a viewport-filling amber bar). */
  grid-template-rows: 64px 52px auto auto 1fr;
  /* minmax(0,…): a bare 1fr track grows to the header/subnav min-content
     width on narrow viewports, and the overflow:hidden below then clips
     the whole shell on the right. */
  grid-template-columns: minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
  width: 100vw;
  overflow: hidden;
}
.app > .header { grid-row: 1; }
.app > .subnav { grid-row: 2; }
.app > .storage-banner { grid-row: 3; }
.app > .license-banner { grid-row: 4; }
.app > .app-main { grid-row: 5; }

.app-main {
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Scrollable inner container for non-dashboard pages (cameras, settings,
   clips, events, etc.) — preserves a centered max-width readable column. */
.app-main.scroll {
  overflow-y: auto;
  padding: 24px 20px;
}
.app-main.scroll > .content {
  margin: 0 auto;
  max-width: 80rem;
  width: 100%;
}

/* Dashboard-only 2-column inner grid: main camera grid + 360px sidebar. */
.dashboard {
  display: grid;
  grid-template-columns: 1fr 360px;
  height: 100%;
  min-height: 0;
  overflow: hidden;
}

/* ---- HEADER ---- */

.header {
  background: linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 100%);
  border-bottom: 1px solid var(--border-2);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 0 20px;
  position: relative;
  gap: 28px;
}

.header::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--accent) 30%,
    var(--accent) 70%,
    transparent 100%);
  opacity: 0.5;
  animation: scanline-sweep 5.5s ease-in-out infinite;
}

@keyframes scanline-sweep {
  0%   { transform: translateX(-100%); opacity: 0; }
  20%  { opacity: 0.7; }
  80%  { opacity: 0.7; }
  100% { transform: translateX(100%); opacity: 0; }
}

.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-right: 24px;
  border-right: 1px solid var(--border-1);
  height: 44px;
  justify-self: start;
}

.brand-mark {
  width: 28px; height: 28px;
  display: grid;
  place-items: center;
  border: 1px solid var(--accent-dim);
  border-radius: 4px;
  position: relative;
  background: var(--bg-2);
}
/* Brand colors are fixed (not --accent): the mark must stay identical across
   themes and match the favicon/site logo. Only the REC dot animates. */
.brand-mark .brand-rec { animation: pulse-soft 2s ease-in-out infinite; }

@keyframes pulse-soft {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}

.brand-meta { display: flex; flex-direction: column; }
.brand-name {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 4px;
  color: var(--text-1);
}
.brand-version {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 2px;
  color: var(--text-3);
  margin-top: 2px;
}

.header-stats {
  display: flex;
  gap: 0;
  justify-self: center;
  align-self: stretch;
  align-items: stretch;
}

.hstat {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 0 22px;
  border-left: 1px solid var(--border-1);
  min-width: 120px;
  position: relative;
}
.hstat:first-child { border-left: none; }
.hstat:last-child  { border-right: 1px solid var(--border-1); }

.hstat-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 2.5px;
  color: var(--text-3);
  text-transform: uppercase;
  margin-bottom: 4px;
}
.hstat-row { display: flex; align-items: baseline; gap: 8px; }
.hstat-val {
  font-family: var(--font-mono);
  font-size: 30px;
  font-weight: 600;
  color: var(--text-1);
  line-height: 1;
  letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
}
.hstat-val.accent { color: var(--accent); }
.hstat-val.warn   { color: var(--warn); }
.hstat-val.danger { color: var(--danger); }
.hstat-val.ok     { color: var(--ok); }
.hstat-sub {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.hstat-bar {
  height: 3px;
  background: var(--bg-3);
  margin-top: 6px;
  width: 100%;
  border-radius: 1px;
  overflow: hidden;
}
.hstat-bar-fill { height: 100%; background: var(--accent); transition: width 0.3s; }
.hstat-bar-fill.warn   { background: var(--warn); }
.hstat-bar-fill.danger { background: var(--danger); }

.header-right { display: flex; align-items: center; gap: 20px; justify-self: end; }

.system-status {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border: 1px solid var(--border-1);
  border-radius: 3px;
  background: var(--bg-2);
}
.status-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 6px var(--ok);
  animation: pulse-soft 2s ease-in-out infinite;
}
.status-dot.warn   { background: var(--warn);   box-shadow: 0 0 6px var(--warn); }
.status-dot.danger { background: var(--danger); box-shadow: 0 0 6px var(--danger); }
.status-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--text-2);
  text-transform: uppercase;
}

.clock { display: flex; flex-direction: column; align-items: flex-end; }
.clock-time {
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 500;
  color: var(--text-1);
  letter-spacing: 1px;
  font-variant-numeric: tabular-nums;
}
.clock-date {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-3);
  letter-spacing: 1.5px;
  margin-top: 2px;
  text-transform: uppercase;
}

/* ---- SUBNAV + ACTION BAR ---- */

.subnav {
  background: var(--bg-1);
  border-bottom: 1px solid var(--border-1);
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  padding: 0 20px;
  gap: 20px;
}

.nav-tabs { display: flex; height: 100%; align-items: stretch; }

.nav-tab {
  display: flex;
  align-items: center;
  padding: 0 18px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 2px;
  color: var(--text-3);
  text-transform: uppercase;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: all 0.12s;
  user-select: none;
  position: relative;
}
.nav-tab:hover { color: var(--text-2); }
.nav-tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
  background: linear-gradient(180deg, transparent, var(--accent-glow));
}
.nav-tab-badge {
  margin-left: 8px;
  font-size: 9px;
  background: var(--bg-3);
  color: var(--text-2);
  padding: 1px 5px;
  border-radius: 2px;
  font-variant-numeric: tabular-nums;
}
.nav-tab.active .nav-tab-badge { background: var(--accent); color: var(--bg-0); }

.action-bar { display: flex; gap: 8px; justify-self: end; align-items: center; }

.action-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 14px;
  border: 1px solid var(--border-2);
  background: var(--bg-2);
  color: var(--text-2);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  cursor: pointer;
  border-radius: 3px;
  transition: all 0.12s;
  font-weight: 500;
}
.action-btn:hover { border-color: var(--border-3); color: var(--text-1); background: var(--bg-3); }
.action-btn .ico { width: 12px; height: 12px; opacity: 0.8; flex-shrink: 0; }

.action-btn.primary {
  /* Flat: solid accent fill, white text, hover = one shade darker. No glow
     shadow, no halo ring (the old "AI glow" look). */
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 700;
}
.action-btn.primary:hover { background: var(--accent-2); border-color: var(--accent-2); color: #fff; }
.action-btn.primary .ico  { opacity: 1; }

.user-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: 8px;
  padding: 0 10px;
  height: 28px;
  border-left: 1px solid var(--border-1);
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
}
/* Admin name — clearly legible, not a faint label. */
.user-chip-name { color: var(--text-1); font-weight: 600; }
.user-chip form { display: inline; }
/* Log out — a small outlined button so it reads as an action, not dim text. */
.user-chip button {
  color: var(--text-2);
  padding: 3px 9px;
  border: 1px solid var(--border-2);
  border-radius: 3px;
  font-family: inherit;
  font-size: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
}
.user-chip button:hover { color: var(--text-1); border-color: var(--border-3); background: var(--bg-3); }

/* ============================================================
   4. MAIN + CAMERA GRID + TILE
   ============================================================ */

.main {
  background: var(--bg-0);
  padding: 16px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.grid-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
  padding: 0 2px;
}
.grid-meta-title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 2.5px;
  color: var(--text-3);
  text-transform: uppercase;
}
.grid-meta-controls { display: flex; align-items: center; gap: 4px; }

.layout-toggle {
  display: flex;
  gap: 2px;
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 3px;
  padding: 2px;
}
.layout-toggle button {
  min-width: 34px; height: 22px;
  padding: 0 8px;
  background: transparent;
  border: none;
  color: var(--text-3);
  cursor: pointer;
  border-radius: 2px;
  display: grid;
  place-items: center;
  font-size: 11px;
  white-space: nowrap;
  transition: all 0.12s;
}
.layout-toggle button:hover  { color: var(--text-1); }
.layout-toggle button.active { background: var(--bg-4); color: var(--accent); }

.camera-grid {
  flex: 1;
  display: grid;
  gap: 14px;
  min-height: 0;
}
/* data-count = the layout SIZE (N), so the grid is always a clean N×N matrix.
   Cameras fill the first cells; the remainder render as .tile-empty-pane. */
.camera-grid[data-count="1"] { grid-template-columns: 1fr;            grid-template-rows: 1fr; }
.camera-grid[data-count="2"] { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr); }
.camera-grid[data-count="3"] { grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(3, 1fr); }
.camera-grid[data-count="4"] { grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 1fr); }

/* Grid cell wrapper (the x-show host) — a real flex cell so the camera tile
   inside stretches to fill it exactly like the empty panes do. (A display:contents
   wrapper left the tile un-stretched → mismatched cell heights.) */
.tile-cell { display: flex; min-width: 0; min-height: 0; }
.tile-cell > .tile { flex: 1; min-width: 0; min-height: 0; }
/* drag & drop reorder affordances */
.tile-cell[draggable="true"] { cursor: grab; }
.tile-cell.drag-src { opacity: 0.45; }
.tile-cell.drag-over { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Empty matrix cell — quiet, dashed, clickable to add a camera. */
.tile-empty-pane {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--bg-2);
  border: 1px dashed var(--border-1);
  border-radius: 4px;
  color: var(--text-3, var(--text-2));
  cursor: pointer;
  opacity: 0.45;
  min-height: 0;
  transition: opacity 0.15s, border-color 0.15s, background 0.15s;
}
.tile-empty-pane:hover {
  opacity: 1;
  border-color: var(--accent);
  background: var(--bg-3);
}
.tile-empty-pane-plus  { font-size: 26px; line-height: 1; font-weight: 300; }
.tile-empty-pane-label { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; }

/* ---- TILE ---- */

.tile {
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
  cursor: pointer;
  transition: border-color 0.15s, transform 0.15s;
  min-height: 0;
}
.tile:hover { border-color: var(--border-3); }
.tile.live:hover { border-color: var(--accent-2); }
.tile.recording  { border-color: var(--rec); }
.tile.offline    { border-color: rgba(185, 28, 28, 0.25); }

.tile-stage {
  flex: 1;
  position: relative;
  overflow: hidden;
  background: #000;
  min-height: 0;
}
.tile[data-aspect="16:9"] .tile-stage { aspect-ratio: 16 / 9; flex: none; }
.tile[data-aspect="4:3"]  .tile-stage { aspect-ratio: 4 / 3;  flex: none; }
.tile[data-aspect="1:1"]  .tile-stage { aspect-ratio: 1 / 1;  flex: none; }

.tile-thumb {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

.tile-badges-tl { position: absolute; top: 8px; left: 8px;  display: flex; align-items: center; gap: 6px; z-index: 3; }
.tile-badges-tr { position: absolute; top: 8px; right: 8px; display: flex; align-items: center; gap: 6px; z-index: 3; }
.tile-badges-br { position: absolute; bottom: 8px; right: 8px; display: flex; align-items: center; gap: 6px; z-index: 3; }

.tile-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 7px;
  background: rgba(5, 10, 16, 0.78);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,0.06);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1.2px;
  color: var(--text-2);
  border-radius: 2px;
  text-transform: uppercase;
  font-weight: 600;
}
.tile-pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 4px var(--ok); }
.tile-pill.live { color: var(--ok); border-color: rgba(61, 214, 140, 0.25); }
.tile-pill.rec {
  color: #fff;
  background: rgba(255, 51, 68, 0.92);
  border-color: var(--rec);
}
.tile-pill.rec .dot {
  background: #fff;
  box-shadow: 0 0 4px #fff;
  animation: rec-blink 1.4s ease-in-out infinite;
}
@keyframes rec-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
.tile-pill.offline { color: var(--danger); border-color: rgba(185, 28, 28, 0.3); }
.tile-pill.muted   { color: var(--text-3); }

.tile-bitrate {
  font-family: var(--font-mono);
  font-size: 9px;
  color: rgba(255,255,255,0.55);
  background: rgba(5, 10, 16, 0.6);
  padding: 2px 5px;
  border-radius: 2px;
  letter-spacing: 0.5px;
}

.tile-offline-bg {
  position: absolute; inset: 0;
  background:
    repeating-linear-gradient(
      45deg,
      rgba(255,77,106,0.04) 0,
      rgba(255,77,106,0.04) 12px,
      transparent 12px,
      transparent 24px
    ),
    linear-gradient(135deg, var(--bg-2) 0%, var(--bg-0) 100%);
  display: grid;
  place-items: center;
  text-align: center;
  padding: 8px;
}
.tile-offline-inner { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.tile-offline-x {
  width: 32px; height: 32px;
  border: 1.5px solid var(--danger-dim);
  color: var(--danger);
  display: grid; place-items: center;
  font-family: var(--font-mono);
  font-size: 16px;
  border-radius: 2px;
  opacity: 0.8;
}
.tile-offline-label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 2px;
  color: var(--danger);
  text-transform: uppercase;
}
.tile-offline-since { font-family: var(--font-mono); font-size: 9px; color: var(--text-3); letter-spacing: 0.5px; }

.tile-empty {
  border: 1px dashed var(--border-1);
  border-radius: 4px;
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(
      45deg,
      transparent 0,
      transparent 14px,
      rgba(255,255,255,0.012) 14px,
      rgba(255,255,255,0.012) 28px
    );
  cursor: pointer;
  transition: all 0.15s;
}
.tile-empty:hover { border-color: var(--accent-dim); background-color: var(--accent-glow); }
.tile-empty-inner { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--text-3); }
.tile-empty-plus {
  width: 32px; height: 32px;
  border: 1px solid var(--border-2);
  border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-mono);
  font-size: 16px;
  color: var(--text-3);
}
.tile-empty:hover .tile-empty-plus { border-color: var(--accent); color: var(--accent); }
.tile-empty-label { font-family: var(--font-mono); font-size: 9px; letter-spacing: 2px; text-transform: uppercase; }

.tile-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  background: var(--bg-2);
  border-top: 1px solid var(--border-1);
  flex-shrink: 0;
  gap: 8px;
}
.tile-name { display: flex; align-items: center; gap: 8px; min-width: 0; }
.tile-slot { font-family: var(--font-mono); font-size: 10px; color: var(--text-3); letter-spacing: 1px; }
.tile-cam-name {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: 0.2px;
}
.tile-foot-meta {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-3);
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.tile.offline .tile-cam-name { color: var(--text-2); }

.tile-timestamp {
  position: absolute;
  bottom: 8px; left: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: rgba(255,255,255,0.7);
  text-shadow: 0 1px 2px rgba(0,0,0,0.9);
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  z-index: 2;
}

/* ============================================================
   5. SIDEBAR — license + events
   ============================================================ */

.sidebar {
  background: var(--bg-1);
  border-left: 1px solid var(--border-1);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.panel {
  border-bottom: 1px solid var(--border-1);
  display: flex;
  flex-direction: column;
}
/* Content-sized, NOT flex-filling: with the feed capped at 10 rows a
   stretched panel left a dead gap between the list and the license panel.
   Leftover column space now falls harmlessly below the last panel. */
.panel.events { flex: 0 1 auto; min-height: 0; }
.panel-header {
  padding: 12px 16px 8px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.panel-title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 2.5px;
  color: var(--text-3);
  text-transform: uppercase;
  font-weight: 600;
}
.panel-action {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-3);
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  background: none;
  border: none;
  padding: 2px 4px;
}
.panel-action:hover { color: var(--accent); }

/* ---- LICENSE PANEL ---- */

.license { padding: 8px 16px 16px; }

.license-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 2px;
  font-weight: 700;
  text-transform: uppercase;
  margin-bottom: 12px;
  border: 1px solid;
}
.license-pill.licensed { color: var(--ok);     border-color: var(--ok-dim);     background: rgba(61, 214, 140, 0.06); }
.license-pill.grace    { color: var(--warn);   border-color: var(--warn-dim);   background: rgba(217, 119, 6, 0.07); }
.license-pill.degraded { color: var(--danger); border-color: var(--danger-dim); background: rgba(185, 28, 28, 0.07); }
.license-pill .lp-dot  { width: 6px; height: 6px; border-radius: 50%; }
.license-pill.licensed .lp-dot { background: var(--ok);     box-shadow: 0 0 6px var(--ok); }
.license-pill.grace    .lp-dot { background: var(--warn);   box-shadow: 0 0 6px var(--warn);   animation: pulse-soft 1.6s ease-in-out infinite; }
.license-pill.degraded .lp-dot { background: var(--danger); box-shadow: 0 0 6px var(--danger); animation: pulse-soft 0.9s ease-in-out infinite; }

.license-tier {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-1);
  letter-spacing: 0.4px;
  margin-bottom: 2px;
}

/* Founder golden-ticket badge, Wonka style: a solid aged-gold field with a
   scalloped (ticket) edge and dark engraved serif lettering. Gold lives ONLY
   here, never in charts or status colors, so it stays unmistakably "founder". */
.founder-badge {
  display: block;
  padding: 12px 14px 10px;
  margin: 2px 0 6px;
  text-align: center;
  position: relative;
  background:
    /* faint crinkle over the gold leaf */
    repeating-linear-gradient(105deg,
      rgba(255, 255, 255, 0.05) 0 7px, rgba(0, 0, 0, 0.04) 7px 13px),
    linear-gradient(115deg,
      #a8842b 0%, #d9bc60 22%, #c2a13e 45%, #ecd98d 68%, #c2a13e 85%, #9c7a24 100%);
  /* scalloped edge: union of an inner rectangle + a rounded grid of bumps */
  -webkit-mask:
    linear-gradient(#000, #000) center / calc(100% - 10px) calc(100% - 10px) no-repeat,
    radial-gradient(circle 5px at center, #000 97%, transparent) 0 0 / 12px 12px round;
  mask:
    linear-gradient(#000, #000) center / calc(100% - 10px) calc(100% - 10px) no-repeat,
    radial-gradient(circle 5px at center, #000 97%, transparent) 0 0 / 12px 12px round;
}
/* the ticket's inner rule — a thin dark double frame inside the gold */
.founder-badge::before {
  content: "";
  position: absolute;
  inset: 6px;
  border: 1px solid rgba(56, 40, 10, 0.55);
  outline: 1px solid rgba(56, 40, 10, 0.25);
  outline-offset: 2px;
  pointer-events: none;
}
.founder-badge .fb-line {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
}
.founder-badge .fb-star {
  color: #4a3610;
  font-size: 12px;
  text-shadow: 0 1px 0 rgba(255, 244, 200, 0.4);
}
.founder-badge .fb-label,
.founder-badge .fb-no {
  font-family: Georgia, "Times New Roman", serif;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: #3a2b0c;
  /* engraved: light catches the bottom edge of the stamped letters */
  text-shadow: 0 1px 0 rgba(255, 244, 200, 0.45);
}
.founder-badge-sub {
  margin-top: 4px;
  font-family: Georgia, "Times New Roman", serif;
  font-style: italic;
  font-size: 10px;
  letter-spacing: 0.6px;
  color: rgba(58, 43, 12, 0.85);
}
.license-key {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  letter-spacing: 0.8px;
  margin-bottom: 14px;
  word-break: break-all;
}
.license-rows { display: flex; flex-direction: column; gap: 10px; }
.license-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 8px; }
.license-row-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1.5px;
  color: var(--text-3);
  text-transform: uppercase;
}
.license-row-val {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.license-row-val.dim    { color: var(--text-3); }
.license-row-val.warn   { color: var(--warn); }
.license-row-val.danger { color: var(--danger); }
.license-row-val.ok     { color: var(--ok); }
.license-bar {
  margin-top: 10px;
  height: 4px;
  background: var(--bg-3);
  border-radius: 2px;
  overflow: hidden;
  position: relative;
}
.license-bar-fill { height: 100%; background: var(--ok); transition: width 0.4s, background 0.3s; }
.license-bar-fill.warn   { background: var(--warn); }
.license-bar-fill.danger { background: var(--danger); }

.license-notice {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 3px;
  font-size: 11px;
  line-height: 1.45;
  display: flex;
  gap: 10px;
  align-items: flex-start;
}
.license-notice.licensed { background: rgba(61, 214, 140, 0.06); border: 1px solid rgba(61, 214, 140, 0.15); color: var(--text-2); }
.license-notice.grace    { background: rgba(217, 119, 6, 0.07); border: 1px solid rgba(217, 119, 6, 0.20); color: var(--text-1); }
.license-notice.degraded { background: rgba(185, 28, 28, 0.07); border: 1px solid rgba(185, 28, 28, 0.22); color: var(--text-1); }
.license-notice .ico { flex-shrink: 0; width: 14px; height: 14px; margin-top: 1px; }
.license-notice strong {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  display: block;
  margin-bottom: 3px;
}
.license-notice.licensed strong { color: var(--ok); }
.license-notice.grace    strong { color: var(--warn); }
.license-notice.degraded strong { color: var(--danger); }

.license-cta {
  margin-top: 10px;
  width: 100%;
  height: 30px;
  background: var(--warn);
  border: none;
  border-radius: 3px;
  color: #1a0e00;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  font-weight: 700;
  cursor: pointer;
  text-transform: uppercase;
}
.license-cta:hover  { filter: brightness(1.08); }
.license-cta.danger { background: var(--danger); color: #1a0008; }

/* Server-status diagnostic row — what the heartbeat client last heard
   from the license server. Visually subdued (it's diagnostic, not a CTA)
   but the dot picks up the ok/warn/danger colours so an outage reads at
   a glance. */
.license-server {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border-1, rgba(255,255,255,0.06));
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.license-server-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.license-server-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--text-3);
}
.license-server-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--border-2);
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-2);
}
.license-server-status.ok     { color: var(--ok);     border-color: var(--ok-dim);     background: rgba(61, 214, 140, 0.06); }
.license-server-status.warn   { color: var(--warn);   border-color: var(--warn-dim);   background: rgba(217, 119, 6, 0.07); }
.license-server-status.danger { color: var(--danger); border-color: var(--danger-dim); background: rgba(185, 28, 28, 0.07); }
.license-server-status .ls-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-3);
}
.license-server-status.ok     .ls-dot { background: var(--ok);     box-shadow: 0 0 4px var(--ok); }
.license-server-status.warn   .ls-dot { background: var(--warn);   box-shadow: 0 0 4px var(--warn);   animation: pulse-soft 1.6s ease-in-out infinite; }
.license-server-status.danger .ls-dot { background: var(--danger); box-shadow: 0 0 4px var(--danger); animation: pulse-soft 0.9s ease-in-out infinite; }
.license-server-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.5;
  color: var(--text-3);
}

/* ---- EVENTS FEED ---- */

.events { display: flex; flex-direction: column; min-height: 0; }


.events-list { overflow-y: auto; max-height: 56vh; padding: 4px 8px 16px; }

.event-row {
  display: grid;
  grid-template-columns: 24px 1fr auto;
  gap: 10px;
  align-items: start;
  padding: 9px 8px;
  border-radius: 3px;
  cursor: pointer;
  transition: background 0.1s;
  position: relative;
}
.event-row + .event-row { border-top: 1px solid var(--border-1); }
.event-row:hover { background: var(--bg-2); }

.event-cat {
  width: 22px; height: 22px;
  border-radius: 2px;
  display: grid; place-items: center;
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0;
  margin-top: 1px;
  border: 1px solid;
  flex-shrink: 0;
}
.event-cat.motion        { color: var(--accent); border-color: var(--accent-dim); background: rgba(2, 132, 199, 0.08); }
.event-cat.network       { color: var(--warn);   border-color: var(--warn-dim);   background: rgba(217, 119, 6, 0.06); }
.event-cat.storage       { color: var(--text-2); border-color: var(--border-2);   background: var(--bg-2); }
.event-cat.license       { color: var(--ok);     border-color: var(--ok-dim);     background: rgba(61, 214, 140, 0.06); }
.event-cat.license.alert { color: var(--danger); border-color: var(--danger-dim); background: rgba(185, 28, 28, 0.06); }

.event-body { min-width: 0; }
.event-title {
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-1);
  line-height: 1.3;
  margin-bottom: 2px;
}
.event-title b { font-weight: 600; color: var(--text-1); }
.event-sub {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-3);
  letter-spacing: 0.5px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.event-sub .sep { width: 2px; height: 2px; background: var(--text-4); border-radius: 50%; }
.event-time {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.event-row.unack::before {
  content: '';
  position: absolute;
  left: 0; top: 8px; bottom: 8px;
  width: 2px;
  background: var(--accent);
  border-radius: 1px;
}
.event-row.unack.alert::before { background: var(--danger); }

.events-empty {
  padding: 20px 16px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--text-3);
  text-transform: uppercase;
}

/* ============================================================
   6. DRAWER + MODAL
   ============================================================ */

.drawer-backdrop {
  position: fixed; inset: 0;
  background: rgba(2, 5, 9, 0.6);
  backdrop-filter: blur(3px);
  z-index: 200;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s;
}
.drawer-backdrop.open { opacity: 1; pointer-events: auto; }

.drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 720px;
  max-width: 100vw;
  background: var(--bg-1);
  border-left: 1px solid var(--border-2);
  z-index: 210;
  transform: translateX(100%);
  transition: transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
  display: flex;
  flex-direction: column;
  box-shadow: -20px 0 60px rgba(0,0,0,0.5);
}
.drawer.open { transform: translateX(0); }

.drawer-header {
  display: flex;
  align-items: center;
  padding: 16px 22px;
  border-bottom: 1px solid var(--border-1);
  gap: 14px;
}
.drawer-title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 700;
  color: var(--text-1);
  letter-spacing: 0.3px;
}
.drawer-slot { font-family: var(--font-mono); font-size: 11px; color: var(--text-3); letter-spacing: 1.5px; }
/* Title doubles as the rename trigger; the pencil makes that obvious. */
.drawer-title-edit {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  cursor: pointer;
  color: inherit;
  text-align: left;
}
.drawer-title-edit:disabled { cursor: default; }
.drawer-title-pencil {
  color: var(--text-3);
  opacity: 0.75;
  flex-shrink: 0;
  transition: color .12s, opacity .12s;
}
.drawer-title-edit:hover .drawer-title-pencil { color: var(--accent); opacity: 1; }
.drawer-title-edit:hover .drawer-title { color: var(--text-1); }
/* Same affordance on the Cameras-list rows: pencil next to the name marks it
   editable. text-1 (near-white) — text-3 blended into the row background. */
.row-name-pencil {
  color: var(--text-1);
  opacity: 0.8;
  flex-shrink: 0;
  transition: color .12s, opacity .12s;
}
.row-name-edit:hover .row-name-pencil { color: var(--accent); opacity: 1; }
.drawer-close {
  margin-left: auto;
  width: 32px; height: 32px;
  background: transparent;
  border: 1px solid var(--border-2);
  border-radius: 3px;
  color: var(--text-2);
  cursor: pointer;
  display: grid; place-items: center;
  font-family: var(--font-mono);
}
.drawer-close:hover { border-color: var(--danger); color: var(--danger); }

.drawer-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.drawer-feed {
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 4px;
  position: relative;
  overflow: hidden;
  border: 1px solid var(--border-2);
  /* overflow:hidden gives a flex item min-size 0; without this the column
     compresses + clips it when the drawer is taller than the viewport. */
  flex-shrink: 0;
}
.drawer-feed video { width: 100%; height: 100%; display: block; }

/* Events page — view switcher (Events | Statistics) + range picker. Shares
   the .settings-tabs segment language but without the underline row. */
.ev-view-tabs { display: flex; gap: 6px; }
.ev-view-tabs button {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  padding: 7px 14px;
  background: var(--bg-2);
  color: var(--text-3);
  border: 1px solid var(--border-2);
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  transition: color .12s, border-color .12s, background .12s;
}
.ev-view-tabs button:hover  { color: var(--text-2); border-color: var(--border-3); }
.ev-view-tabs button.active {
  background: var(--bg-3);
  color: var(--text-1);
  border-color: var(--accent-dim);
}

/* Event statistics — tiles, stacked bar chart, top sources */
.stats-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 10px;
}
.stats-tile {
  background: var(--bg-1);
  border: 1px solid var(--border-1);
  border-radius: 6px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.stats-tile-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-3);
  display: flex;
  align-items: center;
  gap: 6px;
}
.stats-tile-val {
  font-family: var(--font-mono);
  font-size: 22px;
  font-variant-numeric: tabular-nums;
  color: var(--text-1);
}
.stats-tile-sub { font-family: var(--font-mono); font-size: 11px; color: var(--text-2); }
.stats-chip {
  width: 8px; height: 8px; border-radius: 2px;
  display: inline-block; flex-shrink: 0;
}
.stats-chart-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 14px;
}
.stats-chart-title {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--text-3);
}
.stats-legend { display: flex; gap: 14px; flex-wrap: wrap; }
.stats-legend > span {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.5px;
  color: var(--text-2);
}
.stats-chart {
  display: flex;
  align-items: flex-end;
  gap: 2px;                       /* the 2px spacer between adjacent bars */
  min-height: 210px;
}
.stats-col-slot {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  justify-content: flex-end;
  cursor: default;
}
.stats-col {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  height: 180px;                  /* keep in sync with CHART_PX in the JS */
  max-width: 34px;
  width: 100%;
  margin: 0 auto;
  border-radius: 2px 2px 0 0;     /* rounds whichever segment is on top */
  overflow: hidden;
}
/* 2px spacer between stacked segments. Transparent border + padding-box
   clip (NOT margins/:first-child — under x-for the <template> nodes are
   real siblings, so structural selectors don't see segment order). The
   topmost segment's border falls on empty column space = invisible. */
.stats-seg {
  border-top: 2px solid transparent;
  background-clip: padding-box;
}
.stats-col-label {
  font-family: var(--font-mono); font-size: 10px; color: var(--text-2);
  text-align: center; white-space: nowrap; overflow: visible;
  height: 13px;
}
.stats-tip {
  position: fixed;
  transform: translate(-50%, -100%);
  z-index: 70;
  pointer-events: none;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-radius: 6px;
  padding: 8px 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-2);
  min-width: 140px;
}
.stats-tip-title { color: var(--text-1); margin-bottom: 6px; white-space: nowrap; }
.stats-tip-row {
  display: flex; align-items: center; gap: 6px;
  text-transform: capitalize;
}
.stats-tip-row b { margin-left: auto; color: var(--text-1); font-variant-numeric: tabular-nums; }
.stats-source-row {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-mono); font-size: 12px;
}
.stats-source-rank { color: var(--text-4); width: 20px; text-align: right; flex-shrink: 0; }
.stats-source-name {
  color: var(--text-2); min-width: 120px; max-width: 220px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.stats-source-bar {
  flex: 1; height: 6px; background: var(--bg-2); border-radius: 3px; overflow: hidden;
}
.stats-source-bar > span {
  /* Silver: these bars are magnitude only — a colored bar here reads as
     an alert; neutral keeps the row informational. */
  display: block; height: 100%; background: var(--text-3); border-radius: 3px;
}
.stats-source-count { color: var(--text-1); font-variant-numeric: tabular-nums; flex-shrink: 0; }

/* Settings sub-tabs — same segment language as .drawer-tabs, natural width,
   horizontal scroll on narrow screens (same pattern as the main nav tabs). */
.settings-tabs {
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--border-1);
  padding-bottom: 12px;
  overflow-x: auto;
  scrollbar-width: none;
}
.settings-tabs::-webkit-scrollbar { display: none; }
.settings-tabs button {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  padding: 8px 14px;
  background: var(--bg-2);
  color: var(--text-3);
  border: 1px solid var(--border-2);
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
  transition: color .12s, border-color .12s, background .12s;
}
.settings-tabs button:hover  { color: var(--text-2); border-color: var(--border-3); }
.settings-tabs button.active {
  background: var(--bg-3);
  color: var(--text-1);
  border-color: var(--accent-dim);
}
.settings-pane { display: flex; flex-direction: column; gap: 18px; }

/* Config tabs (Motion | AI Detection) — segment control */
.drawer-tabs {
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--border-1);
  padding-bottom: 12px;
}
.drawer-tabs button {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  padding: 8px 10px;
  background: var(--bg-2);
  color: var(--text-3);
  border: 1px solid var(--border-2);
  border-radius: 4px;
  cursor: pointer;
  transition: color .12s, border-color .12s, background .12s;
}
.drawer-tabs button:hover  { color: var(--text-2); border-color: var(--border-3); }
.drawer-tabs button.active {
  background: var(--bg-3);
  color: var(--text-1);
  border-color: var(--accent-dim);
}

.drawer-controls {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 24px;
  align-items: center;
  padding: 16px 18px;
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 4px;
}
.drawer-control-group { display: flex; flex-direction: column; gap: 6px; }
.drawer-control-label {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-3);
  letter-spacing: 2px;
  text-transform: uppercase;
}

.rec-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border: 1px solid var(--border-2);
  background: var(--bg-3);
  border-radius: 3px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--text-2);
  font-weight: 600;
  transition: all 0.15s;
}
.rec-toggle .rec-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--text-3); }
.rec-toggle:hover { color: var(--text-1); border-color: var(--border-3); }
.rec-toggle.on {
  background: rgba(255, 51, 68, 0.1);
  border-color: var(--rec);
  color: var(--rec);
}
.rec-toggle.on .rec-dot {
  background: var(--rec);
  box-shadow: 0 0 6px var(--rec);
  animation: rec-blink 1.4s ease-in-out infinite;
}

.drawer-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--border-1);
  border: 1px solid var(--border-1);
  border-radius: 4px;
  overflow: hidden;
  flex-shrink: 0;  /* overflow:hidden → min-size 0; don't let the column clip it */
}
.dstat {
  background: var(--bg-2);
  padding: 12px 14px;
  display: flex; flex-direction: column; gap: 4px;
}
.dstat-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--text-3);
}
.dstat-val {
  font-family: var(--font-mono);
  font-size: 16px;
  font-weight: 600;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}
.dstat-val.ok { color: var(--ok); }

.drawer-device {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1px;
  background: var(--border-1);
  border: 1px solid var(--border-1);
  border-radius: 4px;
  overflow: hidden;
  flex-shrink: 0;  /* overflow:hidden → min-size 0; don't let the column clip it */
}

.drawer-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}
.drawer-actions .spacer { flex: 1; }

/* AI model picker — two-tier choice cards (default vs more-accurate) */
.model-choices { display: flex; flex-direction: column; gap: 8px; }
.model-choice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 12px; border: 1px solid var(--border-2);
  border-radius: 4px; cursor: pointer; background: var(--bg-2);
  transition: border-color .12s, background .12s;
}
.model-choice:hover { border-color: var(--border-3); }
.model-choice.active { border-color: var(--accent-dim); background: var(--bg-3); }
.model-choice input { margin-top: 3px; flex-shrink: 0; }
.model-choice-body { display: flex; flex-direction: column; gap: 3px; }
.model-choice-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 13px; color: var(--text-1); font-weight: 600;
}
.model-choice-tag {
  font-family: var(--font-mono); font-size: 8px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--text-3); font-weight: 600;
  border: 1px solid var(--border-2); border-radius: 2px; padding: 1px 5px;
}
.model-choice-tag.accent { color: var(--accent); border-color: var(--accent-dim); }
.model-choice-badge {
  font-family: var(--font-mono); font-size: 9px; color: var(--ok); letter-spacing: 1px;
}
.model-choice-sub { font-size: 11px; color: var(--text-2); }
.model-choice-star { font-size: 11px; color: var(--accent); }
.model-choice-cap { font-size: 11px; color: var(--ok); }
.model-choice-warn { font-size: 11px; color: var(--danger); line-height: 1.4; }
.model-advanced { margin-top: 10px; }
.model-advanced summary {
  font-size: 11px; color: var(--text-3); cursor: pointer;
  font-family: var(--font-mono); letter-spacing: .5px;
}
.model-advanced-rf { font-size: 11px; color: var(--text-2); margin-top: 6px; }
.model-gpu-hint {
  margin-top: 10px; padding: 8px 10px; font-size: 11px; line-height: 1.5;
  color: var(--accent); background: var(--bg-2);
  border: 1px solid var(--accent-dim); border-radius: 4px;
}
.model-gpu-hint code { font-family: var(--font-mono); color: var(--text-1); }

/* ---- MODAL (Add Camera) ---- */

.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(2, 5, 9, 0.7);
  backdrop-filter: blur(4px);
  z-index: 400;
  display: none;
  align-items: center;
  justify-content: center;
}
.modal-backdrop.open { display: flex; }

.modal {
  width: 680px;
  max-width: 92vw;
  max-height: 88vh;
  background: var(--bg-1);
  border: 1px solid var(--border-2);
  border-radius: 5px;
  display: flex; flex-direction: column;
  box-shadow: 0 30px 80px rgba(0,0,0,0.6), 0 0 0 1px var(--accent-dim);
  position: relative;
  overflow: hidden;
}
.modal::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  opacity: 0.6;
}

.modal-header {
  padding: 18px 22px 14px;
  border-bottom: 1px solid var(--border-1);
  display: flex; align-items: center; gap: 18px;
}
.modal-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.5px;
  color: var(--text-1);
}
.modal-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.modal-close {
  margin-left: auto;
  width: 30px; height: 30px;
  background: transparent;
  border: 1px solid var(--border-2);
  border-radius: 3px;
  color: var(--text-2);
  cursor: pointer;
  display: grid; place-items: center;
  font-family: var(--font-mono);
}
.modal-close:hover { border-color: var(--danger); color: var(--danger); }

.stepper {
  display: flex;
  align-items: center;
  padding: 14px 22px;
  border-bottom: 1px solid var(--border-1);
  gap: 12px;
  background: var(--bg-0);
}
.step {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.step-num {
  width: 20px; height: 20px;
  border-radius: 50%;
  border: 1px solid var(--border-2);
  display: grid; place-items: center;
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  background: var(--bg-2);
}
.step.active { color: var(--accent); }
.step.active .step-num { border-color: var(--accent); color: var(--accent); background: var(--accent-glow); }
.step.done { color: var(--ok); }
.step.done .step-num { border-color: var(--ok); color: var(--ok); background: rgba(61,214,140,0.08); }
.step-rule { flex: 1; height: 1px; background: var(--border-1); }
.step-rule.done { background: var(--ok-dim); }

.modal-body { flex: 1; overflow-y: auto; padding: 22px; min-height: 280px; }
.modal-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 22px;
  border-top: 1px solid var(--border-1);
  background: var(--bg-0);
}
.modal-foot-info { font-family: var(--font-mono); font-size: 10px; color: var(--text-3); letter-spacing: 1px; text-transform: uppercase; }
.modal-buttons { display: flex; gap: 8px; }

/* discovery (Step 1) */
.disco { border: 1px solid var(--border-1); border-radius: 4px; background: var(--bg-0); }
.disco-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-1);
}
.disco-bar-label {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.disco-progress {
  flex: 1;
  height: 3px;
  background: var(--bg-2);
  border-radius: 2px;
  overflow: hidden;
  position: relative;
}
.disco-progress-fill {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  background-size: 50% 100%;
  background-repeat: no-repeat;
  animation: disco-scan 1.2s linear infinite;
}
@keyframes disco-scan {
  0%   { background-position: -50% 0; }
  100% { background-position: 150% 0; }
}
.disco-count {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* form (Step 2 + 3) */
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.form-row.single { grid-template-columns: 1fr; }

.form-field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 16px; }
.form-field-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--text-3);
  text-transform: uppercase;
}
.form-input,
.form-select {
  background: var(--bg-0);
  border: 1px solid var(--border-2);
  color: var(--text-1);
  font-family: var(--font-mono);
  font-size: 12px;
  padding: 9px 12px;
  border-radius: 3px;
  outline: none;
  transition: border-color 0.15s;
  letter-spacing: 0.3px;
}
.form-input:focus,
.form-select:focus { border-color: var(--accent); }
.form-help {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-3);
  letter-spacing: 0.5px;
  margin-top: 2px;
  word-break: break-all;
}

.test-block {
  margin-top: 4px;
  padding: 12px 14px;
  background: var(--bg-0);
  border: 1px solid var(--border-1);
  border-radius: 3px;
  display: flex; align-items: center; gap: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-2);
}
.test-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ok);
  box-shadow: 0 0 6px var(--ok);
}
.test-dot.danger { background: var(--danger); box-shadow: 0 0 6px var(--danger); }

/* generic buttons reusable across modal/drawer */
.btn-primary, .btn-secondary, .btn-ghost, .btn-danger {
  height: 34px;
  padding: 0 18px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  border-radius: 3px;
  cursor: pointer;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border: 1px solid transparent;
}
.btn-primary {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
  font-weight: 700;
}
/* Flat hover = one shade darker (not a glossy brightness bump). */
.btn-primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-secondary {
  background: var(--bg-2);
  color: var(--text-2);
  border-color: var(--border-2);
}
.btn-secondary:hover { border-color: var(--border-3); color: var(--text-1); }
.btn-ghost {
  background: transparent;
  color: var(--text-3);
  border-color: transparent;
}
.btn-ghost:hover { color: var(--text-1); }
.btn-danger {
  background: rgba(185, 28, 28, 0.10);
  color: var(--danger);
  border-color: var(--danger-dim);
}
.btn-danger:hover { background: rgba(185, 28, 28, 0.12); }

/* ============================================================
   7. TOASTS
   ============================================================ */

.toast-stack {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 600;
  display: flex; flex-direction: column;
  gap: 8px;
  pointer-events: none;
}
.toast {
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  border-left: 3px solid var(--accent);
  padding: 10px 14px;
  border-radius: 3px;
  min-width: 280px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-1);
  display: flex; align-items: center; gap: 10px;
  pointer-events: auto;
  animation: toast-in 0.2s ease-out;
}
.toast.ok     { border-left-color: var(--ok); }
.toast.warn   { border-left-color: var(--warn); }
.toast.danger { border-left-color: var(--danger); }

@keyframes toast-in {
  from { transform: translateX(20px); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

/* Scrollbars (WebKit) */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-2); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--border-3); }

/* Thin-stroke SVG icons (re-used in nav, drawer, modal) */
.svg-ico { stroke: currentColor; stroke-width: 1.5; fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* ============================================================
   7b. PAGE HELPERS — reusable chrome for non-dashboard pages
       (cameras list, settings, clips, events, login). Keeps each
       template short and visually consistent without authoring
       one-off CSS per page.
   ============================================================ */

.page { display: flex; flex-direction: column; gap: 18px; }
.page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border-1);
}
.page-title {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  color: var(--text-1);
  letter-spacing: 0.4px;
}
.page-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  letter-spacing: 1.5px;
  text-transform: uppercase;
  margin-top: 4px;
}

.page-card {
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 4px;
  padding: 16px;
}
.page-card.muted { background: var(--bg-1); }
.page-card.dense { padding: 12px 14px; }

.page-section-title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 2px;
  color: var(--text-3);
  text-transform: uppercase;
  margin-bottom: 6px;
}

.page-empty {
  padding: 32px 24px;
  border: 1px dashed var(--border-1);
  text-align: center;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  border-radius: 4px;
  background: rgba(20, 32, 46, 0.3);
}
.page-empty a { color: var(--accent); }
.page-empty a:hover { text-decoration: underline; }

.page-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border-1);
  border-radius: 4px;
  overflow: hidden;
  background: var(--bg-2);
}
.page-list > * + * { border-top: 1px solid var(--border-1); }
.page-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  background: var(--bg-2);
  transition: background 0.1s;
}
.page-row:hover { background: var(--bg-3); }
.page-row .meta { font-family: var(--font-mono); font-size: 10px; color: var(--text-3); letter-spacing: 0.5px; }
.page-row .name { font-family: var(--font-display); font-size: 14px; color: var(--text-1); font-weight: 600; }
/* One line + ellipsis, NOT break-all: on a squeezed mobile flex column,
   break-all wrapped RTSP URLs one character per line (Tailscale phone test).
   The full value rides in the element's title tooltip. */
.page-row .sub { font-family: var(--font-mono); font-size: 11px; color: var(--text-3); letter-spacing: 0.3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.page-input,
.page-select,
.page-textarea {
  background: var(--bg-0);
  border: 1px solid var(--border-2);
  color: var(--text-1);
  font-family: var(--font-mono);
  font-size: 12px;
  padding: 8px 11px;
  border-radius: 3px;
  outline: none;
  transition: border-color 0.15s;
  letter-spacing: 0.3px;
  width: 100%;
}
.page-input:focus,
.page-select:focus,
.page-textarea:focus { border-color: var(--accent); }
.page-input::placeholder { color: var(--text-4); }

.page-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--text-3);
  text-transform: uppercase;
  display: block;
  margin-bottom: 4px;
}

.page-link { color: var(--accent); cursor: pointer; }
.page-link:hover { text-decoration: underline; filter: brightness(1.1); }

.page-grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.page-grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.page-grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 700px) {
  .page-grid-2, .page-grid-3, .page-grid-4 { grid-template-columns: 1fr; }
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 8px;
  border: 1px solid var(--border-2);
  border-radius: 2px;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1.2px;
  color: var(--text-2);
  text-transform: uppercase;
  font-weight: 600;
}
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-3); }
.pill.ok { color: var(--ok); border-color: var(--ok-dim); }
.pill.ok .dot { background: var(--ok); box-shadow: 0 0 4px var(--ok); }
.pill.warn { color: var(--warn); border-color: var(--warn-dim); }
.pill.warn .dot { background: var(--warn); box-shadow: 0 0 4px var(--warn); }
.pill.danger { color: var(--danger); border-color: var(--danger-dim); }
.pill.danger .dot { background: var(--danger); box-shadow: 0 0 4px var(--danger); }
.pill.accent { color: var(--accent); border-color: var(--accent-dim); }
.pill.accent .dot { background: var(--accent); box-shadow: 0 0 4px var(--accent); }

.alert-box {
  padding: 10px 12px;
  border-radius: 3px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.3px;
}
.alert-box.danger { background: rgba(185, 28, 28, 0.08); border: 1px solid rgba(185, 28, 28, 0.25); color: var(--danger); }
.alert-box.ok     { background: rgba(61, 214, 140, 0.08); border: 1px solid rgba(61, 214, 140, 0.25); color: var(--ok); }
.alert-box.warn   { background: rgba(217, 119, 6, 0.08); border: 1px solid rgba(217, 119, 6, 0.25); color: var(--warn); }

/* ============================================================
   8. LEGACY UTILITY CLASSES (slate/emerald)
   ---------------------------------------------------------------
   Retained for pages not yet repainted to the named-component
   system. New work should prefer the .nav-tab / .tile / .panel /
   .btn-primary vocabulary above. Delete a row here when its last
   consumer template migrates.
   ============================================================ */

/* Layout */
.h-full { height: 100%; }
.h-2 { height: 0.5rem; }
.w-2 { width: 0.5rem; }
.w-32 { width: 8rem; }
.w-full { width: 100%; }
.max-w-md { max-width: 28rem; }
.max-w-lg { max-width: 32rem; }
.max-w-sm { max-width: 24rem; }
.max-w-3xl { max-width: 48rem; }
.max-w-7xl { max-width: 80rem; }
.max-h-full { max-height: 100%; }
.max-h-64 { max-height: 16rem; }
.h-4 { height: 1rem; }
.h-6 { height: 1.5rem; }
.w-4 { width: 1rem; }
.w-6 { width: 1.5rem; }
.aspect-video { aspect-ratio: 16 / 9; }

.mx-auto { margin-left: auto; margin-right: auto; }
.ml-auto { margin-left: auto; }
.ml-2 { margin-left: 0.5rem; }
.mt-1 { margin-top: 0.25rem; }
.mt-2 { margin-top: 0.5rem; }
.mt-3 { margin-top: 0.75rem; }
.mb-6 { margin-bottom: 1.5rem; }
.mb-8 { margin-bottom: 2rem; }
.px-1 { padding-left: 0.25rem; padding-right: 0.25rem; }
.px-2 { padding-left: 0.5rem; padding-right: 0.5rem; }
.px-3 { padding-left: 0.75rem; padding-right: 0.75rem; }
.px-4 { padding-left: 1rem; padding-right: 1rem; }
.py-1 { padding-top: 0.25rem; padding-bottom: 0.25rem; }
.py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
.py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }
.py-6 { padding-top: 1.5rem; padding-bottom: 1.5rem; }
.py-8 { padding-top: 2rem; padding-bottom: 2rem; }
.p-1 { padding: 0.25rem; }
.p-2 { padding: 0.5rem; }
.p-3 { padding: 0.75rem; }
.p-4 { padding: 1rem; }
.p-5 { padding: 1.25rem; }
.p-6 { padding: 1.5rem; }
.p-8 { padding: 2rem; }

.flex { display: flex; }
.inline { display: inline; }
.inline-block { display: inline-block; }
.inline-flex { display: inline-flex; }
.block { display: block; }
.grid { display: grid; }
.grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.grid-cols-12 { grid-template-columns: repeat(12, minmax(0, 1fr)); }
.gap-1 { gap: 0.25rem; }
.gap-2 { gap: 0.5rem; }
.gap-3 { gap: 0.75rem; }
.gap-4 { gap: 1rem; }
.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }
.justify-between { justify-content: space-between; }
.justify-end { justify-content: flex-end; }
.justify-center { justify-content: center; }
.justify-start { justify-content: flex-start; }
.space-y-3 > * + * { margin-top: 0.75rem; }
.space-y-4 > * + * { margin-top: 1rem; }
.space-y-6 > * + * { margin-top: 1.5rem; }
.flex-1 { flex: 1 1 0%; }
.flex-wrap { flex-wrap: wrap; }
.min-w-0 { min-width: 0; }
.shrink-0 { flex-shrink: 0; }
.relative { position: relative; }
.absolute { position: absolute; }
.fixed { position: fixed; }
.inset-0 { top: 0; right: 0; bottom: 0; left: 0; }
.inset-x-0 { left: 0; right: 0; }
.top-0 { top: 0; }
.bottom-0 { bottom: 0; }
.z-50 { z-index: 50; }
.overflow-hidden { overflow: hidden; }
.overflow-y-auto { overflow-y: auto; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pointer-events-none { pointer-events: none; }
.pointer-events-auto { pointer-events: auto; }
.cursor-not-allowed { cursor: not-allowed; }
.cursor-not-allowed:disabled { pointer-events: none; }

.rounded { border-radius: 0.25rem; }
.rounded-lg { border-radius: 0.5rem; }
.rounded-full { border-radius: 9999px; }
.border { border-width: 1px; }
.border-b { border-bottom-width: 1px; }
.border-t { border-top-width: 1px; }
.border-dashed { border-style: dashed; }
.divide-y > * + * { border-top-width: 1px; }
.divide-slate-800 > * + * { border-color: #1e293b; }

.antialiased { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
.text-xs { font-size: 0.75rem; line-height: 1rem; }
.text-sm { font-size: 0.875rem; line-height: 1.25rem; }
.text-base { font-size: 1rem; line-height: 1.5rem; }
.text-lg { font-size: 1.125rem; line-height: 1.75rem; }
.text-xl { font-size: 1.25rem; line-height: 1.75rem; }
.text-2xl { font-size: 1.5rem; line-height: 2rem; }
.text-center { text-align: center; }
.text-left { text-align: left; }
.uppercase { text-transform: uppercase; }
.tracking-tight { letter-spacing: -0.025em; }
.tracking-wide { letter-spacing: 0.025em; }
.font-medium { font-weight: 500; }
.font-semibold { font-weight: 600; }
.font-mono { font-family: var(--font-mono); }

.bg-slate-900 { background-color: #0f172a; }
.bg-slate-950 { background-color: #020617; }
.bg-slate-800 { background-color: #1e293b; }
.bg-slate-700 { background-color: #334155; }
.bg-slate-600 { background-color: #475569; }
.bg-slate-500 { background-color: #64748b; }
.bg-emerald-400 { background-color: #34d399; }
.bg-emerald-500 { background-color: #10b981; }
.bg-amber-400 { background-color: #fbbf24; }
.bg-rose-500 { background-color: #f43f5e; }
.bg-rose-950 { background-color: #4c0519; }
.bg-rose-950\/80 { background-color: rgba(76, 5, 25, 0.8); }
.bg-black { background-color: #000; }
.bg-black\/60 { background-color: rgba(0, 0, 0, 0.6); }
.text-white { color: #ffffff; }
.text-slate-100 { color: #f1f5f9; }
.text-slate-200 { color: #e2e8f0; }
.text-slate-300 { color: #cbd5e1; }
.text-slate-400 { color: #94a3b8; }
.text-slate-500 { color: #64748b; }
.text-slate-600 { color: #475569; }
.text-slate-700 { color: #334155; }
.text-slate-950 { color: #020617; }
.text-rose-200 { color: #fecdd3; }
.text-rose-300 { color: #fda4af; }
.text-rose-400 { color: #fb7185; }
.text-emerald-400 { color: #34d399; }
.text-amber-400 { color: #fbbf24; }
.text-amber-400 a { color: inherit; }
.border-slate-700 { border-color: #334155; }
.border-slate-800 { border-color: #1e293b; }
.border-rose-700 { border-color: #be123c; }
.ring-2 { box-shadow: 0 0 0 2px var(--tw-ring-color); }
.ring-emerald-400 { --tw-ring-color: #34d399; }
.bg-gradient-to-b { background-image: linear-gradient(to bottom, var(--tw-gradient-from), var(--tw-gradient-to)); }
.from-black\/70 { --tw-gradient-from: rgba(0, 0, 0, 0.7); }
.to-transparent { --tw-gradient-to: transparent; }

.hover\:text-white:hover { color: #ffffff; }
.hover\:text-rose-400:hover { color: #fb7185; }
.hover\:bg-emerald-400:hover { background-color: #34d399; }
.hover\:bg-slate-700:hover { background-color: #334155; }
.hover\:underline:hover { text-decoration: underline; }
.focus\:border-emerald-400:focus { border-color: #34d399; }
.focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; }
.disabled\:opacity-50:disabled { opacity: 0.5; }

@media (min-width: 640px) {
  .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sm\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .sm\:grid-cols-24 { grid-template-columns: repeat(24, minmax(0, 1fr)); }
  .sm\:col-span-2 { grid-column: span 2 / span 2; }
}
@media (min-width: 1024px) {
  .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ─── Focused camera view (v2 design — focused-view.jsx) ─────────────
   Single-camera fullscreen layout with toolbar / feed / control strip.
   Composed on top of the livePlayer Alpine component.
*/
.focused {
  flex: 1;
  display: grid;
  grid-template-rows: 50px 1fr auto;
  min-height: 0;
  background: var(--bg-0);
  border: 1px solid var(--border-1);
  border-radius: 4px;
  overflow: hidden;
}

.focused-toolbar {
  display: flex;
  align-items: center;
  padding: 0 16px;
  background: var(--bg-1);
  border-bottom: 1px solid var(--border-1);
  gap: 16px;
  position: relative;
}

.focused-toolbar::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: linear-gradient(90deg, transparent 0%, var(--accent) 50%, transparent 100%);
  opacity: 0.35;
}

.focused-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 12px 0 10px;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: var(--text-1);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  cursor: pointer;
  border-radius: 3px;
  font-weight: 600;
  transition: all 0.12s;
}
.focused-back:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-glow);
}

.focused-title-block {
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--border-1);
  padding-left: 16px;
  line-height: 1.1;
}

.focused-slot {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-3);
  letter-spacing: 1.5px;
}

.focused-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-1);
  letter-spacing: 0.5px;
  margin-top: 2px;
}

.focused-toolbar-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 12px;
}

.focused-toolbar-right .tile-pill {
  font-size: 10px;
  padding: 4px 9px;
  letter-spacing: 1.5px;
}

.focused-feed {
  position: relative;
  background: #000;
  overflow: hidden;
  min-height: 0;
}

.focused-controls {
  display: grid;
  grid-template-columns: auto 220px auto 1fr auto;
  gap: 22px;
  padding: 14px 18px;
  background: var(--bg-1);
  border-top: 1px solid var(--border-1);
  align-items: end;
}

.focused-ctl-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.focused-ctl-group .drawer-control-label {
  margin-bottom: 0;
}

.focused-stats-grid {
  display: grid;
  grid-template-columns: repeat(4, auto);
  gap: 0;
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 3px;
  overflow: hidden;
}

.focused-stats-grid > div {
  padding: 8px 14px;
  border-right: 1px solid var(--border-1);
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.focused-stats-grid > div:last-child { border-right: none; }

.focused-stats-grid .dstat-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1.5px;
  color: var(--text-3);
  text-transform: uppercase;
}

.focused-stats-grid .dstat-val {
  font-family: var(--font-mono);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-1);
  font-variant-numeric: tabular-nums;
}

/* ─── Minimal fullscreen view (feat/live-view-redesign) ──────────────────── */
.focused-min { display: flex; flex-direction: column; height: 100%; background: #000; }
.focused-min-bar { display: flex; align-items: center; gap: 10px; padding: 10px 14px; background: var(--bg-1); border-bottom: 1px solid var(--border-1); }
.focused-min-title { font-family: var(--font-display); font-weight: 600; color: var(--text-1); }
.focused-min-stage { position: relative; flex: 1; min-height: 0; }
.focused-min-actions { display: flex; gap: 8px; padding: 10px 14px; background: var(--bg-1); border-top: 1px solid var(--border-1); }
/* Substream bridge: covers the (still-black) HD video until its first frame
   paints, then crossfades away. pointer-events off so controls stay usable. */
.bridge-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; background: #000; pointer-events: none; opacity: 1; transition: opacity 0.4s ease; }
.bridge-video.bridge-fading { opacity: 0; }
.bridge-video.bridge-hidden { display: none; }

/* ===== CAMERA TILE ===== */

.tile {
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 4px;
  overflow: hidden;
}

/* PTZ + zoom controls (used by the focused view and the drawer). */
.ptz {
  display: grid;
  grid-template-columns: repeat(3, 32px);
  grid-template-rows: repeat(3, 32px);
  gap: 2px;
}

.ptz button {
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  color: var(--text-2);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 12px;
  border-radius: 2px;
  transition: all 0.1s;
}
.ptz button:hover { background: var(--bg-3); color: var(--accent); border-color: var(--accent-dim); }
.ptz button:active { background: var(--accent-glow); }

.drawer-controls {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 24px;
  align-items: start;
  padding: 16px 18px;
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 4px;
}

.drawer-control-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.drawer-control-label {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-3);
  letter-spacing: 2px;
  text-transform: uppercase;
}

.zoom-row {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 200px;
}

.zoom-row button {
  width: 28px; height: 28px;
  background: var(--bg-3);
  border: 1px solid var(--border-2);
  color: var(--text-2);
  border-radius: 2px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 14px;
}
.zoom-row button:hover { color: var(--accent); border-color: var(--accent-dim); }

.zoom-track {
  flex: 1;
  height: 4px;
  background: var(--bg-3);
  border-radius: 2px;
  position: relative;
  cursor: pointer;
}

.zoom-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 2px;
}

.zoom-handle {
  position: absolute;
  top: 50%;
  width: 12px; height: 12px;
  background: var(--accent);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 3px rgba(2, 132, 199, 0.4);
}

.rec-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Offline state for focused view (additions beyond the handoff CSS). */
.focused-offline {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(45deg,
      rgba(185, 28, 28, 0.04) 0,
      rgba(185, 28, 28, 0.04) 16px,
      transparent 16px,
      transparent 32px),
    linear-gradient(135deg, var(--bg-2) 0%, var(--bg-0) 100%);
}
.focused-offline-mark {
  width: 72px;
  height: 72px;
  border: 2px solid var(--danger-dim, #5a2030);
  color: var(--danger);
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 36px;
  border-radius: 4px;
  margin: 0 auto 18px;
}
.focused-offline-label {
  font-family: var(--font-mono);
  font-size: 16px;
  letter-spacing: 5px;
  color: var(--danger);
  font-weight: 600;
}
.focused-offline-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-3);
  margin-top: 10px;
  letter-spacing: 1px;
}
.focused-offline-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-4);
  margin-top: 24px;
  letter-spacing: 1.5px;
}
.focused-controls-offline {
  padding: 18px 0;
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1.5px;
  display: flex;
  align-items: center;
  gap: 14px;
}

/* ─── Playback workspace (v2 design — playback.jsx) ────────────────
   Fullscreen review surface: header / video / transport / timeline /
   footer. Designed as a "playback-modal" in the JSX; we render it as
   a full page since the surface is fullscreen either way.

   The .playback-modal selector below is preserved so the lifted CSS
   works unchanged; the template uses .playback-page which shares the
   same rules via the alias rule at the bottom of this block.
*/
.playback-modal {
  width: 1080px;
  max-width: 96vw;
  max-height: 92vh;
  background: var(--bg-1);
  border: 1px solid var(--border-2);
  border-radius: 5px;
  display: flex;
  flex-direction: column;
  box-shadow: 0 30px 80px rgba(0,0,0,0.6), 0 0 0 1px var(--warn-dim);
  position: relative;
  overflow: hidden;
}

.playback-modal::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--warn), transparent);
  opacity: 0.6;
}

.playback-header {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-1);
}

.playback-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--warn-dim);
  background: rgba(217, 119, 6, 0.08);
  color: var(--warn);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 2px;
  font-weight: 700;
  border-radius: 3px;
}

.playback-cam {
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--border-1);
  padding-left: 14px;
  line-height: 1.15;
}

.playback-slot {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  color: var(--text-3);
}

.playback-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-1);
  letter-spacing: 0.4px;
  margin-top: 2px;
}

.playback-header .modal-close { margin-left: auto; }

.playback-video {
  position: relative;
  background: #000;
  height: 360px;
  overflow: hidden;
  border-bottom: 1px solid var(--border-1);
}

.playback-no-footage {
  position: absolute; inset: 0;
  display: grid;
  place-items: center;
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,0.012) 0, rgba(255,255,255,0.012) 14px, transparent 14px, transparent 28px),
    var(--bg-2);
}

.playback-overlay-tl { position: absolute; top: 12px; left: 12px; }
.playback-overlay-tr { position: absolute; top: 12px; right: 12px; }
.playback-overlay-bl { position: absolute; bottom: 12px; left: 12px; }

.playback-ts {
  font-family: var(--font-mono);
  font-size: 14px;
  color: rgba(255,255,255,0.92);
  background: rgba(5, 10, 16, 0.7);
  padding: 4px 10px;
  border-radius: 2px;
  letter-spacing: 1px;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}

/* Body: video window (left) + clips rail (right). Rail wraps below on narrow.
   The body gets a fixed height so the video (now flex, no aspect-ratio) keeps a
   real size; the 3-class selector overrides the old .playback-page .playback-video
   width:100%/aspect-ratio that would otherwise eat the rail's space. */
.playback-body { display: flex; align-items: stretch; min-height: 340px; height: 62vh; max-height: 680px; }
.playback-page .playback-body .playback-video {
  flex: 1 1 0;
  min-width: 0;
  width: auto;
  height: 100%;
  max-height: none;
  aspect-ratio: auto;
}

.playback-clips {
  flex: 0 0 280px;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-left: 1px solid var(--border-1);
  background: var(--bg-1);
}
.playback-clips-head {
  padding: 10px 14px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-3);
  border-bottom: 1px solid var(--border-1);
}
.playback-clips-list { flex: 1; overflow-y: auto; min-height: 0; }
.playback-clips-empty {
  padding: 18px 14px;
  font-size: 12px;
  color: var(--text-4);
  line-height: 1.5;
}
.playback-clip-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border-1);
  cursor: pointer;
  text-align: left;
}
.playback-clip-row:hover:not(:disabled) { background: var(--bg-2); }
.playback-clip-row.active { background: var(--bg-3); }
.playback-clip-row:disabled { opacity: 0.55; cursor: default; }
.playback-clip-row-main { display: flex; flex-direction: column; min-width: 0; gap: 2px; }
.playback-clip-row-time {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-1);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.playback-clip-row-sub {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--text-4);
}

/* Clip player overlay — covers the main window while a clip plays. */
.playback-clip-overlay { position: absolute; inset: 0; z-index: 5; background: #000; }
.playback-clip-back {
  position: absolute; top: 10px; left: 10px; z-index: 6;
  height: 28px; padding: 0 12px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px;
  background: var(--bg-2); color: var(--text-1);
  border: 1px solid var(--border-3); border-radius: 4px; cursor: pointer;
}
.playback-clip-back:hover { background: var(--bg-3); border-color: var(--accent-dim); }
.playback-clip-label {
  position: absolute; top: 14px; right: 14px; z-index: 6;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px;
  color: var(--text-3);
}

@media (max-width: 760px) {
  .playback-body { flex-direction: column; }
  .playback-clips { flex-basis: auto; max-height: 220px; border-left: none; border-top: 1px solid var(--border-1); }
}

.playback-transport {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 12px 18px;
  background: var(--bg-0);
  border-bottom: 1px solid var(--border-1);
  gap: 16px;
}

.playback-transport-left  { display: flex; align-items: center; gap: 8px; }
.playback-transport-center { display: flex; align-items: center; gap: 6px; justify-self: center; }
.playback-transport-right  { display: flex; align-items: center; gap: 10px; justify-self: end; }

.pb-date {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-1);
  letter-spacing: 1.5px;
  font-weight: 600;
  padding: 0 6px;
}

.pb-icon-btn {
  width: 28px; height: 28px;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: var(--text-2);
  cursor: pointer;
  border-radius: 3px;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 12px;
  transition: all 0.12s;
}
.pb-icon-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-glow);
}

.pb-play {
  width: 40px; height: 32px;
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #04141a;
  cursor: pointer;
  border-radius: 3px;
  font-size: 13px;
  font-weight: 700;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
}
.pb-play:hover { filter: brightness(1.1); }

.pb-speed-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1.5px;
  color: var(--text-3);
}

.pb-speed-pills { display: flex; }

.pb-speed {
  height: 28px;
  min-width: 36px;
  padding: 0 8px;
  background: var(--bg-2);
  border: 1px solid var(--border-2);
  color: var(--text-3);
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.1s;
}
.pb-speed:first-child { border-radius: 3px 0 0 3px; }
.pb-speed:last-child  { border-radius: 0 3px 3px 0; }
.pb-speed + .pb-speed { border-left: none; }
.pb-speed:hover { color: var(--text-1); }
.pb-speed.active {
  background: var(--accent-glow);
  color: var(--accent);
  border-color: var(--accent);
  position: relative;
  z-index: 1;
}

.playback-timeline {
  padding: 6px 18px 16px;
  background: var(--bg-0);
}

.pb-ruler { position: relative; height: 18px; }
.pb-ruler-mark {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--text-3);
  letter-spacing: 0.5px;
}
.pb-ruler-mark span {
  display: block;
  padding-top: 5px;
  border-top: 4px solid var(--border-2);
}

.pb-track {
  position: relative;
  height: 36px;
  background: var(--bg-2);
  border: 1px solid var(--border-1);
  border-radius: 3px;
  margin-bottom: 22px;
  cursor: crosshair;
}

.pb-segment {
  position: absolute;
  top: 2px; bottom: 2px;
  background: var(--accent);
  border-radius: 2px;
  opacity: 1;
}

.pb-event {
  position: absolute;
  cursor: pointer;
  z-index: 2;
}

.pb-event-motion  { background: var(--accent); box-shadow: 0 0 5px var(--accent); top: 8px; height: 20px; width: 2px; transform: translateX(-50%); }
.pb-event-network { background: var(--warn);   box-shadow: 0 0 5px var(--warn);   top: 8px; height: 20px; width: 2px; transform: translateX(-50%); }
.pb-event.alert   { background: var(--danger); box-shadow: 0 0 6px var(--danger); }

.pb-playhead {
  position: absolute;
  top: -10px; bottom: -6px;
  transform: translateX(-50%);
  pointer-events: none;
  z-index: 3;
}
.pb-playhead-stem {
  position: absolute;
  left: 50%; top: 16px;
  width: 2px;
  height: calc(100% - 16px);
  background: #fff;
  box-shadow: 0 0 6px rgba(255,255,255,0.5);
  transform: translateX(-50%);
}
.pb-playhead-flag {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  background: #fff;
  color: #04141a;
  padding: 2px 6px;
  border-radius: 2px;
  letter-spacing: 0.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transform: translateX(-50%);
  position: absolute;
  top: 0; left: 50%;
}

.pb-legend {
  display: flex;
  align-items: center;
  gap: 18px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 1px;
  color: var(--text-2);
  text-transform: uppercase;
}
.pb-leg-swatch {
  display: inline-block;
  width: 12px; height: 8px;
  margin-right: 6px;
  vertical-align: middle;
  border-radius: 1px;
}
.pb-leg-swatch.seg     { background: var(--accent); }
.pb-leg-swatch.motion  { background: var(--accent); width: 2px; height: 12px; }
.pb-leg-swatch.network { background: var(--warn);   width: 2px; height: 12px; }

.playback-footer {
  display: flex;
  align-items: center;
  padding: 12px 18px;
  border-top: 1px solid var(--border-1);
  background: var(--bg-1);
  gap: 8px;
}

.playback-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 40px;
  padding: 0 16px;
  background: rgba(217, 119, 6, 0.10);
  border: 1px solid var(--warn-dim);
  color: var(--warn);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  font-weight: 700;
  border-radius: 3px;
  cursor: pointer;
  transition: all 0.12s;
}
.playback-btn:hover {
  background: rgba(217, 119, 6, 0.18);
  border-color: var(--warn);
  color: var(--warn);
}
.playback-btn .playback-icon { display: inline-flex; }

/* Toast */
.toast-stack {
  position: fixed;
}

/* Alias .playback-page to .playback-modal so we don't need to fork
   the handoff CSS for the page rendering. */
.playback-page {
  /* Simple windowed layout (scrollable page): a fixed-aspect video window on
     top, controls/timeline flow below. Do NOT depend on a full-height parent
     (height:100% collapsed the video to ~0 = "no playback window"). The page
     sizes to its content and the normal .app-main scroll handles overflow. */
  display: flex;
  flex-direction: column;
  width: 100%;
  background: var(--bg-1);
  border: 1px solid var(--border-2);
  border-radius: 4px;
  overflow: hidden;
  position: relative;
}
/* The actual playback window — always visible, 16:9, capped so it fits the
   viewport with room for the controls below. */
.playback-page .playback-video {
  flex: none;
  width: 100%;
  aspect-ratio: 16 / 9;
  max-height: 72vh;
  height: auto;
  min-height: 240px;
}

/* Object-detection feed rows. The thumb occupies the row's 24px first grid
   column (same slot as .event-cat, which is 22px) — keep it ≤24px so it
   doesn't overflow into the event body. */
.event-thumb {
  width: 24px;
  height: 24px;
  border-radius: 3px;
  overflow: hidden;
  margin-top: 1px;
  background: var(--bg-2);
}
.event-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.event-thumb.missing img { display: none; }

/* SP2 events tab. `display` lives in these classes (NOT inline) because Alpine
   x-show calls style.removeProperty('display') when it shows an element — an
   inline display:grid/flex would be stripped and the element collapses to
   block (the 3×3 grid would stack full-width). In a class the layout survives;
   x-show only toggles the inline display:none. */
/* Events tab layout: 3×3 grid + 380px list side by side. Was an inline style
   on the template — promoted to a class so the phone breakpoint can restack
   it (media query at the bottom of this file). */
.ev-layout {
  display: grid;
  grid-template-columns: 1fr 380px;
  gap: 16px;
  align-items: stretch;
  height: calc(100dvh - 190px);
  min-height: 460px;
}
.ev-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 8px;
  flex: 1;
  min-height: 0;
}
.ev-nl-search { display: flex; align-items: center; gap: 8px; }
.event-badge {
  margin-left: 6px;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1px;
  text-transform: uppercase;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--bg-2);
  color: var(--text-2);
  vertical-align: middle;
}
.event-badge.person { color: var(--accent); }
.event-badge.vehicle { color: var(--warn); }
.event-badge.animal { color: var(--ok); }
.event-badge.other { color: var(--text-3); }

.drawer-detection { padding: 12px 0; border-top: 1px solid var(--border-1); }
.rec-toggle.locked { opacity: .6; cursor: pointer; }
.det-zones { font-size: 12px; color: var(--text-3); margin-top: 4px; }
.motion-presets { display: flex; gap: 4px; margin-top: 6px; }
.motion-presets button {
  flex: 1; padding: 6px 0; font-size: 11px; cursor: pointer;
  background: var(--bg-2); color: var(--text-2);
  border: 1px solid var(--border-1); border-radius: 4px;
}
.motion-presets button.active {
  background: var(--accent); color: #fff; border-color: var(--accent);
}
.motion-preset-desc { margin: 8px 0 0; font-size: 11px; color: var(--text-2); }
.motion-gated-hint {
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--text-3);
  line-height: 1.4;
}
.motion-presets button:disabled {
  opacity: .45;
  cursor: not-allowed;
}
.motion-advanced { margin-top: 10px; }
.motion-advanced summary { cursor: pointer; font-size: 11px; color: var(--text-2); }
.det-rule, .det-rule-add { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; font-size: 12px; margin-top: 6px; }
.btn-link { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 12px; }
.btn-link.danger { color: var(--danger); }
.alert-counter {
  background: var(--danger);
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 2px 8px;
  font-family: var(--font-mono);
  font-size: 12px;
  cursor: pointer;
  margin-right: 8px;
}

/* Zone editor modal — zone-specific styles (base .modal* classes in app.css above) */
.modal-wide { max-width: 880px; width: 92vw; }
.zone-canvas-wrap { position: relative; display: inline-block; max-width: 100%; }
.zone-hint { margin: 8px 0 0; font-family: var(--font-mono); font-size: 11px; color: var(--text-3); letter-spacing: .3px; }
.zone-backdrop { display: block; max-width: 100%; height: auto; }
.zone-canvas { position: absolute; inset: 0; cursor: crosshair; }
.zone-controls { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
.zone-list { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.zone-item { display: flex; gap: 6px; align-items: center; padding: 2px 8px; border: 1px solid var(--border-1); border-radius: 4px; cursor: pointer; }
.zone-item.active { border-color: var(--accent); }
.zone-actions { margin-top: 12px; }

/* License panel — paid feature gate row (locked vs entitled) */
.license-features { margin-top: 8px; border-top: 1px solid var(--border-1); padding-top: 8px; }
.license-feature { display: flex; align-items: center; gap: 8px; font-size: 12px; }
.license-feature.feature-locked { color: var(--text-4); }
.license-feature.feature-on .lf-ico { color: var(--ok); }
.license-feature .lf-cta { margin-left: auto; color: var(--accent); }

/* NL-search header bar + results overlay */
.header-search { display: flex; align-items: center; gap: 6px; margin: 0 16px; flex: 1; max-width: 420px; }
.nl-search-input {
  flex: 1; background: var(--bg-2); border: 1px solid var(--border-1);
  color: var(--text-1); border-radius: 6px; padding: 6px 10px; font-size: 13px;
}
.nl-search-btn {
  background: var(--accent); color: #000; border: none; border-radius: 6px;
  padding: 6px 12px; font-size: 13px; cursor: pointer;
}
.nl-search-btn:disabled { opacity: 0.5; cursor: default; }

/* Search-results overlay. Hidden by DEFAULT (display:none) and shown only via
   the reactive `.is-open` class — NOT via x-show toggling against a
   display:flex baked into this class. That older pattern fails open: if the
   rule is ever (re)applied while the store says closed but x-show hasn't run
   its hide(), the fixed full-screen backdrop blocks the whole UI. Default-hidden
   makes the fail-safe state hidden. */
.nl-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.6);
  display: none; align-items: flex-start; justify-content: center;
  z-index: 1000; padding: 64px 24px;
}
.nl-overlay.is-open { display: flex; }
.nl-overlay-panel {
  background: var(--bg-1); border: 1px solid var(--border-1); border-radius: 10px;
  width: min(960px, 100%); max-height: 80vh; overflow: auto; padding: 16px;
}
.nl-overlay-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.nl-overlay-title { color: var(--text-3); font-size: 14px; }
.nl-overlay-close { background: none; border: none; color: var(--text-4); cursor: pointer; font-size: 16px; }
.nl-overlay-msg { color: var(--text-4); padding: 32px; text-align: center; }
.nl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 10px; }
.nl-card { display: block; border: 1px solid var(--border-1); border-radius: 8px; overflow: hidden; text-decoration: none; }
.nl-card-thumb { aspect-ratio: 16 / 9; background: var(--bg-2); position: relative; overflow: hidden; }
/* Zooms the tile onto the matched object's bbox (vars set per-hit from JS);
   hover eases back to the full frame. img + bbox overlay scale together. */
.nl-card-zoom {
  position: absolute;
  inset: 0;
  transform-origin: var(--tz-origin, 50% 50%);
  transform: scale(var(--tz-scale, 1));
  transition: transform 0.25s ease;
}
.nl-card:hover .nl-card-zoom { transform: scale(1); }
.nl-card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.nl-card-box { position: absolute; border: 2px solid var(--accent); border-radius: 3px; box-shadow: 0 0 0 1px rgba(0,0,0,0.4); pointer-events: none; }
/* The tile zoom scales border thickness too — 2px reads as a fat 6px pill at
   3x. Counter-scale so the box stays hairline at any zoom;
   hover (full frame, scale 1) falls back to .nl-card-box's own 2px. */
.nl-card-zoom .nl-card-box {
  border-width: calc(2px / var(--tz-scale, 1));
  border-radius: calc(3px / var(--tz-scale, 1));
  box-shadow: 0 0 0 calc(1px / var(--tz-scale, 1)) rgba(0, 0, 0, 0.4);
}
.nl-card:hover .nl-card-zoom .nl-card-box {
  border-width: 2px;
  border-radius: 3px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4);
}
.nl-card-meta { display: flex; justify-content: space-between; align-items: center; padding: 6px 8px; }
.nl-card-score { color: var(--text-4); font-size: 12px; }
/* In-overlay snapshot viewer (click on a result card) */
.nl-viewer-stage { position: relative; border-radius: 8px; overflow: hidden; background: var(--bg-2); }
.nl-viewer-stage img { width: 100%; display: block; }
.nl-viewer-bar { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.nl-viewer-time { color: var(--text-4); font-size: 12px; }
.nl-viewer-back {
  margin-left: auto; background: none; border: 1px solid var(--border-1);
  color: var(--text-3); border-radius: 6px; padding: 6px 12px; font-size: 13px; cursor: pointer;
}
.nl-viewer-play {
  background: var(--accent); color: #000; border-radius: 6px; border: none;
  padding: 6px 14px; font-size: 13px; text-decoration: none; cursor: pointer;
}
/* Banner shown over weak result sets — the grid stays (closest matches are
   still useful) but the user is told not to trust them as confirmations. */
.nl-weak-banner {
  display: flex; align-items: center; gap: 8px; margin-bottom: 10px;
  padding: 8px 12px; border: 1px solid var(--warn-dim); border-radius: 6px;
  color: var(--warn); font-size: 12px;
}

/* Weaker matches: dimmed cards below the strong grid, behind a toggle. */
.nl-card-weak { opacity: 0.55; }
.nl-card-weak:hover { opacity: 1; }
.nl-weak-toggle-row { display: flex; justify-content: center; margin-top: 12px; }

/* ── Remote Access card (dashboard) — license-panel visual language ─── */
.relay-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 10px;
}
.relay-label {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 1.5px;
  text-transform: uppercase; color: var(--text-3);
}
/* Framed like the LICENSED pill — every sidebar status reads the same. */
.relay-status {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px;
  border: 1px solid var(--border-2); border-radius: 2px;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--text-3);
}
.relay-status .ls-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--text-3); }
.relay-status.ok   { color: var(--ok); border-color: var(--ok-dim); background: rgba(61, 214, 140, 0.06); }
.relay-status.ok .ls-dot   { background: var(--ok); box-shadow: 0 0 4px var(--ok); }
.relay-status.warn { color: var(--warn); border-color: var(--warn-dim); background: rgba(217, 119, 6, 0.07); }
.relay-status.warn .ls-dot { background: var(--warn); box-shadow: 0 0 4px var(--warn); animation: pulse-soft 1.6s ease-in-out infinite; }
.relay-url-row {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-2); border: 1px solid var(--border-1);
  border-radius: 6px; padding: 8px 10px;
}
.relay-url {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-family: var(--font-mono); font-size: 12px;
  color: var(--text-1); text-decoration: none;
}
.relay-url:hover { color: var(--accent); }
.relay-copy {
  flex-shrink: 0; font-family: var(--font-mono); font-size: 9px;
  letter-spacing: 1px; text-transform: uppercase; padding: 4px 10px;
  border: 1px solid var(--border-2); background: none; color: var(--text-2);
  border-radius: 4px; cursor: pointer;
}
.relay-copy:hover { color: var(--accent); border-color: var(--accent-dim); }
.relay-meta {
  margin-top: 6px; font-family: var(--font-mono); font-size: 10px;
  color: var(--text-3);
}

/* ── Upgrade / compare-plans page (/upgrade) + premium-feature tag ───── */
.lf-tag {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent-dim);
  border-radius: 2px;
  padding: 1px 5px;
}
.license-feature .lf-tag + .lf-cta { margin-left: 8px; }

.upgrade-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px;
  margin-bottom: 20px;
  border: 1px solid var(--border-2);
  border-radius: 8px;
  background: linear-gradient(180deg, var(--accent-glow) 0%, transparent 100%);
}
.upgrade-hero strong { display: block; color: var(--text-1); font-size: 15px; }
.upgrade-hero .muted { color: var(--text-3); font-size: 13px; }
.upgrade-hero .license-trial-err { flex-basis: 100%; color: var(--danger); font-size: 12px; margin: 0; }

.plan-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
}
@media (max-width: 920px) { .plan-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .plan-grid { grid-template-columns: 1fr; } }

.plan-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  border: 1px solid var(--border-1);
  border-radius: 8px;
  background: var(--bg-1);
}
.plan-card.current { border-color: var(--accent-dim); box-shadow: 0 0 0 1px var(--accent-dim); }
.plan-card h2 { font-size: 15px; color: var(--text-1); margin: 0; }
.plan-price { font-size: 22px; font-weight: 700; color: var(--text-1); margin: 0; }
.plan-price .muted { font-size: 12px; font-weight: 400; color: var(--text-3); }
.plan-feats { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; flex: 1; }
.plan-feats li { font-size: 12px; color: var(--text-2); padding-left: 16px; position: relative; }
.plan-feats li::before { content: "✓"; position: absolute; left: 0; color: var(--ok); }
.plan-card .btn-primary { text-align: center; text-decoration: none; }
.plan-card .btn-primary[disabled] { opacity: 0.5; cursor: not-allowed; }
.plan-current {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--accent);
  text-align: center;
  padding: 6px 0;
}

.upgrade-note { margin-top: 18px; font-size: 12px; color: var(--text-3); line-height: 1.5; }
.upgrade-note a { color: var(--accent); }
.upgrade-activate { margin-top: 10px; font-size: 13px; color: var(--text-2); }
.upgrade-activate a { color: var(--accent); }

/* ── Event-clip player modal (dashboard) ─────────────────────────────── */
.clip-modal {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  align-items: center;
  justify-content: center;
}
.clip-modal-scrim {
  position: absolute;
  inset: 0;
  background: rgba(2, 6, 14, 0.72);
  backdrop-filter: blur(2px);
}
.clip-modal-panel {
  position: relative;
  width: min(900px, 92vw);
  max-height: 88vh;
  background: var(--bg-1);
  border: 1px solid var(--border-1, #1c2a38);
  border-radius: 10px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.clip-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-1, #1c2a38);
}
.clip-modal-title {
  font-weight: 600;
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
}
.clip-modal-time {
  font-family: var(--font-mono, monospace);
  font-size: 11px;
  color: var(--text-3, #7d8b99);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.clip-modal-close {
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: var(--text-2, #aab6c2);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
}
.clip-modal-close:hover { color: var(--text-1, #e6edf3); }
.clip-modal-body {
  position: relative;
  background: #000;
  aspect-ratio: 16 / 9;
  display: flex;
  align-items: center;
  justify-content: center;
}
.clip-modal-video {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}
.clip-modal-msg {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--text-2, #aab6c2);
  font-size: 13px;
  pointer-events: none;
}
.clip-modal-msg button { pointer-events: auto; }

/* Per-page +1px text bump (design decision 2026-07-03): Cameras, Storage, Settings carry
   .text-plus1 on their root section; Dashboard/Recordings/Events/Logs stay as-is.
   Inline template sizes on those pages are bumped in the markup itself. */
.text-plus1 .page-sub { font-size: 11px; }
.text-plus1 .page-section-title { font-size: 11px; }
.text-plus1 .page-empty { font-size: 12px; }
.text-plus1 .page-input,
.text-plus1 .page-select,
.text-plus1 .page-textarea { font-size: 13px; }
.text-plus1 .page-label { font-size: 11px; }
.text-plus1 .page-row .name { font-size: 15px; }
.text-plus1 .page-row .sub { font-size: 12px; }
.text-plus1 .pill { font-size: 10px; }
.text-plus1 .btn-primary,
.text-plus1 .btn-secondary,
.text-plus1 .btn-ghost { font-size: 12px; }

/* ============================================================
   MOBILE SHELL (phones, ≤720px)
   The desktop shell is a fixed-height grid sized for ≥1000px: the
   header stats strip alone needs ~730px and the tab row ~780px. On
   phones the strip is dropped (its numbers live on the pages), tabs
   scroll sideways, and the dashboard stacks into one scrolling column.
   ============================================================ */
@media (max-width: 720px) {
  .app { grid-template-rows: 56px 44px auto auto 1fr; }

  /* Header: brand left, status + clock right. */
  .header { grid-template-columns: auto 1fr; padding: 0 12px; gap: 12px; }
  .header-stats { display: none; }
  .header-right { justify-self: end; gap: 12px; }
  .brand { border-right: none; padding-right: 0; gap: 10px; }
  .brand-version { display: none; }
  .clock-date { display: none; }

  /* Subnav: tab row scrolls horizontally; actions collapse to icons.
     stretch (not center): .nav-tabs relies on height:100%, which collapses
     to its auto content height under center alignment and clips the tabs. */
  /* 3 tracks like the desktop rule — the middle one is the template's empty
     spacer div; losing it wraps the action bar onto an implicit row. */
  .subnav { grid-template-columns: minmax(0, 1fr) auto auto; padding: 0 4px 0 8px; gap: 8px; align-items: stretch; }
  .action-bar { align-self: center; }
  /* Explicit height (not the desktop 100%): once the strip becomes a scroll
     container, neither the percentage nor stretch resolves against the auto
     row and the strip collapses to scrollbar height. The row itself is fixed
     at 44px by the .app grid above. */
  .nav-tabs { overflow-x: auto; scrollbar-width: none; height: 44px; }
  .nav-tabs::-webkit-scrollbar { display: none; }
  .nav-tab { padding: 0 11px; letter-spacing: 1px; flex-shrink: 0; }
  /* The strip scrolls but nothing said so — a clipped "RECOR" read as broken
     on the phone test. The right-edge fade signals more tabs off-screen. */
  .nav-tabs { mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent); -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent); }
  .action-btn.primary .btn-label { display: none; }
  .action-btn.primary { padding: 0 10px; }
  .user-chip-name { display: none; }
  .user-chip { margin-left: 0; padding: 0; border: none; background: none; }

  /* Pages: tighter gutter around the readable column. */
  .app-main.scroll { padding: 16px 12px; }

  /* Dashboard: grid + sidebar become one scrolling column. */
  .app-main { overflow-y: auto; }
  /* Plain flow, not a 1-column grid: the fixed-height grid/flex chain keeps
     collapsing .main to its meta strip during intrinsic row sizing. Block
     layout sizes .main to its content and puts the sidebar after it. */
  .dashboard { display: block; height: auto; overflow: visible; }
  .main { overflow: visible; height: auto; }
  /* flex:none — the desktop flex:1 has basis 0, so in the auto-height mobile
     column the grid contributes no height and its rows collapse to 0. */
  .camera-grid[data-count] { grid-template-columns: 1fr; grid-template-rows: none; flex: none; }
  /* Viewport-derived 16:9 height (grid width = 100vw − .main padding), NOT
     aspect-ratio: an aspect-derived height can't feed the intrinsic sizing
     of the outer .dashboard rows, which collapses .main to the meta strip. */
  .tile-cell { height: calc((100vw - 32px) * 9 / 16); }
  /* Empty layout slots are noise when stacked — keep only the leading one
     (i.e. the "add a camera" pane shown when nothing is configured yet).
     The panes are Alpine x-for siblings inserted AFTER their <template>, so
     "the first pane" is the one adjacent to the template — :first-child
     never matches (the template element itself is the first child when
     there are zero cameras). */
  .camera-grid .tile-empty-pane { display: none; }
  .camera-grid template + .tile-empty-pane { display: flex; height: calc((100vw - 32px) * 9 / 16); }
  .layout-toggle { display: none; }
  .sidebar { border-left: none; border-top: 1px solid var(--border-1); overflow: visible; }
  .panel.events { flex: none; height: 420px; }

  /* Events tab: grid + list restack into one column. The grid's fr rows
     sized against the fixed desktop height — with auto height the cards
     need their own aspect ratio or they collapse to slivers. */
  .ev-layout { grid-template-columns: 1fr; height: auto; min-height: 0; }
  .ev-grid { grid-template-rows: none; }
  .ev-grid-card { aspect-ratio: 16 / 9; }
  .events-list { max-height: 60vh; }

  /* Playback transport: the desktop 1fr|auto|1fr grid squeezed the date
     into a one-char-per-line column. Stack the three groups centered. */
  .playback-transport { grid-template-columns: 1fr; gap: 8px; justify-items: center; padding: 10px 12px; }
  .pb-date { white-space: nowrap; }
}

/* ── Storage health banner (base.html island) ─────────────────────────
   Class-based on purpose: x-show manages inline display, so the banner
   must NOT carry a dynamic :style that would overwrite it. Red = not
   recording (configured disk/share missing); amber = recording works but
   lands on the SYSTEM disk (attach a dedicated disk). */
.storage-banner {
  text-align: center;
  font-weight: 600;
  letter-spacing: 0.04em;
}
.storage-banner.error {
  background: var(--danger);
  color: #1a0008;
  padding: 8px 12px;
  font-size: 13px;
}
.storage-banner.warn {
  background: var(--warn, #b8860b);
  color: #140b00;
  padding: 6px 12px;
  font-size: 12px;
}

/* Prominent Upgrade-to-Pro CTA in the license panel — a notice-sized box
   (same visual weight as "All systems licensed"), not a thin link. It only
   FUNNELS to /upgrade; the trial itself starts there, with the full copy. */
.upgrade-cta {
  margin-top: 12px;
  padding: 12px;
  border-radius: 3px;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-size: 11px;
  line-height: 1.45;
  text-decoration: none;
  color: var(--text-2);
  background: rgba(217, 119, 6, 0.10);
  border: 1px solid rgba(217, 119, 6, 0.35);
}
.upgrade-cta:hover { background: rgba(217, 119, 6, 0.16); border-color: var(--warn); }
.upgrade-cta .ico { flex-shrink: 0; margin-top: 1px; color: var(--warn); }
.upgrade-cta strong {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  display: block;
  margin-bottom: 3px;
  color: var(--warn);
}

/* Trial-offer CTA (Community, trial unused) — benefit headline + action
   button + friction-remover microcopy, the standard trial pattern. Neutral
   panel colors, NOT warning-orange: an offer must not read as an alert.
   The button only funnels to /upgrade; the trial itself starts there. */
.trial-cta {
  margin-top: 12px;
  padding: 14px;
  border-radius: 8px;
  border: 1px solid var(--border-2);
  background: var(--bg-2);
}
.trial-cta strong {
  display: block;
  font-family: var(--font-display);
  font-size: 16px;
  letter-spacing: 0.5px;
  color: var(--text-1);
  margin-bottom: 10px;
}
.trial-btn {
  display: block;
  width: 100%;
  text-align: center;
  background: var(--accent);
  color: #fff;
  border-radius: 6px;
  padding: 9px 0;
  font-weight: 600;
  font-size: 13px;
}
.trial-btn:hover { background: var(--accent-2); }
.trial-micro {
  display: block;
  text-align: center;
  font-size: 11px;
  color: var(--text-3);
  margin-top: 8px;
}

/* Scarcity line on plan cards (Lifetime 12-month window, Founder x500) —
   deliberately louder than the muted price suffix it replaces. */
.plan-scarcity {
  display: block;
  margin: -6px 0 10px;
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--warn);
}

/* ---- Restart Calyston overlay (GPU banner + Settings → System) ---- */
.restart-overlay {
  position: fixed; inset: 0;
  background: rgba(2, 5, 9, 0.82);
  backdrop-filter: blur(4px);
  z-index: 500; /* above modals — nothing is clickable while we're down */
  display: flex;
  align-items: center;
  justify-content: center;
}
.restart-overlay-card {
  padding: 22px 34px;
  border: 1px solid var(--border-1);
  border-radius: 10px;
  background: var(--bg-1);
  color: var(--text-1);
  font-size: 15px;
}

/* ---- Events: detection-on-but-no-model explainer ---- */
.events-no-model-banner {
  margin: 0 0 12px;
  padding: 10px 14px;
  border: 1px solid var(--warn);
  border-radius: 8px;
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  color: var(--text-1);
  font-size: 13px;
  line-height: 1.5;
}
.events-no-model-banner a { color: var(--accent); }

/* ---- Camera drawer: motion decode-unhealthy warning ---- */
.motion-decode-warning {
  margin: 6px 0 0;
  padding: 8px 12px;
  border: 1px solid var(--warn);
  border-radius: 8px;
  background: color-mix(in srgb, var(--warn) 12%, transparent);
  color: var(--text-1);
  font-size: 12px;
  line-height: 1.5;
}

/* Push-notification channel rows (Settings -> Notifications). Each channel is
   a bordered block tinted by its enabled state — green delivers, red is
   paused — so a glance shows where alerts actually go. */
.push-channel {
  border: 1px solid var(--border-1);
  border-left-width: 3px;
  border-radius: 4px;
  padding: 10px 12px 12px;
  margin-top: 12px;
  transition: border-color 0.15s, background 0.15s;
}
.push-channel.on {
  border-color: var(--ok-dim);
  border-left-color: var(--ok);
  background: color-mix(in srgb, var(--ok) 7%, transparent);
}
.push-channel.off {
  border-color: var(--danger-dim);
  border-left-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 6%, transparent);
}
.push-channel-head { display: flex; align-items: center; gap: 10px; }
.push-channel-head .page-label { margin: 0; font-size: 12px; }
.push-channel-state {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 1.5px;
  cursor: pointer;
  user-select: none;
}
.push-channel.on .push-channel-state { color: var(--ok); }
.push-channel.off .push-channel-state { color: var(--danger); }
/* compact fields: these blocks stack three channels, keep them tight */
.push-channel .page-input { padding: 5px 9px; }
.push-channel .page-grid-2 { gap: 8px 12px; }

/* Small pill switch: a visually-hidden checkbox drives track + knob, so
   Alpine x-model / keyboard / tests all see a plain checkbox. */
.toggle-switch { position: relative; width: 34px; height: 18px; flex: none; }
.toggle-switch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}
.toggle-switch .track {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: var(--danger);
  transition: background 0.15s;
  pointer-events: none;
}
.toggle-switch .knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #f8fafc;
  transition: left 0.15s;
  pointer-events: none;
}
.toggle-switch input:checked ~ .track { background: var(--ok); }
.toggle-switch input:checked ~ .knob { left: 18px; }
.toggle-switch input:focus-visible ~ .track {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Bottom-of-sidebar status strip: the license verdict as a full-width
   banner, the heartbeat detail row under it. margin-top:auto pins it to the
   bottom of the (flex-column) sidebar — leftover space stays in the middle. */
.license-status-strip { padding: 14px 16px; display: flex; flex-direction: column; gap: 12px; margin-top: auto; }
.license-status-strip .license-pill.big {
  justify-content: center;
  padding: 10px 16px;
  font-size: 12px;
  letter-spacing: 4px;
}
.license-status-strip .license-pill.big .lp-dot { width: 8px; height: 8px; }

/* ---- Dashboard as a video wall on rotated phones -------------------------
   Turning a phone sideways ON THE DASHBOARD makes the camera grid take the
   whole screen in its chosen matrix (2x2/3x3/4x4) — no header, no sidebar,
   no chrome. Rotating back restores the normal page (the query stops
   matching). Scoped to coarse pointers + short viewports so desktop windows
   and tablets are never hijacked. z-index sits under modals (1000+) and the
   restart overlay, over everything else. */
@media (pointer: coarse) and (orientation: landscape) and (max-height: 620px) {
  .dashboard .camera-grid {
    position: fixed;
    inset: 0;
    z-index: 300;
    background: var(--bg-0);
    padding: 2px;
    gap: 2px;
  }
  .dashboard .tile-cell { height: auto; min-height: 0; }
  /* Empty matrix slots are dead space on a wall — hide them all. */
  .dashboard .camera-grid .tile-empty-pane,
  .dashboard .camera-grid template + .tile-empty-pane { display: none; }
  /* On a wall, state reads as a bare dot — green = live, red blink = REC.
     The text pill is chrome over the picture; offline/locked tiles keep
     labelling themselves full-frame, so their (dot-less) pills just vanish. */
  .dashboard .camera-grid .tile-pill {
    padding: 0; gap: 0; border: none; background: none;
    backdrop-filter: none; font-size: 0; letter-spacing: 0;
  }
  .dashboard .camera-grid .tile-pill .dot { width: 6px; height: 6px; }
  .dashboard .camera-grid .tile-pill.rec .dot {
    background: var(--rec);
    box-shadow: 0 0 4px var(--rec);
  }
}

/* Phone tiles are a quarter the desktop size, but the on-image overlays
   (LIVE/REC pill, bitrate, timestamp) kept their desktop dimensions and
   covered a visible slice of the picture. Shrink the chrome in proportion —
   both stacked portrait tiles and the landscape wall above. The focused
   live-page toolbar pill is off-image and keeps its own (more specific)
   sizing. */
@media (pointer: coarse) and (max-width: 720px),
       (pointer: coarse) and (orientation: landscape) and (max-height: 620px) {
  .tile-badges-tl { top: 5px; left: 5px; gap: 4px; }
  .tile-badges-tr { top: 5px; right: 5px; gap: 4px; }
  .tile-badges-br { bottom: 5px; right: 5px; gap: 4px; }
  .tile-pill { font-size: 8px; padding: 2px 5px; gap: 4px; letter-spacing: 0.8px; }
  .tile-pill .dot { width: 5px; height: 5px; }
  .tile-bitrate { font-size: 8px; padding: 1px 4px; }
  .tile-timestamp { bottom: 5px; left: 5px; font-size: 8px; }
}
