/* ============================================================================
   Clearview "Console" — Dashboard
   ----------------------------------------------------------------------------
   Requires styles.css (tokens) + clearview-refresh.css + media.css (app shell).
   Namespaced `cvd-`. Ported from UI Clearview/css/dashboard.css.

   THE DIAGNOSIS
   The old dashboard scored a "control room" impression by piling on controls:
   8 stat tiles, a 3-tab chart, a paginated OBS sidebar, a licence banner, and
   three quick-action buttons. What it did NOT do is answer the only question an
   operator has during a show: is the show OK?

   THE RESPONSE
   1. A FLEET-STATE HERO that names the show state in one sentence and surfaces
      machines needing attention BY NAME, not by page number.
   2. Two charts, side by side, no tabs — watched together because they are
      watched together.
   3. An ALWAYS-VISIBLE activity tail, one line per event.
   4. A COMPACT FLEET GRID sorted attention-first so trouble surfaces without
      hunting. No pagination.
   ============================================================================ */

/* ==================================================================== hero
   Fleet health in one row. The number the operator watches is "how many are
   live". Everything else (recording / streaming / transfers) is context. */
.cvd-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--cv-space-3);
  align-items: stretch;
  padding: var(--cv-space-3) var(--cv-space-4);
  border: 1px solid var(--cv-border);
  border-radius: var(--cv-radius-lg);
  background: var(--cv-bg-surface);
}
/* Show-critical state (offline machines, errors) lifts the border to danger,
   so the whole panel reads as "attend to me" without moving the eye. */
.cvd-hero[data-state="attn"]  { border-color: var(--cv-warning-edge); background: linear-gradient(180deg, var(--cv-warning-wash), transparent 40%); }
.cvd-hero[data-state="down"]  { border-color: var(--cv-danger-edge);  background: linear-gradient(180deg, var(--cv-danger-wash),  transparent 40%); }
.cvd-hero[data-state="clear"] { border-color: var(--cv-success-edge); }

.cvd-hero-left  { display: grid; gap: var(--cv-space-2); min-width: 0; }
.cvd-hero-right { display: grid; gap: var(--cv-space-2); align-content: start; justify-items: end; }

/* The show sentence. Big, plain-language, so a glance answers the question. */
.cvd-hero-sentence {
  display: flex; align-items: baseline; gap: var(--cv-space-3); flex-wrap: wrap;
  font-size: var(--cv-text-lg);
  line-height: 1.15;
}
.cvd-hero-sentence b {
  font-family: var(--cv-font-mono); font-variant-numeric: tabular-nums;
  font-weight: var(--cv-weight-semibold);
  font-size: var(--cv-text-2xl);
  color: var(--cv-text);
}
.cvd-hero-sentence .cvd-sep    { color: var(--cv-text-disabled); }
.cvd-hero-sentence .cvd-c-live { color: var(--cv-accent); }
.cvd-hero-sentence .cvd-c-rec  { color: var(--cv-danger); }
.cvd-hero-sentence .cvd-c-strm { color: var(--cv-warning); }
.cvd-hero-sentence .cvd-c-attn { color: var(--cv-warning); }
.cvd-hero-sentence .cvd-c-down { color: var(--cv-danger); }

/* Machines needing attention, INLINE. If there are none, the row does not
   render — an empty attention row is louder than no row at all. */
.cvd-attn {
  display: flex; align-items: center; gap: var(--cv-space-2);
  flex-wrap: wrap;
  font-size: var(--cv-text-xs);
  color: var(--cv-text-secondary);
}
.cvd-attn-label {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--cv-warning);
  font-weight: var(--cv-weight-medium);
}
.cvd-attn[data-severity="down"] .cvd-attn-label { color: var(--cv-danger); }
.cvd-attn-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px var(--cv-space-2);
  border: 1px solid var(--cv-border);
  border-radius: var(--cv-radius-full);
  background: var(--cv-bg-raised);
  font-family: var(--cv-font-mono); font-size: 10px;
  /* Mono text at 10px is already tight; --cv-text-secondary drops it below AA
     on the light raised surface. The chip is data (a machine name the operator
     is about to click) — full text contrast. */
  color: var(--cv-text);
  cursor: pointer;
  transition: border-color var(--cv-dur-fast) var(--cv-ease), background var(--cv-dur-fast) var(--cv-ease);
}
.cvd-attn-chip:hover { border-color: var(--cv-border-strong); background: var(--cv-bg-hover); }
.cvd-attn-chip[data-s="down"]  { border-color: var(--cv-danger-edge); }
.cvd-attn-chip[data-s="down"]  .cvd-attn-dot { background: var(--cv-danger); }
.cvd-attn-chip[data-s="error"] { border-color: var(--cv-danger-edge); }
.cvd-attn-chip[data-s="error"] .cvd-attn-dot { background: var(--cv-danger); }
.cvd-attn-chip[data-s="stale"] { border-color: var(--cv-warning-edge); }
.cvd-attn-chip[data-s="stale"] .cvd-attn-dot { background: var(--cv-warning); }
.cvd-attn-dot {
  width: 6px; height: 6px; border-radius: var(--cv-radius-full);
  background: var(--cv-text-disabled);
}
.cvd-attn-more {
  padding: 2px var(--cv-space-2);
  font-size: 10px; color: var(--cv-text-muted);
}

