/* ---------------------------------------------------------------------------
   Uptime — stylesheet

   Colour is defined once, as tokens on :root, and redefined in exactly two
   places: a prefers-color-scheme block for the OS setting, and a [data-theme]
   block so the toggle can override the OS in both directions. Nothing below
   those blocks ever names a raw colour.

   The status palette (good / warning / serious / critical) is deliberately NOT
   themed. Those four hexes clear 3:1 on both surfaces, and a status colour that
   shifted between themes would be a status colour you cannot learn.
--------------------------------------------------------------------------- */

:root {
  color-scheme: light;

  --page:        #f9f9f7;
  --surface:     #fcfcfb;
  --surface-2:   #f2f1ed;
  --ink:         #0b0b0b;
  --ink-2:       #52514e;
  --muted:       #898781;
  --grid:        #e1e0d9;
  --baseline:    #c3c2b7;
  --border:      rgba(11, 11, 11, 0.10);
  --border-firm: rgba(11, 11, 11, 0.16);

  --accent:      #2a78d6;
  --accent-ink:  #ffffff;
  --accent-wash: rgba(42, 120, 214, 0.10);

  --good:      #0ca30c;
  --warning:   #fab219;
  --serious:   #ec835a;
  --critical:  #d03b3b;
  --neutral:   #c3c2b7;

  --shadow: 0 1px 2px rgba(11, 11, 11, 0.05), 0 8px 24px rgba(11, 11, 11, 0.06);

  /* The four glows of the page backdrop: the accent blue, a green kept well
     away from --good, slate and sand. Faint on purpose, so a status colour is
     still the only strong colour on the page. */
  --glow-a:    rgba(42, 120, 214, 0.13);
  --glow-b:    rgba(70, 160, 110, 0.11);
  --glow-c:    rgba(120, 120, 176, 0.12);
  --glow-d:    rgba(214, 170, 100, 0.13);

  --radius: 10px;
  --radius-sm: 6px;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --page:        #0d0d0d;
    --surface:     #1a1a19;
    --surface-2:   #232322;
    --ink:         #ffffff;
    --ink-2:       #c3c2b7;
    --muted:       #898781;
    --grid:        #2c2c2a;
    --baseline:    #383835;
    --border:      rgba(255, 255, 255, 0.10);
    --border-firm: rgba(255, 255, 255, 0.18);
    --accent:      #3987e5;
    --accent-wash: rgba(57, 135, 229, 0.14);
    --neutral:     #383835;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
    --glow-a:    rgba(40, 96, 196, 0.24);
    --glow-b:    rgba(22, 112, 56, 0.18);
    --glow-c:    rgba(82, 74, 152, 0.20);
    --glow-d:    rgba(142, 100, 40, 0.15);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --page:        #0d0d0d;
  --surface:     #1a1a19;
  --surface-2:   #232322;
  --ink:         #ffffff;
  --ink-2:       #c3c2b7;
  --muted:       #898781;
  --grid:        #2c2c2a;
  --baseline:    #383835;
  --border:      rgba(255, 255, 255, 0.10);
  --border-firm: rgba(255, 255, 255, 0.18);
  --accent:      #3987e5;
  --accent-wash: rgba(57, 135, 229, 0.14);
  --neutral:     #383835;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.35);
  --glow-a:    rgba(40, 96, 196, 0.24);
  --glow-b:    rgba(22, 112, 56, 0.18);
  --glow-c:    rgba(82, 74, 152, 0.20);
  --glow-d:    rgba(142, 100, 40, 0.15);
}

* { box-sizing: border-box; }

