/* ============================================================================
   Technical-Light design system — portable theme layer
   ----------------------------------------------------------------------------
   A refined technical-light aesthetic: warm-neutral paper, hairline rules,
   IBM Plex type, monospace tabular numerics, status carried by colour. Built
   to layer over Bootstrap 5 via --bs-* overrides, but every rule below works
   standalone — Bootstrap is optional.

   HOW TO ADOPT
   1. Serve the three IBM Plex woff2 files (shipped in fonts/) and fix the
      @font-face url() paths below to wherever you serve them.
   2. Include this file once, globally. Add view-specific rules in a separate
      stylesheet — never edit the token block per-view.
   3. Status is colour, not iconography. Use the .s-* / .chip-* / .kv .v.*
      helpers; do not hand-pick hex values in feature CSS.
   ========================================================================= */

/* ── Vendored fonts (embedded woff2, no network/CDN fetch) ───────────────────
   Adjust these url()s to your asset route. If you cannot vendor the fonts the
   --sans / --mono fallback stacks below degrade gracefully to system fonts. */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('../fonts/ibm-plex-sans-400.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal; font-weight: 600; font-display: swap;
  src: url('../fonts/ibm-plex-sans-600.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal; font-weight: 500; font-display: swap;
  src: url('../fonts/ibm-plex-mono-500.woff2') format('woff2');
}

/* ── Design tokens ───────────────────────────────────────────────────────────
   The single source of truth. Re-theme by editing only this block. */
:root {
  /* Surfaces & ink */
  --paper:        #f4f4f1;   /* page background — warm off-white, never pure */
  --card:         #ffffff;   /* raised surfaces: cards, bars, table heads     */
  --ink:          #1b1d21;   /* primary text                                  */
  --ink-soft:     #5a6066;   /* secondary text, labels                        */
  --ink-faint:    #8b9097;   /* tertiary text, captions, units                */
  --rule:         #e4e4df;   /* hairline borders / row dividers               */
  --rule-strong:  #d2d2cb;   /* emphasised hairlines: bar underline, pills    */

  /* Accent */
  --accent:       #2f5fd0;   /* links, sort arrows, primary actions           */
  --accent-deep:  #1e3f99;   /* hover / pressed accent, raw-value emphasis     */

  /* Status — foreground */
  --ok:           #2f9e44;
  --warn:         #e8920c;
  --bad:          #e03131;
  --idle:         #868e96;

  /* Status — tinted backgrounds (pair with the matching foreground) */
  --ok-bg:        #e9f6ec;
  --warn-bg:      #fdf1dd;
  --bad-bg:       #fceaea;
  --idle-bg:      #eef0f2;

  /* Status — derived border tints (lighter than the foreground; for chips,
     pills, and tinted cards). Pair with the matching -bg above. */
  --ok-border:    #c6e6cd;
  --warn-border:  #efd6a6;
  --bad-border:   #eec3c3;
  --ok-border-soft:   #bfe3c6;  /* conn pill (slightly lighter)               */
  --warn-border-soft: #f0d9ab;  /* conn pill (slightly lighter)               */
  --bad-border-soft:  #f0c0c0;  /* conn pill (slightly lighter)               */

  /* Warning ink — a deeper amber than --warn, for chip/notice/value text that
     needs more contrast on the warm tint than the pure --warn would give. */
  --warn-ink:      #b56a00;
  --warn-ink-deep: #8a5a00;

  /* Info / accent tint — on-palette blue wash (StatusPill Info, dir-read tag) */
  --info-bg:      #e7ecfb;
  --info-border:  #cdd9f7;

  /* Neutral surface washes — derived from --paper/--accent, no own foreground */
  --zebra-bg:     #fbfbf9;   /* even-row / sticky-head fill — barely-there     */
  --hover-bg:     #f3f6fd;   /* row / rail-link hover — faint cool wash        */
  --active-bg:    #eef2fc;   /* active rail-link fill                          */

  /* Type stacks — Plex first, graceful system fallback */
  --mono: 'IBM Plex Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
  --sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Bootstrap 5 overrides — harmless if Bootstrap is absent */
  --bs-body-bg:          var(--paper);
  --bs-body-color:       var(--ink);
  --bs-body-font-family: var(--sans);
  --bs-body-font-size:   0.9rem;
  --bs-primary:          var(--accent);
  --bs-border-color:     var(--rule);
  --bs-emphasis-color:   var(--ink);
}

/* ── Base ────────────────────────────────────────────────────────────────────
   The faint top-right radial is the one deliberate flourish — a soft sheen,
   not a gradient wash. Keep it subtle. */
body {
  background:
    radial-gradient(1200px 480px at 88% -8%, var(--card) 0%, rgba(255,255,255,0) 70%),
    var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 0.9rem;
  -webkit-font-smoothing: antialiased;
}

/* Any numeric / fixed-width text. Tabular figures so columns of digits align. */
.numeric,
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-deep); text-decoration: underline; }