/* Secondary metrics on the right — CPU / Memory / Transfers. These matter
   less than fleet state, so they sit smaller and off to the side. */
.cvd-hero-secondary { display: flex; gap: var(--cv-space-4); }
.cvd-mini {
  display: grid; gap: 2px; justify-items: end;
  min-width: 78px;
}
.cvd-mini-label {
  font-size: 9px; font-weight: var(--cv-weight-semibold);
  letter-spacing: var(--cv-tracking-caps); text-transform: uppercase;
  color: var(--cv-text-muted);
}
.cvd-mini-value {
  font-family: var(--cv-font-mono); font-variant-numeric: tabular-nums;
  font-size: var(--cv-text-lg); font-weight: var(--cv-weight-semibold);
  color: var(--cv-text);
}
.cvd-mini-bar {
  width: 78px; height: 3px; border-radius: var(--cv-radius-full);
  background: var(--cv-bg-active); overflow: hidden;
}
.cvd-mini-bar i {
  display: block; height: 100%; background: var(--cv-accent);
  transition: width var(--cv-dur) var(--cv-ease), background var(--cv-dur-fast) var(--cv-ease);
}
.cvd-mini[data-state="high"] .cvd-mini-bar i { background: var(--cv-warning); }
.cvd-mini[data-state="high"] .cvd-mini-value { color: var(--cv-warning); }
.cvd-mini[data-state="over"] .cvd-mini-bar i { background: var(--cv-danger); }
.cvd-mini[data-state="over"] .cvd-mini-value { color: var(--cv-danger); }

/* ================================================================= charts
   Two charts, side by side. The old build tabbed between them AND the activity
   log — so the operator watched ONE thing at a time. During a show they watch
   all three. */
.cvd-charts {
  display: grid; gap: var(--cv-space-3);
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  /* Otherwise grid row-syncing stretches both cards to match the taller one,
     and if the canvas ever grows the JS reads the larger clientHeight and
     the chart redraws to fill it — the growth compounds on every tick. */
  align-items: start;
}
.cvd-chart {
  display: grid;
  /* auto + auto (not 1fr). 1fr let the canvas stretch to fill whatever height
     the outer grid gave the card; combined with the JS reading clientHeight
     that turns into an unbounded feedback loop under grid row-syncing. */
  grid-template-rows: auto auto;
  padding: var(--cv-space-3);
  border: 1px solid var(--cv-border); border-radius: var(--cv-radius-lg);
  background: var(--cv-bg-surface);
}
.cvd-chart-head {
  display: flex; align-items: center; gap: var(--cv-space-3);
  margin-bottom: var(--cv-space-2);
  flex-wrap: wrap;
}
.cvd-chart-title {
  font-size: var(--cv-text-xs); font-weight: var(--cv-weight-semibold);
  color: var(--cv-text);
}
.cvd-chart-legend {
  display: flex; align-items: center; gap: var(--cv-space-3); flex-wrap: wrap;
  /* 10px labels beside big count values — --cv-text-muted lands at 4.5:1
     exactly, which rounds down under one edge case. */
  font-size: 10px; color: var(--cv-text-secondary);
}
.cvd-chart-legend b {
  font-family: var(--cv-font-mono); font-variant-numeric: tabular-nums;
  font-weight: var(--cv-weight-semibold);
  color: var(--cv-text);
  margin-left: 4px;
}
.cvd-chart-dot {
  width: 8px; height: 8px; border-radius: 2px;
  display: inline-block; margin-right: 4px; vertical-align: middle;
}
.cvd-chart-canvas {
  position: relative;
  /* Fixed height, not min-height. The JS reads clientHeight to size the canvas
     buffer, so any growth here is amplified into a bigger draw next tick. */
  height: 200px;
  /* During a live resize the JS sets canvas.style.width from the wrap width,
     but there is a frame gap between the wrap shrinking and the resize event
     firing — enough time for the canvas to visibly bleed past the card and
     over the sibling. Clip it. */
  overflow: hidden;
}
/* Cap the canvas at its wrap size so it also cannot push the grid track wider
   than its 1fr share on the way DOWN. A grid track will grow to fit oversized
   content and the flex on the container above will let it eat its neighbour. */