/* The `hidden` attribute is only enforced by the user-agent stylesheet, as
   [hidden] { display: none } -- and ANY author display declaration outranks it.
   `.modal-backdrop { display: grid }` below silently defeated it, leaving the
   dialog on screen from page load with nothing in it and an X that appeared to
   do nothing (it was setting .hidden correctly; the CSS was ignoring it).
   Declaring it here at author level, with !important, means `el.hidden = true`
   wins for every element no matter how it is otherwise styled. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; background: var(--page); }

body {
  margin: 0;
  color: var(--ink);
  font: 14px/1.5 var(--font);
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }

.wrap { width: 100%; max-width: 1100px; margin: 0 auto; padding: 0 20px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface); color: var(--ink); padding: 10px 14px; border-radius: var(--radius-sm);
}
.skip:focus { left: 12px; top: 12px; }

/* --- backdrop -------------------------------------------------------------- */

/* Behind every page: the page colour with four wide, faint glows on it, one
   towards each corner, on two layers that drift slowly against each other
   while the second also fades a little in and out. Each layer is painted once
   and then only moved and faded (transform, opacity), so it costs the page no
   layout or repaint; both are bigger than the screen by more than they ever
   move, so no edge shows. The page colour is on the root, not on <body>: a
   background on <body> would paint over both layers. */
:root {
  /* How each glow falls away from its centre to nothing: many stops on a curve
     that is level at both ends (3r² - 2r³), so no ring or edge can be picked out. */
  --fall-a: var(--glow-a), color-mix(in srgb, var(--glow-a) 94%, transparent) 15%, color-mix(in srgb, var(--glow-a) 78%, transparent) 30%, color-mix(in srgb, var(--glow-a) 57%, transparent) 45%, color-mix(in srgb, var(--glow-a) 35%, transparent) 60%, color-mix(in srgb, var(--glow-a) 16%, transparent) 75%, color-mix(in srgb, var(--glow-a) 3%, transparent) 90%, transparent;
  --fall-b: var(--glow-b), color-mix(in srgb, var(--glow-b) 94%, transparent) 15%, color-mix(in srgb, var(--glow-b) 78%, transparent) 30%, color-mix(in srgb, var(--glow-b) 57%, transparent) 45%, color-mix(in srgb, var(--glow-b) 35%, transparent) 60%, color-mix(in srgb, var(--glow-b) 16%, transparent) 75%, color-mix(in srgb, var(--glow-b) 3%, transparent) 90%, transparent;
  --fall-c: var(--glow-c), color-mix(in srgb, var(--glow-c) 94%, transparent) 15%, color-mix(in srgb, var(--glow-c) 78%, transparent) 30%, color-mix(in srgb, var(--glow-c) 57%, transparent) 45%, color-mix(in srgb, var(--glow-c) 35%, transparent) 60%, color-mix(in srgb, var(--glow-c) 16%, transparent) 75%, color-mix(in srgb, var(--glow-c) 3%, transparent) 90%, transparent;
  --fall-d: var(--glow-d), color-mix(in srgb, var(--glow-d) 94%, transparent) 15%, color-mix(in srgb, var(--glow-d) 78%, transparent) 30%, color-mix(in srgb, var(--glow-d) 57%, transparent) 45%, color-mix(in srgb, var(--glow-d) 35%, transparent) 60%, color-mix(in srgb, var(--glow-d) 16%, transparent) 75%, color-mix(in srgb, var(--glow-d) 3%, transparent) 90%, transparent;
}
body::before, body::after { content: ""; position: fixed; z-index: -1; inset: -18%; pointer-events: none; will-change: transform, opacity; }
body::before {
  background:
    radial-gradient(ellipse 58% 56% at 18% 20%, var(--fall-a)),
    radial-gradient(ellipse 52% 50% at 84% 84%, var(--fall-d)),
    var(--page);
  animation: drift-a 47s ease-in-out infinite alternate;
}
body::after {
  background:
    radial-gradient(ellipse 52% 52% at 84% 16%, var(--fall-b)),
    radial-gradient(ellipse 56% 50% at 18% 88%, var(--fall-c));
  animation: drift-b 61s ease-in-out infinite alternate, glow 29s ease-in-out infinite alternate;
}
@keyframes drift-a { from { transform: translate3d(-4%, -3%, 0) rotate(-3deg); } to { transform: translate3d(4%, 3%, 0) rotate(3deg); } }
@keyframes drift-b { from { transform: translate3d(4%, -3%, 0) rotate(3deg); } to { transform: translate3d(-4%, 4%, 0) rotate(-3deg); } }
@keyframes glow { from { opacity: 1; } to { opacity: .55; } }
/* With reduced motion asked for, nothing drifts; the second layer only fades, slowly. */
@media (prefers-reduced-motion: reduce) {
  body::before { animation: none; }
  body::after { animation: glow 29s ease-in-out infinite alternate; }
}