/* ── App chrome: top bar ─────────────────────────────────────────────────────
   One bar across the top: brand, breadcrumb crumbs, a flex spacer, then meta
   text and any status pill pushed hard right. */
.app-bar {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.85rem 1.25rem;
  background: var(--card);
  border-bottom: 1px solid var(--rule-strong);
}
.app-bar .brand {
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: 0.02em;
}
.app-bar .brand .mark { color: var(--accent); }   /* the one accent glyph     */
.app-bar .crumb { color: var(--ink-faint); font-size: 0.85rem; }
.app-bar .spacer { flex: 1; }                       /* pushes meta/pill right  */
.app-bar .meta {
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--ink-soft);
}

/* ── Connection / liveness pill ──────────────────────────────────────────────
   A rounded pill with a dot, driven entirely by data-state. Use for any
   live-link health indicator (websocket, SSE, polling). */
.conn-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  border: 1px solid var(--rule-strong);
  color: var(--ink-soft);
  background: var(--card);
}
.conn-pill .dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--idle);
}
.conn-pill[data-state="connected"]      { color: var(--ok);   border-color: var(--ok-border-soft); background: var(--ok-bg); }
.conn-pill[data-state="connected"] .dot { background: var(--ok); }
.conn-pill[data-state="connecting"]      { color: var(--warn); border-color: var(--warn-border-soft); background: var(--warn-bg); }
.conn-pill[data-state="connecting"] .dot { background: var(--warn); animation: pulse 1.1s ease-in-out infinite; }
.conn-pill[data-state="disconnected"]      { color: var(--bad); border-color: var(--bad-border-soft); background: var(--bad-bg); }
.conn-pill[data-state="disconnected"] .dot { background: var(--bad); }

@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.25; } }

/* ── Status text helpers ─────────────────────────────────────────────────────
   Recolour a value in place — counts, ratios, error totals. */
.s-ok   { color: var(--ok); }
.s-warn { color: var(--warn); }
.s-bad  { color: var(--bad); }
.s-idle { color: var(--idle); }

/* ── State chip ──────────────────────────────────────────────────────────────
   Compact rectangular badge for an enumerated state (bound/recovering/…).
   Squarer than the pill; use the pill for liveness, the chip for state. */
.chip {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.15rem 0.5rem;
  border-radius: 4px;
  border: 1px solid transparent;
}
.chip-ok   { color: var(--ok);        background: var(--ok-bg);   border-color: var(--ok-border); }
.chip-warn { color: var(--warn-ink);  background: var(--warn-bg); border-color: var(--warn-border); }
.chip-bad  { color: var(--bad);       background: var(--bad-bg);  border-color: var(--bad-border); }
.chip-idle { color: var(--idle);      background: var(--idle-bg); border-color: var(--rule-strong); }

/* ── Panel — the base raised surface ─────────────────────────────────────────
   A white card with a hairline border and 8px radius. .panel-head is the
   uppercase eyebrow label that sits on top. */
.panel {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 8px;
}
.panel-head {
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-faint);
  padding: 0.6rem 0.9rem;
  border-bottom: 1px solid var(--rule);
}

/* ── Page wrapper ────────────────────────────────────────────────────────────
   Centred, capped width, even gutter. */
.page { padding: 1.25rem; max-width: 1680px; margin: 0 auto; }

/* ── Reveal-on-paint ─────────────────────────────────────────────────────────
   Add .rise to top-level sections; stagger with inline animation-delay
   (.02s, .08s, .14s …) so panels settle in sequence, not all at once. */
@keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.rise { animation: rise 0.4s ease both; }

/* ════════════════════════════════════════════════════════════════════════════
   COMPONENT LIBRARY
   Generic, reusable pieces. View-specific layout belongs in a separate sheet.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── KPI / aggregate cards ───────────────────────────────────────────────────
   A responsive strip of headline numbers. .agg-card.alert / .caution tint the
   whole card when a watched metric goes non-zero. */
