/* ─── tokens ──────────────────────────────────────────────────────────── */
:root {
  /* Warm near-black surfaces (Vercel-ish) */
  --bg:           #0a0a0a;
  --bg-2:         #0d0d0c;
  --surface:      #111110;
  --surface-2:    #161614;
  --surface-3:    #1c1c19;
  --hairline:     rgba(255, 255, 255, 0.07);
  --hairline-2:   rgba(255, 255, 255, 0.10);
  --grid:         rgba(255, 255, 255, 0.05);
  --grid-strong:  rgba(255, 255, 255, 0.18);
  --bar-empty:    rgba(255, 255, 255, 0.07);

  --text:         #ededed;
  --text-2:       #b4b4b1;
  --text-3:       #8a8a86;
  --text-4:       #6a6a66;

  /* Status colors */
  --ok:           #34d399;
  --ok-dim:       rgba(52, 211, 153, 0.18);
  --warn:         #f59e0b;
  --warn-dim:     rgba(245, 158, 11, 0.18);
  --bad:          #ef4444;
  --bad-dim:      rgba(239, 68, 68, 0.18);
  --info:         #60a5fa;
  --info-dim:     rgba(96, 165, 250, 0.18);
  /* Loss-of-signal: shown when probesStale=true. Distinct from --bar-empty
     (which is a translucent overlay) and from --ok/--warn/--bad (saturated). */
  --stale:        #9ca3af;
  --stale-dim:    rgba(156, 163, 175, 0.18);

  /* Accent — amber per user pick */
  --accent:       #f59e0b;
  --accent-2:     #fbbf24;
  --accent-soft:  rgba(245, 158, 11, 0.12);

  /* Theme-swappable bits — overridden in :root[data-theme="light"]. */
  --btn-primary-fg:       #0a0a0a;
  --btn-primary-hover-bg: #fff;
  --hover-bg:             rgba(255,255,255,0.025);
  --inset-hl:             rgba(255,255,255,0.05);
  --page-grad:            linear-gradient(180deg, #0c0b0a 0%, #0a0a0a 800px);
  --header-grad:          linear-gradient(180deg, rgba(10,10,10,0.85), rgba(10,10,10,0.55));
  --title-grad:           linear-gradient(180deg, #fff 0%, #c8c8c4 100%);

  --radius:       12px;
  --radius-lg:    16px;
  --radius-sm:    8px;
  --shadow:       0 1px 0 rgba(255,255,255,0.04) inset,
                  0 30px 80px -20px rgba(0,0,0,0.5),
                  0 8px 24px -12px rgba(0,0,0,0.5);

  --font:         'Onest', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
}

/* During a theme flip, fade every element's color-ish properties so the swap
   feels smooth. The class is added by the toggle and removed ~260ms later, so
   it doesn't pile on top of the short per-component hover transitions. */
html.theme-transitioning,
html.theme-transitioning *,
html.theme-transitioning *::before,
html.theme-transitioning *::after {
  transition: background-color 240ms ease,
              background 240ms ease,
              color 240ms ease,
              border-color 240ms ease,
              box-shadow 240ms ease,
              fill 240ms ease,
              stroke 240ms ease !important;
}

/* ─── light theme override ────────────────────────────────────────────── */
:root[data-theme="light"] {
  --bg:           #fafaf9;
  --bg-2:         #f4f4f2;
  --surface:      #ffffff;
  --surface-2:    #f7f7f5;
  --surface-3:    #efefec;
  --hairline:     rgba(0, 0, 0, 0.08);
  --hairline-2:   rgba(0, 0, 0, 0.12);
  --grid:         rgba(0, 0, 0, 0.05);
  --grid-strong:  rgba(0, 0, 0, 0.22);
  --bar-empty:    rgba(0, 0, 0, 0.08);
  --stale:        #6b7280;
  --stale-dim:    rgba(107, 114, 128, 0.18);

  --text:         #18181b;
  --text-2:       #3f3f46;
  --text-3:       #71717a;
  --text-4:       #a1a1aa;

  --btn-primary-fg:       #fafaf9;
  --btn-primary-hover-bg: #000;
  --hover-bg:             rgba(0,0,0,0.035);
  --inset-hl:             rgba(0,0,0,0.04);
  --page-grad:            linear-gradient(180deg, #f4f4f2 0%, #fafaf9 800px);
  /* Match the body's top color (--bg-2 = #f4f4f2) so the sticky header
     composites invisibly over it instead of reading as a lighter strip. */
  --header-grad:          linear-gradient(180deg, rgba(244,244,242,0.85), rgba(244,244,242,0.55));
  --title-grad:           linear-gradient(180deg, #18181b 0%, #52525b 100%);

  --shadow:       0 1px 0 rgba(255,255,255,0.6) inset,
                  0 30px 80px -20px rgba(0,0,0,0.10),
                  0 8px 24px -12px rgba(0,0,0,0.08);
}

/* ─── reset ──────────────────────────────────────────────────────────── */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  font-size: 14.5px;
  line-height: 1.5;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
  background-image:
    radial-gradient(1200px 600px at 10% -10%, rgba(245, 158, 11, 0.04), transparent 60%),
    radial-gradient(900px 500px at 95% 0%, rgba(96, 165, 250, 0.025), transparent 60%),
    var(--page-grad);
  background-attachment: fixed;
}
button { font-family: inherit; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4, p { margin: 0; }

/* ─── layout ─────────────────────────────────────────────────────────── */
.shell {
  max-width: 1140px;
  margin: 0 auto;
  padding: 0 28px 80px;
}

/* ─── page enter + top progress bar ──────────────────────────────────── */
/* Each direct child of .shell fades + slides up with a small per-position
   delay so the page cascades in instead of popping as one block. `backwards`
   fill-mode hides the element until its delay kicks in. */
.shell > * {
  animation: pageEnter 360ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
}
.shell > *:nth-child(1) { animation-delay:  60ms; }
.shell > *:nth-child(2) { animation-delay: 120ms; }
.shell > *:nth-child(3) { animation-delay: 180ms; }
.shell > *:nth-child(4) { animation-delay: 240ms; }
.shell > *:nth-child(5) { animation-delay: 300ms; }
.shell > *:nth-child(6) { animation-delay: 360ms; }
.shell > *:nth-child(7) { animation-delay: 420ms; }
.shell > *:nth-child(n+8) { animation-delay: 480ms; }

/* Header drops in from above. */
.hdr { animation: headerEnter 360ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards; }

@keyframes pageEnter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes headerEnter {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

/* Thin top progress bar. Toggled by .is-loading (initial data fetch) and
   .is-navigating (full-page nav). Opacity fade keeps the appearance gentle;
   the inner pill animates only while visible. */
.page-loader {
  position: fixed; top: 0; left: 0; right: 0;
  height: 2px;
  overflow: hidden;
  z-index: 1000;
  pointer-events: none;
  opacity: 0;
  transition: opacity 180ms ease;
}
body.is-loading .page-loader,
body.is-navigating .page-loader { opacity: 1; }
.page-loader::before {
  content: '';
  position: absolute; top: 0; bottom: 0; left: 0;
  width: 30%;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  animation: pageLoaderSlide 1.1s ease-in-out infinite;
}
@keyframes pageLoaderSlide {
  from { transform: translateX(-100%); }
  to   { transform: translateX(420%); }
}

@media (prefers-reduced-motion: reduce) {
  .shell > *, .hdr, .srv-row, .bar { animation: none; }
  .page-loader::before { animation: none; }
}

/* ─── header ─────────────────────────────────────────────────────────── */
.hdr {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 28px;
  max-width: 1140px; margin: 0 auto;
  backdrop-filter: blur(12px) saturate(160%);
  -webkit-backdrop-filter: blur(12px) saturate(160%);
  background: var(--header-grad);
}
.hdr::after {
  content: '';
  position: absolute;
  left: 28px; right: 28px; bottom: 0;
  height: 1px;
  background: var(--hairline);
}
.logo { display: flex; align-items: center; }
/* Sizing-only — display is owned by the variant rules below so the
   .logo-img--light/--dark display:none takes effect. The previous
   `display: block` here had higher specificity (0,1,1) than the
   single-class variant rules (0,1,0) and silently showed both
   logos at once. */
.logo img { height: 32px; width: auto; }

/* Two glyph variants — render both in JSX, hide the wrong one via CSS
   based on the active data-theme. The dark variant (light glyph for
   dark backgrounds) is the default since the site loads dark by
   default; the light variant takes over when the user toggles light. */
.logo-img--light { display: none; }
.logo-img--dark  { display: block; }
:root[data-theme="light"] .logo-img--light { display: block; }
:root[data-theme="light"] .logo-img--dark  { display: none; }
.hdr-right { display: flex; align-items: center; gap: 8px; }
.hdr-clock {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 12px; border-radius: 99px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  font-family: var(--font-mono); font-size: 12px;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px;
  padding: 0; border-radius: 99px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  color: var(--text-2);
  cursor: pointer;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.theme-toggle:hover { background: var(--surface-2); color: var(--text); border-color: var(--hairline-2); }

/* Admin link in the public-page header. Only rendered when /api/me confirms
   the visitor is a status admin — see AdminButton in components.jsx. Low
   visual weight on purpose: deliberately not a CTA. */
.hdr-admin-link {
  display: inline-flex; align-items: center;
  padding: 5px 10px;
  border-radius: 99px;
  font-size: 12px; font-weight: 500; letter-spacing: 0.02em;
  background: var(--surface);
  border: 1px solid var(--hairline);
  color: var(--text-2);
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.hdr-admin-link:hover { background: var(--surface-2); color: var(--text); border-color: var(--hairline-2); }

/* ─── buttons ─────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px;
  border-radius: 8px;
  font-size: 13px; font-weight: 500;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background .15s ease, border-color .15s ease, color .15s ease, transform .1s;
  background: transparent; color: var(--text);
}
.btn-ghost {
  background: var(--surface);
  border-color: var(--hairline);
  color: var(--text-2);
}
.btn-ghost:hover { background: var(--surface-2); border-color: var(--hairline-2); color: var(--text); }
.btn-primary { background: var(--text); color: var(--btn-primary-fg); }
.btn-primary:hover { background: var(--btn-primary-hover-bg); }
.btn-sm { padding: 5px 10px; font-size: 12px; }
.btn.block { display: flex; justify-content: center; width: 100%; }
.btn:active { transform: translateY(1px); }

.link { color: var(--accent); font-size: 13px; font-weight: 500; }
.link:hover { color: var(--accent-2); }

/* ─── dots & pills ────────────────────────────────────────────────────── */
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 99px; background: currentColor; }
.dot-lg { width: 11px; height: 11px; }
.dot-pulse { position: relative; }
.dot-pulse::after {
  content: ''; position: absolute; inset: -3px;
  border-radius: 99px; background: currentColor; opacity: 0.35;
  animation: pulse 1.8s ease-out infinite;
}
.dot-pulse[style*="--ok"]::after { background: var(--ok); }
@keyframes pulse {
  0%   { transform: scale(0.6); opacity: 0.45; }
  100% { transform: scale(2.4); opacity: 0; }
}
.banner-ok .dot-pulse::after { background: var(--ok); }
.banner-degraded .dot-pulse::after { background: var(--warn); }
.banner-outage .dot-pulse::after { background: var(--bad); }
.banner-maintenance .dot-pulse::after { background: var(--info); }
.hdr-clock .dot-pulse { color: var(--ok); }
.hdr-clock .dot-pulse::after { background: var(--ok); }

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px;
  border-radius: 99px;
  font-size: 12px; font-weight: 500;
  border: 1px solid var(--hairline);
  background: var(--surface);
  white-space: nowrap;
  flex-shrink: 0;
}
.pill .dot { width: 6px; height: 6px; }
.pill-sm { font-size: 11px; padding: 2px 8px; }
.pill-ok   { color: var(--ok);   background: var(--ok-dim);   border-color: rgba(52,211,153,0.25); }
.pill-warn { color: var(--warn); background: var(--warn-dim); border-color: rgba(245,158,11,0.25); }
.pill-bad  { color: var(--bad);  background: var(--bad-dim);  border-color: rgba(239,68,68,0.25); }
.pill-info { color: var(--info); background: var(--info-dim); border-color: rgba(96,165,250,0.25); }
.pill-ok .dot   { background: var(--ok); }
.pill-warn .dot { background: var(--warn); }
.pill-bad .dot  { background: var(--bad); }
.pill-info .dot { background: var(--info); }

.chip {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  font-size: 11px; font-weight: 500;
  color: var(--text-3);
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: 6px;
}

.muted { color: var(--text-3); font-size: 13px; }

/* ─── banner ──────────────────────────────────────────────────────────── */
.banner {
  position: relative;
  margin: 36px 0 22px;
  padding: 28px 32px;
  border-radius: var(--radius-lg);
  background: linear-gradient(180deg, var(--surface) 0%, var(--bg-2) 100%);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow);
}
/* Glow self-clips at the banner's rounded corners (border-radius: inherit + its
   own overflow:hidden) so the banner itself can stay overflow:visible — the
   "30-day uptime" InfoTip bubble pops above the banner edge otherwise it would
   be clipped by an overflow:hidden on the banner. */
.banner-glow {
  position: absolute; inset: 0; pointer-events: none; opacity: 0.65;
  background: radial-gradient(600px 240px at 10% 0%, var(--ok-dim), transparent 70%);
  transition: background .6s ease, opacity .6s ease;
  border-radius: inherit;
  overflow: hidden;
}
.banner-degraded    .banner-glow { background: radial-gradient(600px 240px at 10% 0%, var(--warn-dim),  transparent 70%); }
.banner-outage      .banner-glow { background: radial-gradient(600px 240px at 10% 0%, var(--bad-dim),   transparent 70%); }
.banner-stale       .banner-glow { background: radial-gradient(600px 240px at 10% 0%, var(--stale-dim), transparent 70%); }
.banner-maintenance .banner-glow { background: radial-gradient(600px 240px at 10% 0%, var(--info-dim),  transparent 70%); }

/* Loss-of-signal banner — rendered ABOVE the headline banner when probesStale.
   Warning-yellow (not red) because stale probes are not the same as an outage. */
.stale-banner {
  display: flex; align-items: center; gap: 12px;
  margin: 28px 0 -10px;
  padding: 14px 18px;
  border-radius: var(--radius);
  background: var(--warn-dim);
  border: 1px solid rgba(245, 158, 11, 0.35);
  color: var(--text);
}
.stale-banner-icon {
  width: 28px; height: 28px; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  color: var(--warn);
}
.stale-banner-title { font-weight: 600; }
.stale-banner-sub   { color: var(--text-3); font-size: 13px; margin-top: 2px; }

/* Grayed-out per-row uptime when probesStale. */
.srv-uptime-stale { color: var(--stale); font-variant-numeric: tabular-nums; }

.banner-inner {
  position: relative;
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: 26px;
}
.banner-icon {
  width: 56px; height: 56px;
  border-radius: 18px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  color: var(--ok);
}
.banner-degraded    .banner-icon { color: var(--warn); }
.banner-outage      .banner-icon { color: var(--bad); }
.banner-stale       .banner-icon { color: var(--stale); }
.banner-maintenance .banner-icon { color: var(--info); }
.banner-eyebrow {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; font-weight: 500;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-3);
}
.banner-eyebrow > span:first-child { font-weight: 600; }
.banner-sep { color: var(--text-4); }
.banner-title {
  font-size: 30px; line-height: 1.15; letter-spacing: -0.02em;
  font-weight: 600; margin-top: 6px;
  background: var(--title-grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  text-wrap: balance;
}
.banner-sub { color: var(--text-3); margin-top: 6px; max-width: 60ch; }

.banner-stats { display: flex; gap: 28px; align-items: center; padding-left: 24px; border-left: 1px solid var(--hairline); }
.stat { text-align: right; min-width: 90px; }
.stat-num {
  font-size: 26px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.stat-num span { font-size: 14px; color: var(--text-3); font-weight: 500; margin-left: 2px; }
.stat-lbl { font-size: 11px; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 2px; display: inline-flex; align-items: center; gap: 4px; }

/* ─── info tooltip ────────────────────────────────────────────────────── */
.info-tip {
  display: inline-flex; align-items: center;
  color: var(--text-4);
  cursor: help;
  position: relative;
  outline: none;
}
.info-tip svg { width: 12px; height: 12px; }
.info-tip:hover, .info-tip:focus-visible { color: var(--text-2); }
.info-tip-bubble {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 0;
  width: 240px;
  padding: 10px 12px;
  background: var(--surface-3);
  border: 1px solid var(--hairline-2);
  border-radius: 8px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-2);
  letter-spacing: 0;
  text-transform: none;
  font-weight: 400;
  box-shadow: 0 10px 30px -8px rgba(0,0,0,0.6);
  z-index: 10;
  visibility: hidden;
  opacity: 0;
  transition: opacity .12s ease, visibility .12s ease;
  pointer-events: none;
}
.info-tip:hover .info-tip-bubble,
.info-tip:focus-visible .info-tip-bubble { visibility: visible; opacity: 1; }
/* Inside chart labels the icon sits on the left of the card — anchor the bubble left so it doesn't overflow. */
.chart-lbl .info-tip-bubble { right: auto; left: 0; }

/* ─── card ──────────────────────────────────────────────────────────── */
.card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 22px 24px;
  margin-bottom: 18px;
}
.card-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 18px;
}
.card-head h2 { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
.card-head p { margin-top: 4px; font-size: 13px; }

/* ─── segmented control ─────────────────────────────────────────────── */
.seg-row { display: flex; gap: 10px; align-items: center; }
.seg {
  display: inline-flex; padding: 3px;
  background: var(--surface-2); border: 1px solid var(--hairline);
  border-radius: 8px;
}
.seg button {
  appearance: none; border: 0; background: transparent;
  color: var(--text-3);
  padding: 5px 12px; font-size: 12px; font-weight: 500;
  border-radius: 6px; cursor: pointer;
  transition: background .12s ease, color .12s ease;
  font-family: inherit;
}
.seg button:hover { color: var(--text-2); }
.seg button.on {
  background: var(--surface-3); color: var(--text);
  box-shadow: 0 1px 0 var(--inset-hl) inset;
}

/* ─── incident card ─────────────────────────────────────────────────── */
.incident {
  padding: 0; overflow: hidden;
  border-color: rgba(245, 158, 11, 0.25);
  background: linear-gradient(180deg, rgba(245,158,11,0.05), var(--surface) 70%);
}
.incident-bad {
  border-color: rgba(239, 68, 68, 0.28);
  background: linear-gradient(180deg, rgba(239,68,68,0.06), var(--surface) 70%);
}
/* Status = monitoring → blue card. Overrides severity-based outline. */
.incident-info {
  border-color: rgba(96, 165, 250, 0.28);
  background: linear-gradient(180deg, rgba(96,165,250,0.06), var(--surface) 70%);
}
/* Status = resolved → neutral card, no severity/status tint. */
.incident-neutral {
  border-color: var(--hairline);
  background: var(--surface);
}
.incident-head {
  width: 100%;
  /* Two-row layout: pills + meta on the first row, title on the second.
     Gap separates the pills from the title; padding-bottom is intentionally
     tight so the description below reads as a continuation of the title. */
  display: flex; flex-direction: column; gap: 14px;
  padding: 14px 22px 4px;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: inherit; text-align: left;
  font-family: inherit;
}
.incident-head:hover { background: var(--hover-bg); }
/* Static head on the dedicated /incident/?id=… page — not clickable. */
.incident-head-static { cursor: default; }
.incident-head-static:hover { background: transparent; }
/* Collapsed state: the body is hidden, so the head needs its own bottom
   padding instead of relying on the description's padding to close off the
   card. Matches the top padding so the title isn't pinned to the border. */
.incident-head-collapsed { padding-bottom: 14px; }
/* Same reasoning for cards with no description paragraph (maintenance cards,
   incidents whose description is empty/null): the meta grid would otherwise
   sit flush with the title because the head's 4px bottom assumes a
   description is hugging it from below. */
.card.incident:not(:has(.incident-desc)) .incident-head { padding-bottom: 14px; }
.incident-head-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; min-width: 0;
}
.incident-head-pills {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; min-width: 0;
}
.incident-title {
  font-weight: 500;
  font-size: 17px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--text);
}
.incident-head-r {
  display: flex; align-items: center; gap: 12px;
  color: var(--text-3); font-size: 13px;
  flex-shrink: 0;
}
.chev { transition: transform .2s ease; }
.chev.open { transform: rotate(180deg); }

.incident-body {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .28s ease;
}
.incident-body.open { grid-template-rows: 1fr; }
.incident-body-inner {
  min-height: 0;
  overflow: hidden;
}

.incident-desc {
  /* Optional context paragraph between the head and the meta grid.
     padding-top is 0 because the head already finishes with only 4px under
     the title — together with this, description hugs the title closely. */
  padding: 0 22px 14px;
  margin: 0;
  color: var(--text-2);
  font-size: 13.5px;
  max-width: 80ch;
  white-space: pre-wrap;
}
.incident-meta {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  padding: 14px 22px;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.incident-meta > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.incident-meta b { font-weight: 500; color: var(--text); font-size: 13.5px; }
.incident-meta .muted { text-transform: uppercase; letter-spacing: 0.06em; font-size: 10.5px; }

.timeline {
  display: flex; align-items: center; justify-content: space-between;
  list-style: none; padding: 22px 22px 6px; margin: 0;
  position: relative;
}
.timeline::before {
  content: ''; position: absolute;
  left: 50px; right: 50px; top: calc(22px + 8px);
  border-top: 1px dashed var(--hairline-2);
  z-index: 0;
}
.tl-step {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  color: var(--text-4); font-size: 12px;
}
.tl-mark {
  width: 18px; height: 18px; border-radius: 99px;
  background: var(--surface-2);
  border: 1px solid var(--hairline-2);
  display: flex; align-items: center; justify-content: center;
}
.tl-mark > span {
  width: 8px; height: 8px; border-radius: 99px;
  background: var(--surface-3);
}
/* Completed phases (reached, not the current step) — always green. */
.tl-step.on:not(.current) .tl-mark        { border-color: var(--ok); background: var(--ok-dim); }
.tl-step.on:not(.current) .tl-mark > span { background: var(--ok); }
.tl-step.on:not(.current)                 { color: var(--ok); }

/* Current phase — color is driven by the per-label classes below via
   --tl-color / --tl-dim. Falls back to the page accent for legacy markup. */
.tl-step.current .tl-mark {
  border-color: var(--tl-color, var(--accent));
  background:   var(--tl-dim,   var(--accent-soft));
  box-shadow: 0 0 0 4px var(--tl-dim, var(--accent-soft));
}
.tl-step.current .tl-mark > span { background: var(--tl-color, var(--accent)); }
.tl-step.current                 { color: var(--tl-color, var(--accent)); }

/* Per-phase color tokens. */
.tl-investigating { --tl-color: var(--bad);  --tl-dim: var(--bad-dim);  }
.tl-identified    { --tl-color: var(--warn);   --tl-dim: var(--warn-dim);   }
.tl-monitoring    { --tl-color: var(--info);   --tl-dim: var(--info-dim);   }
.tl-resolved      { --tl-color: var(--ok);     --tl-dim: var(--ok-dim);     }
/* Maintenance timeline steps share the same plumbing. Verifying uses the
   same info-blue as the status pill at the top of the card — keeps it
   inside the palette and decoupled from the user-tweakable --accent. */
.tl-scheduled     { --tl-color: var(--info);   --tl-dim: var(--info-dim);   }
.tl-in-progress   { --tl-color: var(--warn);   --tl-dim: var(--warn-dim);   }
.tl-verifying     { --tl-color: var(--info);   --tl-dim: var(--info-dim);   }
.tl-completed     { --tl-color: var(--ok);     --tl-dim: var(--ok-dim);     }

.updates {
  list-style: none; margin: 0; padding: 8px 22px 22px;
}
.update {
  padding: 14px 0;
  border-top: 1px solid var(--hairline);
}
.update:first-child { border-top: 0; }
.update-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.update p { color: var(--text-2); font-size: 13.5px; max-width: 80ch; }
.update-tag {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px; border-radius: 4px;
}
.tag-investigating { color: var(--bad);    background: var(--bad-dim);  }
.tag-identified    { color: var(--warn);   background: var(--warn-dim); }
.tag-monitoring    { color: var(--info);   background: var(--info-dim); }
.tag-resolved      { color: var(--ok);     background: var(--ok-dim); }
/* Maintenance update labels. */
.tag-scheduled     { color: var(--info);   background: var(--info-dim); }
.tag-in-progress   { color: var(--warn);   background: var(--warn-dim); }
.tag-verifying     { color: var(--info);   background: var(--info-dim); }
.tag-completed     { color: var(--ok);     background: var(--ok-dim); }

/* ─── services grid ─────────────────────────────────────────────────── */
.srv-legend {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 4px; padding: 0 2px;
}
.legend-l { display: flex; gap: 16px; color: var(--text-3); font-size: 12px; }
.legend-l span { display: inline-flex; align-items: center; gap: 6px; }
.legend-r { display: flex; align-items: center; gap: 8px; font-size: 11px; }
.legend-line { width: 80px; height: 1px; background: var(--hairline-2); }

/* Mobile: at narrow viewports the legend's two halves can't both fit
   on one row — "1 hour ago" wraps to two lines and the line graphic
   gets squished. Stack the halves, let legend-l wrap if it has to,
   and let the line graphic flex to fill whatever space is left on
   the timestamp row. */
@media (max-width: 560px) {
  .srv-legend {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .legend-l { flex-wrap: wrap; gap: 8px 14px; }
  .legend-r { justify-content: space-between; }
  .legend-r .muted { white-space: nowrap; }
  .legend-line { flex: 1; width: auto; min-width: 24px; }
}

.srv-list { display: flex; flex-direction: column; gap: 6px; margin-top: 16px; }
.srv-group { padding-top: 6px; }
.srv-group-head {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-4);
  padding: 12px 4px 8px;
}

.srv-row {
  display: grid;
  grid-template-columns: minmax(220px, 280px) 1fr minmax(96px, 110px);
  align-items: center; gap: 20px;
  padding: 14px 6px;
  position: relative;
  /* 9px gutter above each row (4px + 1px divider + 4px) so spacing matches
     the past-incident / maintenance-history lists, where each <li> has
     padding: 4px 0 around the rounded hover pill. */
  margin-top: 9px;
  border-radius: var(--radius-sm);
  transition: background .12s ease;
  /* Continuous stagger across all monitors regardless of group. The --row-i
     custom property is set inline by UptimeRow. */
  animation: rowEnter 320ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
  animation-delay: calc(var(--row-i, 0) * 28ms);
  /* Row is rendered as <a> so middle-/Cmd-click opens the detail page in a new
     tab. Reset the anchor defaults that would otherwise repaint it. */
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}
.srv-row:focus-visible { outline: 2px solid var(--text); outline-offset: -2px; }
/* Divider drawn in the gutter above each row instead of on the row itself,
   so the row's hover background can be a rounded pill with breathing room. */
.srv-row::before {
  content: '';
  position: absolute;
  top: -5px; left: 0; right: 0;
  height: 1px;
  background: var(--hairline);
}
@keyframes rowEnter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.srv-row:hover { background: var(--hover-bg); }

.srv-meta { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.srv-name {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-weight: 500; font-size: 14px;
}
.srv-desc { font-size: 12px; color: var(--text-3); }

/* Service status dot on the left of the name. Pulses once each time a fresh probe lands. */
.srv-dot {
  position: relative;
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 99px;
  flex-shrink: 0;
}
.srv-dot::after {
  content: '';
  position: absolute; inset: -3px;
  border-radius: 99px;
  background: currentColor;
  opacity: 0;
  pointer-events: none;
}
.srv-dot-pulsing::after { animation: srvDotPulse 1.6s ease-out 1; }
@keyframes srvDotPulse {
  0%   { transform: scale(0.55); opacity: 0.55; }
  100% { transform: scale(2.6);  opacity: 0;    }
}

/* Hover tooltip around the dot. Left-anchored and content-sized; reuses the
   .info-tip / .info-tip-bubble plumbing so hover + focus behaviour is consistent. */
.srv-dot-tip { line-height: 0; }
.srv-dot-bubble { right: auto; left: 0; width: max-content; min-width: 220px; max-width: 360px; padding: 10px 14px; }
.srv-dot-tip-row { display: flex; align-items: center; gap: 10px; line-height: 1.4; }
.srv-dot-tip-title { color: var(--text); font-weight: 500; font-size: 12px; }
.srv-dot-tip-meta  { color: var(--text-3); font-size: 11px; margin-top: 2px; }

.srv-viz { position: relative; height: 32px; }

.bars {
  display: flex; align-items: center; gap: 2px;
  height: 100%; position: relative;
}
.bar {
  flex: 1; height: 100%; min-width: 2px;
  background: var(--bar-color);
  border-radius: 2px;
  transition: transform .12s ease, opacity .12s ease, filter .12s ease;
  opacity: 0.88;
  transform-origin: bottom;
  /* Quick left-to-right rise within each row. Bars inherit --row-i from the
     parent .srv-row so the sweep starts when the row settles in. */
  animation: barRise 280ms cubic-bezier(0.2, 0.8, 0.2, 1) backwards;
  animation-delay: calc(var(--row-i, 0) * 28ms + var(--bar-i, 0) * 4ms + 60ms);
}
@keyframes barRise {
  from { transform: scaleY(0); opacity: 0; }
  to   { transform: scaleY(1); opacity: 0.88; }
}
.bar:hover { transform: scaleY(1.08); opacity: 1; filter: brightness(1.2); }

/* Skeleton state for the latest "no data" bar — a probe is in flight, so the
   bar reads as actively loading rather than as a permanent gap. A solid
   brighter-grey background plus a vertical scale + opacity pulse reads
   clearly even on a 6–10px wide bar; horizontal shimmer sweeps don't (the
   bar is too narrow for them to register). Overrides the dim --bar-empty
   background and the one-shot barRise so the pulse is the only motion. */
.bar-fetching {
  background: var(--text-4) !important;
  opacity: 1 !important;
  transform-origin: bottom !important;
  animation: barSkeleton 1.2s ease-in-out infinite !important;
}
@keyframes barSkeleton {
  0%, 100% { transform: scaleY(0.7); opacity: 0.45; }
  50%      { transform: scaleY(1);   opacity: 0.95; }
}
@media (prefers-reduced-motion: reduce) {
  .bar-fetching { animation: none !important; opacity: 0.6 !important; }
}

/* Reveal animation when the latest bar transitions from fetching to a real
   value — a quick rise + soft glow handoff so it doesn't just pop in place. */
.bar-just-landed {
  animation: barLand 520ms cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes barLand {
  0%   { transform: scaleY(0.2); opacity: 0; filter: brightness(1.6); }
  60%  { transform: scaleY(1.08); opacity: 1; filter: brightness(1.3); }
  100% { transform: scaleY(1);    opacity: 0.88; filter: brightness(1); }
}
@media (prefers-reduced-motion: reduce) {
  .bar-just-landed { animation: none; }
}

/* Tooltip spinner shown in place of the status dot while a probe is pending. */
.bar-tip-spinner {
  width: 9px; height: 9px;
  border-radius: 99px;
  border: 1.5px solid var(--hairline-2);
  border-top-color: var(--text-2);
  animation: barTipSpin .7s linear infinite;
}
@keyframes barTipSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .bar-tip-spinner { animation: none; }
}
.bar-tip {
  position: absolute; bottom: 110%;
  transform: translateX(-50%);
  background: var(--surface-3);
  border: 1px solid var(--hairline-2);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 11.5px;
  white-space: nowrap;
  z-index: 5;
  pointer-events: none;
  box-shadow: 0 10px 30px -10px rgba(0,0,0,0.6);
  animation: tipIn .12s ease;
}
@keyframes tipIn { from { opacity: 0; transform: translateX(-50%) translateY(2px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
.bar-tip-d { font-weight: 500; color: var(--text); }
.bar-tip-s { display: flex; align-items: center; gap: 6px; color: var(--text-3); margin-top: 2px; }
.bar-tip-s .dot { width: 7px; height: 7px; }

.dots-grid {
  display: grid;
  grid-template-columns: repeat(45, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 2px; height: 100%;
}
.dot-cell { border-radius: 2px; opacity: 0.85; }

.spark { width: 100%; height: 100%; display: block; }

.pill-bar {
  position: relative; height: 8px; width: 100%; margin: 12px 0;
}
.pill-bar-track { position: absolute; inset: 0; background: var(--bar-empty); border-radius: 99px; }
.pill-bar-fill {
  position: absolute; top: 0; left: 0; bottom: 0;
  background: linear-gradient(90deg, var(--ok), #6ee7b7);
  border-radius: 99px;
}
.pill-bar-incident {
  position: absolute; top: -2px; width: 3px; height: 12px;
  border-radius: 2px;
}

.srv-stat { text-align: right; }
.srv-uptime {
  font-family: var(--font-mono);
  font-size: 14px; font-weight: 500;
  color: var(--text); letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.srv-uptime span { color: var(--text-3); margin-left: 1px; }
.srv-uptime-lbl { font-size: 10.5px; color: var(--text-4); text-transform: uppercase; letter-spacing: 0.08em; }

/* ─── charts ───────────────────────────────────────────────────────── */
.charts { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 760px) { .charts { grid-template-columns: 1fr; } }

.chart {
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 16px 18px 12px;
}
.chart-head { display: flex; justify-content: space-between; align-items: flex-start; }
.chart-lbl { font-size: 12px; color: var(--text-3); display: inline-flex; align-items: center; gap: 4px; }
.chart-val {
  font-size: 22px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; margin-top: 2px;
  transition: color .2s ease;
}
.chart-val span { font-size: 13px; color: var(--text-3); margin-left: 3px; font-weight: 500; }
.chart-meta { font-size: 11px; }
.chart-wrap { position: relative; height: 110px; margin-top: 10px; cursor: crosshair; }
.chart-svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.chart-axis {
  display: flex; justify-content: space-between;
  position: absolute; left: 0; right: 0; bottom: -16px;
  font-size: 10px; color: var(--text-4);
  font-family: var(--font-mono);
}

.chart-tip {
  position: absolute;
  bottom: calc(100% + 6px);
  transform: translateX(-50%);
  background: var(--surface-3);
  border: 1px solid var(--hairline-2);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 11.5px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 6;
  box-shadow: 0 10px 30px -10px rgba(0,0,0,0.6);
}
.chart-tip-lbl { color: var(--text-3); font-family: var(--font-mono); }
.chart-tip-val { color: var(--text); font-weight: 500; margin-top: 2px; }

.chart-empty {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-4); font-size: 12px;
}

/* ─── maintenance ──────────────────────────────────────────────────── */
.maint { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; }
.maint-row {
  display: grid; grid-template-columns: auto 1fr;
  gap: 14px; padding: 16px;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: 10px;
}
.maint-icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  background: var(--info-dim); color: var(--info);
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.maint-title { font-weight: 500; font-size: 14px; }
.maint-window {
  /* Neutral muted color — accent on the public page is tweakable, so a
     window timestamp shouldn't ride on it. */
  font-family: var(--font-mono); font-size: 12px;
  color: var(--text-2); margin-top: 2px;
}
.maint-impact { margin-top: 6px; max-width: 80ch; font-size: 13px; }
.maint-affects { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }

/* ─── past incidents ─────────────────────────────────────────────────── */
/* ─── past incidents (grouped by month) ─────────────────────────────── */
.past-total {
  font-size: 11.5px;
  font-family: var(--font-mono);
  letter-spacing: 0.02em;
}
.past-groups { display: flex; flex-direction: column; gap: 20px; }

/* Back link above the card on the public /incident/?id=… detail page.
   Muted on purpose — past incidents shouldn't read like a call-to-action. */
.incident-page-nav { margin: 22px 0 8px; }
.incident-page-nav a {
  display: inline-flex; align-items: center;
  color: var(--text-3);
  font-size: 13px; font-weight: 500;
  transition: color .12s ease;
}
.incident-page-nav a:hover { color: var(--text); }

.past-month-head {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 4px 4px 8px;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 4px;
}
.past-month-label {
  font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--text-3);
}
.past-month-count {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-4);
  font-variant-numeric: tabular-nums;
}

.past-list { list-style: none; padding: 0; margin: 0; }
/* Breathing room around each row so the rounded hover pill doesn't kiss the
   divider above/below it. The divider sits at the li boundary; the padding
   isolates .past-item's hover background from the hairline. */
.past-list li { padding: 4px 0; }
.past-list li + li { border-top: 1px solid var(--hairline); }
/* Mirrors the admin incidents table row: title + muted mono subline on the
   left, severity + status pills on the right, in a 1fr/auto/auto grid.
   The row is an anchor so the whole thing is clickable and middle-click
   opens the detail page in a new tab. */
.past-item {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center; gap: 12px;
  padding: 12px 14px;
  color: inherit;
  text-decoration: none;
  /* Rounded so the hover background reads as a discrete pill, not as a
     flush table row. Visible only on hover/focus when the bg fills in. */
  border-radius: var(--radius-sm);
  transition: background .12s ease;
}
.past-item:hover { background: var(--hover-bg); }
/* Hover/focus stay neutral — the row's background highlight is the affordance.
   --text gives the brightest available foreground in either theme without
   pulling in the tweakable amber/purple accent. */
.past-item:hover .past-item-title { color: var(--text); }
.past-item:focus-visible { outline: 2px solid var(--text); outline-offset: -2px; }

.past-item-body { min-width: 0; }
.past-item-title {
  font-weight: 500;
  font-size: 14px;
  color: var(--text);
  letter-spacing: -0.005em;
}
.past-item-sub {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-3);
  margin-top: 3px;
}

@media (max-width: 560px) {
  /* Stack pills under the body on narrow widths. */
  .past-item { grid-template-columns: 1fr; }
  .past-item .pill { justify-self: flex-start; }
}

/* ─── docs page (How Status Works) ──────────────────────────────── */
.doc { margin: 0; padding: 32px 0 0; }
.doc-head { padding-bottom: 32px; border-bottom: 1px solid var(--hairline); margin-bottom: 32px; }
.doc-eyebrow {
  font-size: 12px; color: var(--text-3);
  text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600;
  margin: 0 0 12px;
}
.doc-title {
  font-size: 34px; font-weight: 700;
  letter-spacing: -0.02em; line-height: 1.15;
  margin: 0 0 16px;
}
.doc-lede { font-size: 16px; color: var(--text-2); margin: 0; max-width: 640px; }

.doc-toc {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  padding: 14px 18px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px 24px;
  margin-bottom: 40px;
}
.doc-toc a {
  font-size: 13px; color: var(--text-3);
  padding: 4px 0;
  transition: color .12s ease;
}
.doc-toc a:hover { color: var(--text); }

.doc-section { margin-bottom: 40px; scroll-margin-top: 24px; }
.doc-section h2 {
  font-size: 20px; font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 14px;
  color: var(--text);
}
.doc-section p { font-size: 14.5px; line-height: 1.7; color: var(--text-2); margin: 0 0 14px; }
.doc-section p:last-child { margin-bottom: 0; }
.doc-section strong { color: var(--text); font-weight: 600; }
.doc-section em { color: var(--text-2); font-style: italic; }
.doc-section code {
  font-family: var(--font-mono);
  font-size: 12.5px;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: 4px;
  padding: 1px 5px;
  color: var(--text);
}

.doc-list {
  list-style: none;
  padding: 0; margin: 0 0 14px;
  display: flex; flex-direction: column; gap: 10px;
}
.doc-list li {
  position: relative;
  padding-left: 22px;
  font-size: 14.5px; line-height: 1.7; color: var(--text-2);
}
.doc-list li::before {
  content: ''; position: absolute;
  left: 6px; top: 11px;
  width: 4px; height: 4px;
  border-radius: 99px;
  background: var(--text-4);
}

.doc-callout {
  background: var(--surface-3);
  border: 1px solid var(--hairline-2);
  border-left: 3px solid var(--text-3);
  border-radius: 6px;
  padding: 12px 16px !important;
  font-size: 14px !important;
}

.doc-code {
  font-family: var(--font-mono);
  font-size: 13px !important;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  padding: 12px 14px !important;
  color: var(--text) !important;
}

.doc-foot {
  margin-top: 48px; padding-top: 24px;
  border-top: 1px solid var(--hairline);
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 12px;
}
.doc-foot .muted { font-size: 13px; margin: 0; }
.doc-foot a { color: var(--text); }
.doc-foot a:hover { color: var(--text-2); }
.doc-back {
  font-size: 13px; font-weight: 500;
  color: var(--text-3) !important;
  transition: color .12s ease;
}
.doc-back:hover { color: var(--text) !important; }

/* On the how-status-works page the article already provides its own bottom
   spacing via .doc-foot, so the global .ftr margin can collapse considerably. */
.doc + .ftr { margin-top: 24px; }

@media (max-width: 760px) {
  .doc-title { font-size: 26px; }
  .doc-toc { grid-template-columns: 1fr; }
}

/* ─── monitor detail page (/monitor/?id=N) ───────────────────────────── */
.mon-hero { padding: 22px 24px; }
.mon-hero-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 6px;
}
/* Dot is wrapped in an .info-tip so the wrapper (not the dot) participates in
   flex layout; line-height:0 collapses the wrapper to the dot's box. */
.mon-hero-dot-tip { line-height: 0; flex-shrink: 0; }
.mon-hero-dot { width: 11px; height: 11px; }
.mon-hero-title {
  font-size: 22px; font-weight: 600; letter-spacing: -0.015em;
  color: var(--text);
}
.mon-hero-desc {
  font-size: 14.5px; color: var(--text-2);
  max-width: 80ch; margin: 4px 0 12px;
}
.mon-hero-meta {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 13px;
}
.mon-hero-sep { color: var(--text-4); }

.mon-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
.mon-stat {
  padding: 14px 16px;
  background: var(--surface-2);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  min-width: 0;
}
.mon-stat-lbl {
  font-size: 11px; color: var(--text-3);
  text-transform: uppercase; letter-spacing: 0.08em;
  margin-bottom: 6px;
}
.mon-stat-val {
  font-family: var(--font-mono);
  font-size: 22px; font-weight: 500;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  line-height: 1.1;
}
.mon-stat-unit { font-size: 13px; color: var(--text-3); margin-left: 2px; font-weight: 500; }
.mon-stat-sub { margin-top: 6px; font-size: 11.5px; color: var(--text-3); }

/* Wrap the bars row in a taller container on the detail page so the buckets
   feel substantial instead of being squeezed to a strip. */
.mon-bars-wrap { padding-top: 6px; }
.mon-bars { height: 56px; }

/* Generic table styling — ported from admin.css so the recent-checks table on
   the monitor detail page matches the admin view. Lives in status.css because
   no other public page currently needs a table; if that changes, lift this
   out of the .mon-* section. */
.tbl {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.tbl thead th {
  text-align: left;
  font-size: 10.5px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-4);
  padding: 10px 14px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--hairline);
  border-top: 1px solid var(--hairline);
}
.tbl tbody tr { transition: background .1s ease; }
.tbl tbody tr:hover { background: var(--hover-bg); }
.tbl tbody tr + tr td { border-top: 1px solid var(--hairline); }
.tbl tbody td {
  padding: 12px 14px;
  vertical-align: middle;
}
.cell-mono { font-family: var(--font-mono); font-size: 12px; }

/* Pull the table flush with the card's inner padding so the header row's
   surface tint reaches the card edges, matching admin's table-inside-panel look. */
.mon-checks-tbl { margin: 4px -24px 0; width: calc(100% + 48px); }
/* Close off the bottom of the table with a hairline so the last row reads as
   bounded (the .tbl pattern only draws border-top between rows, leaving the
   final row open at the bottom). */
.mon-checks-tbl tbody tr:last-child td { border-bottom: 1px solid var(--hairline); }

/* Recent-checks and Uptime-history cards keep the head→body divider, but
   stretch it to the card's outer edges (via negative side margins re-padded
   inside) so it lines up with the flush-edge table / bars below instead of
   ending short at the card's inner padding. Vertical gutters stay symmetric
   (22px above and below the divider) to match the card's top padding. */
.mon-history-card .card-head {
  padding-bottom: 22px;
  margin: 0 -24px 22px;
  padding-left: 24px;
  padding-right: 24px;
  border-bottom: 1px solid var(--hairline);
}
/* Recent-checks card drops the divider entirely — the table header's surface
   tint underneath already separates head from body. */
.mon-checks-card .card-head {
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: 22px;
}

/* Pagination controls sit below the table, separated by a hairline so they
   read as part of the same card section. Same shape as admin's .pager. */
.pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 14px 0 0;
  margin-top: 0;
}
.pager-status { font-size: 12.5px; font-variant-numeric: tabular-nums; }

@media (max-width: 760px) {
  .mon-stats { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 480px) {
  .mon-stats { grid-template-columns: 1fr; }
}

/* ─── footer ──────────────────────────────────────────────────────── */
.ftr {
  margin-top: 48px; padding-top: 24px;
  border-top: 1px solid var(--hairline);
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 16px;
}
.ftr-l { display: flex; flex-direction: column; gap: 4px; }
.ftr-l .muted { font-size: 12px; }
.ftr-contact { font-size: 12px; color: var(--text-3); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }
.ftr-contact a { color: var(--text-3); transition: color .12s ease; }
.ftr-contact a:hover { color: var(--text); }
.ftr-sep { color: var(--text-4); }
.ftr-links { display: flex; gap: 18px; font-size: 13px; color: var(--text-3); flex-wrap: wrap; }
.ftr-links a { transition: color .12s ease; }
.ftr-links a:hover { color: var(--text); }

/* ─── responsive ─────────────────────────────────────────────────────── */
@media (max-width: 760px) {
  .shell { padding: 0 16px 60px; }
  .hdr { padding: 14px 16px; }
  /* Clock kept visible on mobile — operators reading on a phone want
     to see the current time alongside incident timestamps. Trim the
     pill's padding so it still fits next to the wordmark + theme
     toggle on the narrowest viewports. */
  .hdr-clock { padding: 4px 9px; font-size: 11px; }
  .banner { padding: 22px; }
  .banner-inner { grid-template-columns: auto 1fr; gap: 16px; }
  .banner-stats { display: none; }
  .banner-title { font-size: 22px; }
  .srv-row { grid-template-columns: 1fr; gap: 10px; }
  .srv-stat { text-align: left; }
  .timeline::before { display: none; }
  .timeline { flex-wrap: wrap; gap: 12px; }
  .incident-meta { grid-template-columns: 1fr; }
}