/* --- top bar -------------------------------------------------------------- */

.topbar {
  position: sticky; top: 0; z-index: 30;
  border-bottom: 1px solid var(--border);
  transition: background-color 150ms ease;
}
/* At the top of the page the bar is clear, so the backdrop runs unbroken
   behind it. Once the page has moved under it (app.js marks it), it is
   frosted glass over whatever is there. */
.topbar.over {
  background: color-mix(in srgb, var(--page) 88%, transparent);
  backdrop-filter: blur(10px);
}
.topbar-inner { display: flex; align-items: center; gap: 24px; height: 56px; }

.brand { display: flex; align-items: center; gap: 9px; color: var(--ink); font-weight: 600; }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 10px; height: 18px; border-radius: 3px;
  background: var(--good);
  box-shadow: 14px 0 0 -1px var(--good), 28px 0 0 -3px var(--good);
  margin-right: 26px;
}
.brand-name { letter-spacing: -0.01em; }

.topnav { display: flex; gap: 4px; margin-left: auto; }
.topnav a {
  color: var(--ink-2); padding: 6px 10px; border-radius: var(--radius-sm); font-weight: 500;
}
.topnav a:hover { background: var(--surface-2); text-decoration: none; color: var(--ink); }
.topnav a[aria-current="page"] { background: var(--surface-2); color: var(--ink); }

.topbar-tools { display: flex; align-items: center; gap: 8px; }

.live { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 12px; }
.live-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--good);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--good) 60%, transparent);
}
.live[data-state="live"] .live-dot { animation: pulse 2.4s ease-out infinite; }
.live[data-state="offline"] .live-dot { background: var(--muted); animation: none; }
.live[data-state="offline"] .live-text::after { content: " — reconnecting"; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--good) 55%, transparent); }
  70%  { box-shadow: 0 0 0 6px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .live[data-state="live"] .live-dot { animation: none; }
}

/* --- buttons -------------------------------------------------------------- */

.button, .icon-button {
  font: inherit; font-weight: 500; cursor: pointer;
  border: 1px solid var(--border-firm); background: var(--surface); color: var(--ink);
  border-radius: var(--radius-sm); padding: 7px 12px;
  transition: background 120ms ease, border-color 120ms ease;
}
.button:hover, .icon-button:hover { background: var(--surface-2); }
.button:active { transform: translateY(0.5px); }
.button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.button.primary:hover { background: color-mix(in srgb, var(--accent) 88%, black); }
.button.danger { color: var(--critical); border-color: color-mix(in srgb, var(--critical) 40%, var(--border-firm)); }
.button.danger:hover { background: color-mix(in srgb, var(--critical) 10%, var(--surface)); }
.button.small { padding: 4px 9px; font-size: 12.5px; }
.button:disabled { opacity: 0.5; cursor: not-allowed; }

.icon-button {
  display: inline-grid; place-items: center; width: 32px; height: 32px; padding: 0;
  color: var(--ink-2);
}

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* --- hero ----------------------------------------------------------------- */

.hero {
  display: flex; align-items: center; gap: 16px;
  padding: 30px 0 22px;
}
.hero-badge {
  flex: none; width: 40px; height: 40px; border-radius: 12px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--hero-color) 14%, var(--surface));
  color: var(--hero-color);
  border: 1px solid color-mix(in srgb, var(--hero-color) 30%, transparent);
}
.hero[data-level="good"]     { --hero-color: var(--good); }
.hero[data-level="warning"]  { --hero-color: var(--warning); }
.hero[data-level="serious"]  { --hero-color: var(--serious); }
.hero[data-level="critical"] { --hero-color: var(--critical); }
.hero[data-level="none"]     { --hero-color: var(--muted); }