.cvd-chart-canvas > canvas {
  display: block;
  max-width: 100%;
  max-height: 100%;
}

/* =================================================================== log
   Always-visible activity tail. The old build hid this behind a tab named
   "Activity". Hidden by default, in a monitoring surface, is the wrong
   default. */
.cvd-log {
  display: grid; gap: 0;
  padding: 0;
  border: 1px solid var(--cv-border); border-radius: var(--cv-radius-lg);
  background: var(--cv-bg-surface);
  overflow: hidden;
}
.cvd-log-head {
  display: flex; align-items: center; gap: var(--cv-space-2);
  padding: var(--cv-space-2) var(--cv-space-3);
  border-bottom: 1px solid var(--cv-border-subtle);
  background: var(--cv-bg-surface);
}
.cvd-log-title {
  font-size: 9px; font-weight: var(--cv-weight-semibold);
  letter-spacing: var(--cv-tracking-caps); text-transform: uppercase;
  color: var(--cv-text-muted);
}
.cvd-log-body {
  max-height: 260px; overflow-y: auto;
  padding: var(--cv-space-2);
}
.cvd-log-line {
  display: grid;
  grid-template-columns: 68px 46px 100px minmax(0, 1fr);
  gap: var(--cv-space-2); align-items: center;
  padding: 2px var(--cv-space-2);
  font-family: var(--cv-font-mono); font-size: 10px; line-height: 1.6;
  border-radius: var(--cv-radius-sm);
}
.cvd-log-line:hover { background: var(--cv-bg-hover); }
/* --cv-text-disabled measures 2.5:1 on the surface, which fails AA. The
   timestamp is data, not chrome. */