.agg-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 0.75rem;
  margin-bottom: 1rem;
}
@media (max-width: 1100px) { .agg-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px)  { .agg-grid { grid-template-columns: repeat(2, 1fr); } }

.agg-card {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: 0.7rem 0.9rem;
}
.agg-label {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-faint);
}
.agg-value {
  margin-top: 0.25rem;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.1;
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
}
.agg-sub {                       /* trailing "/ 54", "ms" etc. — quieter */
  font-size: 0.85rem;
  font-weight: 400;
  color: var(--ink-faint);
}
.agg-card.alert   { border-color: var(--bad-border); background: var(--bad-bg); }
.agg-card.alert   .agg-value { color: var(--bad); }
.agg-card.caution { border-color: var(--warn-border); background: var(--warn-bg); }
.agg-card.caution .agg-value { color: var(--warn-ink); }

/* ── Metric card + key/value rows ────────────────────────────────────────────
   A .panel-head over a stack of .kv rows: label left, monospace value right.
   Zebra striping on even rows. .v.warn / .v.bad / .v.ok recolour a value. */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 0.85rem;
  margin-bottom: 1rem;
}
.metric-card {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 8px;
  overflow: hidden;
}
.metric-card .panel-head { margin: 0; }

.kv {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding: 0.32rem 0.9rem;
  font-size: 0.85rem;
}
.kv:nth-child(even) { background: var(--zebra-bg); }
.kv .k { color: var(--ink-soft); }
.kv .v {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.kv .v.warn { color: var(--warn); }
.kv .v.bad  { color: var(--bad); }
.kv .v.ok   { color: var(--ok); }

/* ── Toolbar ─────────────────────────────────────────────────────────────────
   Filter/search row that sits inside a .panel above a table. */
.toolbar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.9rem;
  border-bottom: 1px solid var(--rule);
}
.toolbar .spacer { flex: 1; }
.tb-search { max-width: 280px; }
.tb-state  { max-width: 150px; }
.tb-check {
  display: flex; align-items: center; gap: 0.35rem;
  font-size: 0.82rem; color: var(--ink-soft); white-space: nowrap;
  user-select: none;
}
.tb-count { font-family: var(--mono); font-size: 0.78rem; color: var(--ink-faint); }

/* ── Data table ──────────────────────────────────────────────────────────────
   Dense, hairline-ruled table. Uppercase sticky head on a faint fill; numeric
   columns get .num (right-aligned, monospace). Rows are clickable by default —
   drop the cursor/hover rules if yours are not. */
.table-wrap { overflow-x: auto; }

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}
.data-table th,
.data-table td {
  padding: 0.45rem 0.8rem;
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--rule);
}
.data-table th {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
  background: var(--zebra-bg);
  position: sticky;
  top: 0;
}
.data-table th.num,
.data-table td.num { text-align: right; font-family: var(--mono); }

.data-table th.sortable { cursor: pointer; user-select: none; }
.data-table th.sortable:hover { color: var(--ink); }
.data-table th.sorted-asc::after  { content: ' \2191'; color: var(--accent); }
.data-table th.sorted-desc::after { content: ' \2193'; color: var(--accent); }

.data-table tbody tr { cursor: pointer; transition: background 0.08s; }
.data-table tbody tr:hover { background: var(--hover-bg); }
.data-table tbody tr:last-child td { border-bottom: none; }

.empty-row {
  text-align: center !important;
  color: var(--ink-faint);
  padding: 1.6rem !important;
  font-style: italic;
}

/* ── Direction / category tag ────────────────────────────────────────────────
   Tiny inline tag for a per-row category (e.g. read vs write). */
.dir-tag {
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.1rem 0.4rem;
  border-radius: 3px;
}
.dir-read  { color: var(--accent-deep);  background: var(--info-bg); }
.dir-write { color: var(--warn-ink-deep); background: var(--warn-bg); }

/* ── Inline notice ───────────────────────────────────────────────────────────
   A .panel with a warning tint — for "this thing is gone / degraded" banners. */
.notice {
  padding: 0.85rem 1.1rem;
  margin-bottom: 1rem;
  color: var(--warn-ink);
  background: var(--warn-bg);
  border-color: var(--warn-border);
}