.hero-text h1 { font-size: 26px; line-height: 1.25; }
.hero-sub { color: var(--ink-2); margin-top: 3px; font-size: 13.5px; }

/* --- controls row --------------------------------------------------------- */

.controls {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding-bottom: 14px;
}
.segmented {
  display: inline-flex; background: var(--surface-2); border-radius: var(--radius-sm);
  padding: 2px; gap: 2px; border: 1px solid var(--border);
}
.segmented button {
  font: inherit; font-size: 12.5px; font-weight: 500; cursor: pointer;
  border: 0; background: transparent; color: var(--ink-2);
  padding: 4px 10px; border-radius: 4px;
}
.segmented button:hover { color: var(--ink); }
.segmented button[aria-pressed="true"] {
  background: var(--surface); color: var(--ink); box-shadow: var(--shadow);
}

.search {
  flex: 1 1 180px; max-width: 260px;
  font: inherit; padding: 6px 10px;
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
}
.search::placeholder { color: var(--muted); }
.controls .spacer { flex: 1 1 auto; }

/* --- monitor list --------------------------------------------------------- */

.group { margin-bottom: 26px; }
.group-head {
  display: flex; align-items: baseline; gap: 10px;
  padding: 0 0 8px 2px;
}
.group-head h2 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--muted); }
.group-head .group-meta { font-size: 12px; color: var(--muted); margin-left: auto; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

/* The row is a grid so every timeline in the table starts at the same x, which
   is what lets a single shared time axis sit above them all. */
.row {
  display: grid;
  grid-template-columns: minmax(180px, 1.1fr) 76px minmax(220px, 2.4fr) 68px;
  align-items: center;
  gap: 16px;
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  cursor: pointer;
  transition: background 100ms ease;
}
.row:first-child { border-top: 0; }
.row:hover { background: var(--surface-2); }

.axis-row {
  display: grid;
  grid-template-columns: minmax(180px, 1.1fr) 76px minmax(220px, 2.4fr) 68px;
  gap: 16px;
  padding: 0 16px 6px;
  font-size: 11.5px; color: var(--muted);
}
.axis-row .axis-line { grid-column: 3; display: flex; justify-content: space-between; }

.row-name { min-width: 0; display: flex; align-items: center; gap: 9px; }
.row-name .dot { flex: none; }
.row-name-text { min-width: 0; }
.row-title {
  font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.row-target {
  font-size: 12px; color: var(--muted); font-family: var(--mono);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--neutral); }
.dot[data-status="up"] { background: var(--good); }
.dot[data-status="down"] { background: var(--critical); }
.dot[data-status="degraded"] { background: var(--warning); }
.dot[data-status="paused"], .dot[data-status="disabled"] { background: var(--muted); }
.dot[data-status="pending"] { background: var(--neutral); }

.row-uptime { font-variant-numeric: tabular-nums; font-size: 13px; color: var(--ink-2); text-align: right; }
.row-uptime .unit { color: var(--muted); font-size: 11px; }
.row-latency { font-variant-numeric: tabular-nums; font-size: 12.5px; color: var(--muted); text-align: right; }

/* --- the bar timeline ----------------------------------------------------- */

/* Bars are separated by a 2px gap in the surface colour rather than a stroke:
   the gap is what makes neighbouring states read as distinct, and it costs no
   extra ink. */
.timeline { display: flex; gap: 2px; align-items: stretch; height: 30px; }
.tl-bar {
  flex: 1 1 0; min-width: 2px; border-radius: 2px;
  background: var(--neutral);
  position: relative;
  transition: transform 90ms ease, filter 90ms ease;
}
.tl-bar[data-state="up"]       { background: var(--good); }
.tl-bar[data-state="warning"]  { background: var(--warning); }
.tl-bar[data-state="serious"]  { background: var(--serious); }
.tl-bar[data-state="critical"] { background: var(--critical); }
.tl-bar[data-state="none"]     { background: var(--neutral); opacity: 0.45; }
/* The hit target is the bar plus its gap; without this a 4px bar is unhittable. */
.tl-bar::after { content: ""; position: absolute; inset: -4px -2px; }
.tl-bar:hover { filter: brightness(1.12); transform: scaleY(1.12); }

.tl-legend {
  display: flex; gap: 14px; flex-wrap: wrap; align-items: center;
  font-size: 11.5px; color: var(--muted); padding: 10px 2px 0;
}
.tl-legend span { display: inline-flex; align-items: center; gap: 5px; }
.tl-legend i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }

/* --- status pill ---------------------------------------------------------- */

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 550; padding: 2px 8px 2px 6px; border-radius: 20px;
  border: 1px solid transparent; white-space: nowrap;
}
.pill[data-status="up"]       { color: var(--good);     background: color-mix(in srgb, var(--good) 12%, transparent);     border-color: color-mix(in srgb, var(--good) 26%, transparent); }
.pill[data-status="down"]     { color: var(--critical); background: color-mix(in srgb, var(--critical) 12%, transparent); border-color: color-mix(in srgb, var(--critical) 26%, transparent); }
.pill[data-status="degraded"] { color: var(--serious);  background: color-mix(in srgb, var(--warning) 16%, transparent);  border-color: color-mix(in srgb, var(--warning) 34%, transparent); }
.pill[data-status="paused"], .pill[data-status="disabled"], .pill[data-status="pending"] {
  color: var(--muted); background: color-mix(in srgb, var(--muted) 12%, transparent); border-color: var(--border);
}

/* --- detail view ---------------------------------------------------------- */

.detail-head { display: flex; align-items: flex-start; gap: 14px; padding: 26px 0 18px; flex-wrap: wrap; }
.detail-head .back { color: var(--muted); font-size: 13px; }
.detail-title { display: flex; align-items: center; gap: 10px; }
.detail-title h1 { font-size: 22px; }
.detail-sub { color: var(--muted); font-size: 13px; font-family: var(--mono); margin-top: 4px; }
.detail-actions { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 20px; }
.stat { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 13px 15px; }
.stat .label { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.05em; }
.stat .value { font-size: 22px; font-weight: 600; margin-top: 3px; letter-spacing: -0.02em; }
.stat .sub { font-size: 12px; color: var(--muted); margin-top: 2px; }

.panel { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 20px; }
.panel-head {
  display: flex; align-items: baseline; gap: 10px;
  padding: 14px 16px 0;
}
.panel-head h2 { font-size: 14px; }
.panel-head .note { font-size: 12px; color: var(--muted); margin-left: auto; }
.panel-body { padding: 14px 16px; }

.chart { width: 100%; display: block; overflow: visible; }
.chart .grid-line { stroke: var(--grid); stroke-width: 1; }
.chart .axis-text { fill: var(--muted); font-size: 10.5px; font-family: var(--font); }
.chart .series-line { stroke: var(--accent); stroke-width: 2; fill: none; stroke-linejoin: round; stroke-linecap: round; }
.chart .series-area { fill: var(--accent); opacity: 0.10; }
.chart .down-mark { fill: var(--critical); }
.chart .crosshair { stroke: var(--baseline); stroke-width: 1; }
.chart .hover-dot { fill: var(--accent); stroke: var(--surface); stroke-width: 2; }

table.data { width: 100%; border-collapse: collapse; font-size: 13px; }
table.data th {
  text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--muted); font-weight: 500; padding: 0 10px 7px 0; border-bottom: 1px solid var(--border);
}
table.data td { padding: 8px 10px 8px 0; border-bottom: 1px solid var(--border); vertical-align: top; }
table.data tr:last-child td { border-bottom: 0; }
table.data td.num { font-variant-numeric: tabular-nums; text-align: right; padding-right: 0; }
table.data td.mono { font-family: var(--mono); font-size: 12px; color: var(--ink-2); }
.scroll-x { overflow-x: auto; }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 16px; font-size: 13px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; font-family: var(--mono); font-size: 12.5px; overflow-wrap: anywhere; }