.cvd-log-t { color: var(--cv-text-muted); font-variant-numeric: tabular-nums; }
.cvd-log-l {
  padding: 0 4px; border-radius: 2px;
  font-size: 9px; font-weight: var(--cv-weight-semibold);
  letter-spacing: var(--cv-tracking-caps); text-transform: uppercase;
  text-align: center;
  background: var(--cv-bg-raised); color: var(--cv-text-muted);
}
.cvd-log-line[data-l="error"] .cvd-log-l   { background: var(--cv-danger-wash);  color: var(--cv-danger); }
.cvd-log-line[data-l="warning"] .cvd-log-l { background: var(--cv-warning-wash); color: var(--cv-warning); }
.cvd-log-line[data-l="warn"] .cvd-log-l    { background: var(--cv-warning-wash); color: var(--cv-warning); }
.cvd-log-line[data-l="success"] .cvd-log-l { background: var(--cv-success-wash); color: var(--cv-success); }
.cvd-log-line[data-l="info"] .cvd-log-l    { background: var(--cv-info-wash);    color: var(--cv-info); }
.cvd-log-m { color: var(--cv-text-secondary); overflow-wrap: anywhere; }
.cvd-log-mod {
  color: var(--cv-text-muted);
  font-family: inherit;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ================================================================== fleet
   Every machine, small, laid out on a grid. Trouble sorts to the top so an
   offline machine on "page 8" cannot hide. The old build hid trouble behind
   pagination. */
.cvd-fleet {
  border: 1px solid var(--cv-border); border-radius: var(--cv-radius-lg);
  background: var(--cv-bg-surface); overflow: hidden;
}
.cvd-fleet-head {
  display: flex; align-items: center; gap: var(--cv-space-2);
  padding: var(--cv-space-2) var(--cv-space-3);
  border-bottom: 1px solid var(--cv-border);
}
.cvd-fleet-title {
  font-size: var(--cv-text-xs); font-weight: var(--cv-weight-semibold);
}
.cvd-fleet-body {
  display: grid; gap: 2px;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  padding: var(--cv-space-2);
  max-height: 340px; overflow-y: auto;
}

.cvd-tile {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr) auto;
  gap: var(--cv-space-2); align-items: center;
  padding: 4px var(--cv-space-2);
  border-radius: var(--cv-radius);
  cursor: pointer;
  transition: background var(--cv-dur-fast) var(--cv-ease);
}
.cvd-tile:hover { background: var(--cv-bg-hover); }
.cvd-tile-dot {
  width: 8px; height: 8px; border-radius: var(--cv-radius-full);
  background: var(--cv-text-disabled);
}
.cvd-tile-name {
  font-family: var(--cv-font-mono); font-size: 10px;
  color: var(--cv-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cvd-tile-flags { display: flex; gap: 2px; }
.cvd-tile-flag {
  width: 12px; height: 12px; display: grid; place-items: center;
  font-family: var(--cv-font-mono); font-size: 8px; font-weight: var(--cv-weight-semibold);
  border-radius: 2px;
  background: var(--cv-bg-raised); color: var(--cv-text-disabled);
}
.cvd-tile-flag[data-on="true"][data-t="rec"]    { background: var(--cv-danger);  color: var(--cv-on-danger); }
.cvd-tile-flag[data-on="true"][data-t="stream"] { background: var(--cv-warning); color: var(--cv-on-warning); }

/* Status colour on the whole tile, not just the dot — a red dot in a sea of
   black text is invisible at glance. The BACKGROUND says "attend". */
.cvd-tile[data-s="live"] .cvd-tile-dot   { background: var(--cv-accent); }
.cvd-tile[data-s="rec"]  .cvd-tile-dot   { background: var(--cv-danger); }
.cvd-tile[data-s="stream"] .cvd-tile-dot { background: var(--cv-warning); }
.cvd-tile[data-s="both"]   .cvd-tile-dot { background: var(--cv-danger); box-shadow: 0 0 0 2px var(--cv-warning-edge); }
.cvd-tile[data-s="down"], .cvd-tile[data-s="error"] {
  background: var(--cv-danger-wash);
  box-shadow: inset 3px 0 0 var(--cv-danger);
}
.cvd-tile[data-s="down"] .cvd-tile-dot,
.cvd-tile[data-s="error"] .cvd-tile-dot   { background: var(--cv-danger); }
.cvd-tile[data-s="stale"] {
  background: var(--cv-warning-wash);
  box-shadow: inset 3px 0 0 var(--cv-warning);
}
.cvd-tile[data-s="stale"] .cvd-tile-dot  { background: var(--cv-warning); }

/* A dot pulse only on recording machines. Pulsing everything reads as noise
   and the operator learns to filter it out. */
@keyframes cvd-pulse-rec {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}
.cvd-tile[data-s="rec"] .cvd-tile-dot,
.cvd-tile[data-s="both"] .cvd-tile-dot {
  animation: cvd-pulse-rec 1.6s var(--cv-ease) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .cvd-tile-dot { animation: none !important; }
}

/* Legend footer — one line, small. */
.cvd-fleet-legend {
  display: flex; align-items: center; gap: var(--cv-space-3); flex-wrap: wrap;
  padding: var(--cv-space-2) var(--cv-space-3);
  border-top: 1px solid var(--cv-border-subtle);
  background: var(--cv-bg-raised);
  /* On the raised background --cv-text-muted drops to 4.25:1 in the dark
     theme — under AA for 10px text. The legend is content, not decoration. */
  font-size: 10px; color: var(--cv-text-secondary);
}
.cvd-fleet-legend > span { display: inline-flex; align-items: center; gap: 4px; }

/* ================================================================ licence
   Compact — the old banner was a four-column mini-page for compliance text
   the operator does not read during a show. Preserved but flattened. */
.cvd-licence {
  display: flex; align-items: center; gap: var(--cv-space-3);
  padding: var(--cv-space-2) var(--cv-space-3);
  border: 1px solid var(--cv-border); border-radius: var(--cv-radius);
  background: var(--cv-bg-raised);
  font-size: var(--cv-text-2xs); color: var(--cv-text-muted);
  flex-wrap: wrap;
}
.cvd-licence b { color: var(--cv-text); font-weight: var(--cv-weight-medium); }
.cvd-licence a {
  font-family: var(--cv-font-mono);
  color: var(--cv-accent); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 260px;
}
.cvd-licence a:hover { text-decoration: underline; }
.cvd-licence-days {
  padding: 1px var(--cv-space-2); border-radius: var(--cv-radius-sm);
  font-family: var(--cv-font-mono); font-variant-numeric: tabular-nums;
  font-weight: var(--cv-weight-semibold);
  background: var(--cv-success-wash); color: var(--cv-success);
  font-size: var(--cv-text-2xs);
  border: 1px solid var(--cv-success-edge);
}
.cvd-licence-days[data-state="warn"] { background: var(--cv-warning-wash); color: var(--cv-warning); border-color: var(--cv-warning-edge); }
.cvd-licence-days[data-state="over"] { background: var(--cv-danger-wash);  color: var(--cv-danger); border-color: var(--cv-danger-edge); }

/* ================================================================= layout
   The page grid. Nothing overlaps, nothing is behind a tab. */
.cvd-page {
  display: grid; gap: var(--cv-space-3);
  min-width: 0;
}

/* Below 720px the hero secondary metrics wrap under the sentence, and the
   fleet body tightens. */
@media (max-width: 720px) {
  .cvd-hero { grid-template-columns: minmax(0, 1fr); }
  .cvd-hero-right { justify-items: start; }
  .cvd-fleet-body { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
  .cvd-log-line { grid-template-columns: 54px 40px minmax(0, 1fr); }
  .cvd-log-mod { display: none; }
}