/* --- forms ---------------------------------------------------------------- */

.field { margin-bottom: 14px; }
.field > label { display: block; font-size: 12.5px; font-weight: 550; margin-bottom: 5px; }
.field .help { font-size: 12px; color: var(--muted); margin-top: 5px; }
.field input[type="text"], .field input[type="password"], .field input[type="number"],
.field select, .field textarea {
  width: 100%; font: inherit; padding: 7px 10px;
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
}
.field textarea { min-height: 72px; resize: vertical; font-family: var(--mono); font-size: 12.5px; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--accent); }
.field.check { display: flex; align-items: flex-start; gap: 9px; }
.field.check input { margin-top: 2px; }
.field.check label { font-weight: 450; margin: 0; }
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0 14px; }

.form-section { border-top: 1px solid var(--border); margin-top: 18px; padding-top: 16px; }
.form-section h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin-bottom: 12px; }

details.advanced { margin-top: 6px; }
details.advanced > summary {
  cursor: pointer; font-size: 12.5px; color: var(--accent); list-style: none;
  padding: 6px 0; user-select: none;
}
details.advanced > summary::-webkit-details-marker { display: none; }
details.advanced > summary::before { content: "▸ "; }
details.advanced[open] > summary::before { content: "▾ "; }

.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  border: 1px solid var(--border-firm); border-radius: 20px; padding: 4px 11px; font-size: 12.5px;
}
.chip:hover { background: var(--surface-2); }
.chip input { margin: 0; }
.chip[data-checked="true"] { border-color: var(--accent); background: var(--accent-wash); }

/* --- modal ---------------------------------------------------------------- */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 60;
  background: color-mix(in srgb, var(--page) 60%, rgba(0, 0, 0, 0.45));
  display: grid; place-items: start center; padding: 5vh 16px;
  overflow-y: auto;
}
.modal {
  background: var(--surface); border: 1px solid var(--border-firm); border-radius: 14px;
  box-shadow: var(--shadow); width: 100%; max-width: 560px;
}
.modal-head { display: flex; align-items: center; gap: 10px; padding: 16px 18px 6px; }
.modal-head h2 { font-size: 16px; }
.modal-head .icon-button { margin-left: auto; }
.modal-body { padding: 10px 18px 4px; max-height: 68vh; overflow-y: auto; }
.modal-foot {
  display: flex; gap: 8px; justify-content: flex-end; align-items: center;
  padding: 14px 18px; border-top: 1px solid var(--border); margin-top: 10px;
}
.modal-foot .left { margin-right: auto; }

/* --- misc ----------------------------------------------------------------- */

.empty {
  text-align: center; padding: 60px 20px; color: var(--muted);
  border: 1px dashed var(--border-firm); border-radius: var(--radius); background: var(--surface);
}
.empty h2 { font-size: 16px; color: var(--ink); margin-bottom: 6px; }
.empty p { margin: 0 auto 16px; max-width: 42ch; }

.loading { padding: 60px 0; color: var(--muted); text-align: center; }

.foot { padding: 26px 20px 40px; color: var(--muted); font-size: 12px; }

.toasts { position: fixed; right: 16px; bottom: 16px; z-index: 80; display: flex; flex-direction: column; gap: 8px; }
.toast {
  background: var(--surface); border: 1px solid var(--border-firm); border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm); box-shadow: var(--shadow);
  padding: 10px 14px; font-size: 13px; max-width: 380px;
}
.toast[data-kind="error"] { border-left-color: var(--critical); }
.toast[data-kind="success"] { border-left-color: var(--good); }

.tooltip {
  position: fixed; z-index: 90; pointer-events: none;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: 8px 10px; font-size: 12px; max-width: 260px;
}
.tooltip .tt-value { font-weight: 600; font-size: 13px; }
.tooltip .tt-label { color: var(--muted); font-size: 11.5px; margin-top: 1px; }
.tooltip .tt-row { display: flex; align-items: center; gap: 6px; margin-top: 4px; }
.tooltip .tt-key { width: 14px; height: 2px; border-radius: 1px; flex: none; }

.inline-note { font-size: 12.5px; color: var(--muted); }
.mono { font-family: var(--mono); font-size: 12.5px; }
.copyable {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 6px 8px; font-family: var(--mono); font-size: 12px; overflow-wrap: anywhere;
}

/* --- narrow screens ------------------------------------------------------- */

@media (max-width: 760px) {
  .wrap { padding: 0 16px; }

  .row {
    grid-template-columns: 1fr auto;
    grid-template-areas: "name uptime" "timeline timeline";
    row-gap: 10px;
  }
  .row-name { grid-area: name; }
  .row-uptime { grid-area: uptime; }
  .row .timeline { grid-area: timeline; }
  .row-latency { display: none; }
  .axis-row { grid-template-columns: 1fr; padding-bottom: 4px; }
  .axis-row .axis-line { grid-column: 1; }

  /* The 24h view draws 96 bars. At the desktop 2px gap they cannot compress
     below ~382px (96 bars at their 2px minimum plus 95 gaps), which is wider
     than a phone and pushed the whole page into horizontal scroll. Halving the
     gap takes the floor to ~287px and fits, while still separating the bars --
     the gap only has to read as a gap. */
  .timeline { gap: 1px; }

  .topbar-inner { gap: 12px; }
  .topnav a { padding: 6px 8px; }
  .hero-text h1 { font-size: 21px; }
  .brand-mark { margin-right: 0; box-shadow: none; }

  /* The live indicator keeps its dot, which carries the state on its own.
     Clipping the word rather than display:none keeps it in the accessibility
     tree, so a screen reader still announces the connection state. */
  .live-text {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
}

@media (max-width: 460px) {
  /* Three nav items, a wordmark and the tools no longer fit side by side. The
     mark alone still identifies the app, and it is a link home either way. */
  .brand-name { display: none; }
  .topnav a { padding: 6px 7px; font-size: 13.5px; }
}

/* --- session controls ----------------------------------------------------- */

.auth-slot { display: inline-flex; align-items: center; }
.button.ghost { background: transparent; border-color: var(--border); }

/* --- sign-in gate --------------------------------------------------------- */
/* The dashboard is not a public status page, so until there is a session there
   is nothing to show around the login -- the nav and footer are hidden rather
   than left as dead chrome hinting at pages the viewer cannot open. */

body[data-gated="true"] .topnav,
body[data-gated="true"] .live,
body[data-gated="true"] .foot { display: none; }

.gate {
  max-width: 340px;
  margin: 12vh auto 0;
  padding: 26px 26px 24px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
}

.gate-title {
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-bottom: 4px;
}

.gate-sub {
  font-size: 13px;
  color: var(--ink-2);
  margin-bottom: 20px;
}

.gate-note {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}

.gate-label {
  display: block;
  font-size: 12.5px;
  font-weight: 550;
  margin-bottom: 5px;
}

.gate input[type="password"],
.gate input[type="email"],
.gate input[type="text"] {
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  font-size: 13.5px;
  color: var(--ink);
  background: var(--page);
  border: 1px solid var(--border-firm);
  border-radius: 7px;
}

.gate input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-wash);
}

/* The six digits are the only thing on the screen, so they get the room. */
.gate input.gate-code {
  font-family: var(--mono);
  font-size: 26px;
  letter-spacing: 0.35em;
  text-align: center;
  padding: 10px 6px 10px 14px;
}

.gate-error {
  min-height: 17px;
  margin-top: 7px;
  font-size: 12.5px;
  color: var(--critical);
}

.gate-ok {
  font-size: 12.5px;
  color: var(--good);
}

.gate-ok:empty { display: none; }

.gate-submit {
  width: 100%;
  margin-top: 9px;
  justify-content: center;
}

.gate-note b { color: var(--ink); font-weight: 550; }
.gate-form .gate-note { margin-top: 12px; }
.gate-foot { text-align: center; }

.linkbutton {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 12.5px;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.linkbutton:disabled { opacity: 0.5; cursor: default; }

.auth-who {
  font-size: 12.5px;
  color: var(--ink-2);
  margin-right: 8px;
  max-width: 24ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- access panel --------------------------------------------------------- */

.access-h3 { font-size: 13px; font-weight: 600; margin: 18px 0 8px; }
.access-h3:first-of-type { margin-top: 14px; }
.access-h3 .note { font-size: 12px; font-weight: 450; color: var(--muted); }

.access-add { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.access-add input {
  flex: 1 1 200px;
  padding: 6px 9px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--page);
  border: 1px solid var(--border-firm);
  border-radius: 7px;
}
.access-add input:focus { outline: none; border-color: var(--accent); }

.access-alert { flex-direction: column; align-items: stretch; gap: 2px; }
.access-alert strong + .stale-hint { margin-bottom: 8px; }
.access-alert .stale-hint:last-child { margin-bottom: 0; }

table.data tr.revoked td { color: var(--muted); }
table.data td.actions { white-space: nowrap; }

.invite-out { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 12px; }
.invite-field {
  flex: 1 1 260px;
  padding: 6px 9px;
  font: inherit;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
  background: var(--page);
  border: 1px solid var(--border-firm);
  border-radius: 7px;
}
.invite-out .help { font-size: 12px; color: var(--muted); flex-basis: 100%; }

.pill[data-tone="good"] { color: var(--good);     background: color-mix(in srgb, var(--good) 12%, transparent);     border-color: color-mix(in srgb, var(--good) 26%, transparent); }
.pill[data-tone="bad"]  { color: var(--critical); background: color-mix(in srgb, var(--critical) 12%, transparent); border-color: color-mix(in srgb, var(--critical) 26%, transparent); }
.pill[data-tone="warn"] { color: var(--serious);  background: color-mix(in srgb, var(--warning) 16%, transparent);  border-color: color-mix(in srgb, var(--warning) 34%, transparent); }
.pill[data-tone="none"] { color: var(--muted); }

/* --- ticker warning ------------------------------------------------------- */
/* Shown when nothing has called /api/cron recently. It has to outrank the
   status hero visually: a stale green dashboard is worse than a red one. */

.stale-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 6px;
  margin: 0 0 16px;
  padding: 11px 14px;
  border-radius: 8px;
  font-size: 13px;
  color: var(--ink);
  background: color-mix(in srgb, var(--critical) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--critical) 45%, var(--border-firm));
}

.stale-banner strong { color: var(--critical); }

.stale-banner .stale-hint {
  flex-basis: 100%;
  margin-top: 3px;
  font-size: 12px;
  color: var(--muted);
}

/* --- layout utilities ----------------------------------------------------- */
/* These exist so no element carries an inline style attribute, which is what
   lets the Content-Security-Policy drop 'unsafe-inline' from style-src. */

.flush       { margin: 0; }
.flush-top   { margin-top: 0; }
.spaced-top  { margin-top: 14px; }
.gap-right   { margin-right: 6px; }
.pulled-up   { margin: -8px 0 12px; }
.error-text  { color: var(--critical); }

/* Legend swatches, coloured by token rather than by an inline background. */
.tl-legend i[data-token="good"]     { background: var(--good); }
.tl-legend i[data-token="warning"]  { background: var(--warning); }
.tl-legend i[data-token="serious"]  { background: var(--serious); }
.tl-legend i[data-token="critical"] { background: var(--critical); }
.tl-legend i[data-token="neutral"]  { background: var(--neutral); opacity: 0.45; }

/* --- break glass ---------------------------------------------------------- */

.bg-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
}
.bg-row:first-child { border-top: 0; }
.bg-label { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.bg-label b { font-weight: 550; overflow-wrap: anywhere; }
.bg-label em { font-style: normal; font-size: 12px; color: var(--muted); }
.gate-foot a { color: var(--accent); }
