/* ════════════════════════════════════════════════════════════════════════
   SENTINEL — GLASS DESIGN SYSTEM
   Soft, layered, near-monochrome dark UI with translucent glass cards
   floating over topographic imagery.
   ════════════════════════════════════════════════════════════════════════ */

@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap');

/* ── Tokens ─────────────────────────────────────────────────────────── */
:root {
  /* Surfaces */
  --bg:             #0a0a0c;
  --bg-elevated:    #131318;
  --glass:          rgba(20, 20, 24, 0.42);
  --glass-strong:   #2d2f3269;
  --glass-warning:  rgba(60, 22, 22, 0.55);

  /* Hairlines */
  --hairline:        rgba(255, 255, 255, 0.08);
  --hairline-strong: rgba(255, 255, 255, 0.14);
  --hairline-bright: rgba(255, 255, 255, 0.22);

  /* Text */
  --text:           rgba(255, 255, 255, 0.92);
  --text-secondary: rgba(255, 255, 255, 0.55);
  --text-tertiary:  rgba(255, 255, 255, 0.38);
  --text-quaternary:rgba(255, 255, 255, 0.22);

  /* Status — used sparingly, mostly as small dots / icons */
  --ok:    #34D17A;
  --down:  #FF4D4F;
  --warn:  #FF9F43;
  --info:  #5DA8FF;

  /* Effects */
  --blur:           saturate(100%) blur(28px);
  --blur-light:     saturate(140%) blur(14px);
  --shadow-card:    0 8px 32px rgba(0, 0, 0, 0.4);
  --shadow-pill:    0 1px 0 rgba(255, 255, 255, 0.04) inset;

  /* Shared glass-surface chrome — applied to every major panel
     (rail, cards, modal, detail panel, tiles, monitors, etc.) so
     they read as the same material. Edit one var here to retune
     the whole app. */
  --glass-border:       1px solid rgba(255, 255, 255, 0.06);
  --glass-edge-light:   rgba(255, 255, 255, 0.14);
  --glass-shadow-lift:  0 8px 20px rgba(0, 0, 0, 0.30),
                        0 24px 56px -16px rgba(0, 0, 0, 0.35);

  /* Radii */
  --r-card:  22px;
  --r-tile:  16px;
  --r-pill:  999px;
  --r-chip:  10px;

  /* Type */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Display", system-ui, sans-serif;
  --w-light:   300;
  --w-regular: 400;
  --w-medium:  500;
  --w-semibold:600;

  /* Motion */
  --ease:        cubic-bezier(0.22, 1, 0.36, 1);
  --ease-quick:  cubic-bezier(0.4, 0, 0.2, 1);
}

/* ── Reset ──────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { font-size: 16px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
body {
  font-family: var(--font);
  font-weight: var(--w-regular);
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  overflow: hidden;
  letter-spacing: -0.005em;
}
button { font-family: inherit; color: inherit; background: none; border: none; cursor: pointer; }
a { color: inherit; text-decoration: none; }
h1, h2, h3, h4 { font-weight: var(--w-medium); letter-spacing: -0.015em; }


/* ════════════════════════════════════════════════════════════════════════
   LAYOUT
   ════════════════════════════════════════════════════════════════════════ */

.app {
  position: relative;
  height: 100vh;
  overflow: hidden;
}

/* ── Topbar — transparent overlay sitting above the map ─────────────── */
.topbar {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 64px;
  display: flex;
  align-items: center;
  gap: 32px;
  padding: 0 24px;
  background: transparent;
  z-index: 10;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.9rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.01em;
  color: var(--text);
}

.brand-mark {
  width: 26px;
  height: 26px;
  background: url('/img/sentinel-logo.svg') center center / contain no-repeat;
  flex-shrink: 0;
}

.tabs {
  display: flex;
  gap: 4px;
  align-items: center;
}

.tab {
  padding: 8px 18px;
  font-size: 0.8125rem;
  font-weight: var(--w-regular);
  color: var(--text-tertiary);
  border-radius: var(--r-pill);
  transition: color 0.15s var(--ease-quick), background 0.15s var(--ease-quick);
}

.tab:hover { color: var(--text-secondary); }

.tab.active {
  color: var(--text);
  /* Liquid glass — same body recipe as .icon-btn / .map-control /
     close buttons so the active pill reads as part of the same
     round-glass family. Border faked via inset shadow so the active
     state doesn't change tab geometry (no 1px shift on neighbours). */
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.20),
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 4px 14px rgba(0, 0, 0, 0.45);
}

.topbar-spacer { flex: 1; }

/* Mobile nav dropdown — hidden on desktop. Visibility is flipped at the
   720px breakpoint below where the inline `.tabs` are hidden instead. */
.tabs-mobile { position: relative; display: none; flex: 1; min-width: 0; }
.tabs-mobile-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  font-size: 0.84rem;
  font-weight: var(--w-medium);
  color: var(--text);
  border-radius: var(--r-pill);
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: var(--shadow-pill);
  letter-spacing: -0.005em;
  max-width: 100%;
}
.tabs-mobile-trigger svg {
  flex-shrink: 0;
  color: var(--text-tertiary);
  transition: transform 0.2s var(--ease-quick);
}
.tabs-mobile-trigger[aria-expanded="true"] svg { transform: rotate(180deg); }
.tabs-mobile-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 180px;
  background: rgba(20,20,24,0.94);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  box-shadow: var(--shadow-card);
  padding: 6px;
  z-index: 12;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.tabs-mobile-menu[hidden] { display: none; }
.tabs-mobile-item {
  display: block;
  padding: 9px 14px;
  font-size: 0.85rem;
  color: var(--text-secondary);
  border-radius: 10px;
  transition: background 0.12s, color 0.12s;
  white-space: nowrap;
}
.tabs-mobile-item:hover { background: rgba(255,255,255,0.06); color: var(--text); }
.tabs-mobile-item.active {
  background: rgba(255,255,255,0.08);
  color: var(--text);
  font-weight: var(--w-medium);
}

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

.icon-btn {
  position: relative;
  width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.92);
  /* Same recipe as .map-control + .detail-close so all the round
     glass buttons share one body language. */
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.20);
  box-shadow:
    0 4px 14px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.15);
  transition: background 0.15s, color 0.15s, transform 0.12s var(--ease-quick);
}
.icon-btn:hover {
  background: rgba(255, 255, 255, 0.18);
  color: var(--text);
  transform: translateY(-1px);
}
.icon-btn:active { transform: translateY(0) scale(0.96); }
.icon-btn svg { width: 18px; height: 18px; }

/* Red badge on the bell icon when there are unread alerts */
.icon-badge {
  position: absolute;
  top: 2px; right: 2px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--down);
  color: #fff;
  font-size: 0.62rem;
  font-weight: var(--w-medium);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  border: 2px solid var(--bg);
  font-feature-settings: "tnum";
}
.icon-badge[hidden] { display: none; }


/* ════════════════════════════════════════════════════════════════════════
   PERMANENT ALERTS PANEL — sits under Network Pulse on the Live Map.
   Hidden when there are no alerts; appears whenever there's something to
   show. Sections per category (Down / Incidents / Maintenance), with
   tinted item backgrounds matching the severity colour.
   ════════════════════════════════════════════════════════════════════════ */
.map-alerts {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: var(--r-card);
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
  overflow: hidden;
}
.map-alerts[hidden] { display: none; }

.map-alerts-head {
  padding: 13px 18px 6px;
}
.map-alerts-title {
  font-size: 0.92rem;
  font-weight: var(--w-medium);
  color: var(--text);
  letter-spacing: -0.01em;
}

.map-alerts-body {
  padding: 4px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 60vh;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline-strong) transparent;
}
.map-alerts-body::-webkit-scrollbar { width: 4px; }
.map-alerts-body::-webkit-scrollbar-thumb { background: var(--hairline-strong); border-radius: 2px; }

/* Section header (e.g. "Down Monitors (2)") */
.map-alerts-section { display: flex; flex-direction: column; gap: 4px; }
.map-alerts-section-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px 4px;
  font-size: 0.82rem;
  color: var(--text);
}
.map-alerts-section-icon {
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-secondary);
}
.map-alerts-section-icon.down        { background: rgba(255, 77, 79, 0.18);  color: var(--down); }
.map-alerts-section-icon.warn        { background: rgba(255, 159, 67, 0.18); color: var(--warn); }
.map-alerts-section-icon.ok          { background: rgba(52, 209, 122, 0.18); color: var(--ok); }
.map-alerts-section-icon.maintenance { background: rgba(175, 82, 222, 0.18); color: #B594E5; }
.map-alerts-section-title { font-weight: var(--w-medium); }
.map-alerts-section-count { font-size: 0.76rem; color: var(--text-tertiary); }

/* Individual alert item — clickable button, tinted by severity */
.alert-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  width: 100%;
  border: none;
  font-family: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: 14px;
  transition: background 0.15s, transform 0.1s;
  background: rgba(255, 77, 79, 0.10);  /* default — overridden by tone class */
}
.alert-item:hover { background: rgba(255, 77, 79, 0.16); }
.alert-item:focus-visible {
  outline: 2px solid var(--info);
  outline-offset: 2px;
}
/* Tone variants */
.alert-item.tone-down        { background: rgba(255, 77, 79, 0.10); }
.alert-item.tone-down:hover  { background: rgba(255, 77, 79, 0.18); }
.alert-item.tone-warn        { background: rgba(255, 159, 67, 0.10); }
.alert-item.tone-warn:hover  { background: rgba(255, 159, 67, 0.18); }
.alert-item.tone-ok          { background: rgba(52, 209, 122, 0.10); }
.alert-item.tone-ok:hover    { background: rgba(52, 209, 122, 0.18); }
.alert-item.tone-maintenance        { background: rgba(175, 82, 222, 0.10); }
.alert-item.tone-maintenance:hover  { background: rgba(175, 82, 222, 0.18); }

.alert-badge {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--text-tertiary);
  color: #fff;
  font-size: 0.7rem;
  font-weight: var(--w-medium);
}
.alert-badge.down { background: var(--down); }
.alert-badge.warn { background: var(--warn); }
.alert-badge.ok   { background: var(--ok);  color: #0a0a0c; }
.alert-badge.maintenance { background: #8E5BD2; }

.alert-item-info { flex: 1; min-width: 0; }
.alert-item-title {
  font-size: 0.86rem;
  color: var(--text);
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.alert-item-sub {
  font-size: 0.74rem;
  color: var(--text-secondary);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.alert-item-chevron {
  width: 14px;
  height: 14px;
  color: var(--text-tertiary);
  flex-shrink: 0;
}


/* ── Canvas — full-bleed map with floating glass overlays.
   Sits absolute behind the topbar so the map shows through it. */
.canvas {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #0d0d10;
}

/* Map fills the entire canvas, sitting under everything */
#map {
  position: absolute;
  inset: 0;
  z-index: 0;
  /* Hide while Mapbox is loading its first tile — the JS adds .ready
     once map.on('load') fires, eliminating the grey flash. */
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
#map.ready { opacity: 1; }
/* If JS / Mapbox token is unavailable the map never marks ready —
   reveal it after a generous timeout so the rest of the UI doesn't
   sit on top of a black box forever. */
@keyframes glass-map-fallback-in { to { opacity: 1; } }
#map { animation: glass-map-fallback-in 0s ease 4s forwards; }

/* ════════════════════════════════════════════════════════════════════════
   DASHBOARD ENTRY ANIMATION

   Sequence on first dashboard load:
     1. body has class `welcoming` (set in HTML)
     2. Topbar / rail / map-right are held off-screen
     3. <.dashboard-welcome> curtain centred over the canvas, with a
        backdrop-blur that masks the still-loading map underneath
     4. JS removes body.welcoming after ~1.8s + map ready
     5. Curtain fades out, chrome slides into place (staggered)
   Login has its own choreography on body.login-page; we exclude it here.
   ════════════════════════════════════════════════════════════════════════ */

/* Off-screen state during welcome */
body.welcoming .topbar,
body.welcoming .rail,
body.welcoming .map-right {
  opacity: 0;
  pointer-events: none;
}
body.welcoming .topbar    { transform: translateY(-100%); }
body.welcoming .rail      { transform: translateX(-100%); }
body.welcoming .map-right { transform: translateX(100%); }

/* When the welcoming class is removed, animate the chrome in.
   `both` fill mode pins the from-state pre-animation so there's no
   flash of the at-rest state before the keyframes start. */
@keyframes dashboard-slide-down {
  from { opacity: 0; transform: translateY(-100%); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes dashboard-slide-from-left {
  from { opacity: 0; transform: translateX(-100%); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes dashboard-slide-from-right {
  from { opacity: 0; transform: translateX(100%); }
  to   { opacity: 1; transform: translateX(0); }
}
/* `backwards` (not `both`) so the final keyframe's transform is released
   once the animation completes — a persistent transform on these
   containers creates a new containing block and breaks `backdrop-filter`
   on every descendant (the cards' blur stops seeing the map underneath). */
body:not(.welcoming):not(.login-page) .topbar {
  animation: dashboard-slide-down       0.55s var(--ease) 0s    backwards;
}
body:not(.welcoming):not(.login-page) .rail {
  animation: dashboard-slide-from-left  0.65s var(--ease) 0.12s backwards;
}
body:not(.welcoming):not(.login-page) .map-right {
  animation: dashboard-slide-from-right 0.65s var(--ease) 0.22s backwards;
}

/* The curtain itself */
.dashboard-welcome {
  position: fixed;
  inset: 0;
  z-index: 60;        /* above the map, below the modal layer */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(10, 10, 12, 0.66);
  backdrop-filter: blur(60px) saturate(140%);
  -webkit-backdrop-filter: blur(60px) saturate(140%);
  transition: opacity 0.6s var(--ease), backdrop-filter 0.6s var(--ease), -webkit-backdrop-filter 0.6s var(--ease);
}
.dashboard-welcome.fade-out {
  opacity: 0;
  pointer-events: none;
  backdrop-filter: blur(0px) saturate(100%);
  -webkit-backdrop-filter: blur(0px) saturate(100%);
}

.dashboard-welcome-card {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: var(--r-card);
  padding: 32px 44px 28px;
  text-align: center;
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 260px;
  max-width: 92vw;
  animation: dashboard-welcome-in 0.5s var(--ease);
}
@keyframes dashboard-welcome-in {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0)   scale(1); }
}

.dashboard-welcome-logo {
  width: 56px;
  height: 56px;
  margin-bottom: 14px;
  filter:
    drop-shadow(0 0 18px rgba(93, 168, 255, 0.32))
    drop-shadow(0 4px 14px rgba(0, 0, 0, 0.5));
}

.dashboard-welcome-title {
  font-size: 1.4rem;
  font-weight: var(--w-light);
  letter-spacing: -0.015em;
  color: var(--text);
  line-height: 1.3;
}
.dashboard-welcome-name {
  font-weight: var(--w-medium);
  color: var(--text);
}

.dashboard-welcome-sub {
  font-size: 0.82rem;
  color: var(--text-tertiary);
  margin-top: 6px;
  letter-spacing: 0.02em;
}

@media (max-width: 480px) {
  .dashboard-welcome-card { padding: 26px 30px 22px; min-width: 0; }
  .dashboard-welcome-title { font-size: 1.2rem; }
}

/* Left rail — inset glass panel containing the data cards.
   `top: 64px` clears the floating transparent topbar above. */
.rail {
  position: absolute;
  top: 64px;
  left: 0;
  bottom: 0;
  width: 600px;
  max-width: 90vw;
  transition: width 0.35s var(--ease);
  overflow-y: auto;
  padding: 13px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  z-index: 2;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline-strong) transparent;
  /* More transparent now — relies on the hairline border + soft
     shadow stack for definition rather than opacity. Reads as
     proper dark glass rather than a tinted overlay. */
  background: rgba(0, 0, 0, 0.45);
  border-radius: 23px;
  /* Really subtle hairline border. Border + box-shadow together
     give the rail a defined silhouette without needing a heavy
     background. */
  border: 1px solid rgba(255, 255, 255, 0.06);
  /* Full available height so flex children (.tab-panel + .cards-fade) can
     claim remaining space without per-tab math. 64px topbar + 40px margin = 104. */
  height: calc(100vh - 104px);
  margin: 20px;
  backdrop-filter: var(--blur) saturate(1.4) brightness(0.92);
  -webkit-backdrop-filter: var(--blur) saturate(1.4) brightness(0.92);
  /* Refined lift — dropped the punchy 2px close shadow that read as
     a hard line; now it's just two soft layers (bulk drop + far halo)
     at lower opacities. The hairline border above does the close-edge
     definition the 2px shadow used to. Inset highlights kept for the
     glass-edge feel.
  */
  box-shadow:
    /* Top edge highlight — light catching the upper rim of the glass */
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    /* Very subtle perimeter glow — inside-edge hint */
    inset 0 0 60px 6px rgba(255, 255, 255, 0.02),
    /* Darker bottom inner shadow — depth */
    inset 0 -1px 0 rgba(0, 0, 0, 0.3),
    inset 0 -24px 48px -24px rgba(0, 0, 0, 0.35),
    /* Soft mid drop — bulk lift */
    0 14px 36px rgba(0, 0, 0, 0.32),
    /* Far diffuse halo — ambient occlusion */
    0 32px 72px -20px rgba(0, 0, 0, 0.4);
}

/* Widen the rail to host the 3-col monitor grid when the user is on the
   Client Detail panel. Smooth width transition is on .rail above. */
.rail:has(.tab-panel[data-tab="client-detail"]:not([hidden])) {
  width: 900px;
}
.rail::-webkit-scrollbar { width: 6px; }
.rail::-webkit-scrollbar-thumb { background: var(--hairline-strong); border-radius: 3px; }

@media (max-width: 720px) {
  .rail { width: 100%; max-width: 100%; margin: 0; border-radius: 0; }
}


/* ════════════════════════════════════════════════════════════════════════
   COMPONENTS
   ════════════════════════════════════════════════════════════════════════ */

/* ── Pill / chip / badge primitives ─────────────────────────────────── */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  font-size: 0.78rem;
  font-weight: var(--w-regular);
  color: var(--text-secondary);
}

.pill-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--r-pill);
  font-size: 0.7rem;
  font-weight: var(--w-medium);
  color: var(--text);
  background: rgba(255,255,255,0.1);
  margin-left: 4px;
}

.dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--text-tertiary);
}
.dot.ok    { background: var(--ok); }
.dot.down  { background: var(--down); }
.dot.warn  { background: var(--warn); }


/* ── Segmented selector (24 Bus / 100 Taxi / 12 Trains) ────────────── */
.segmented {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.seg {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  background: var(--bg-elevated);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  font-size: 0.85rem;
  font-weight: var(--w-regular);
  color: var(--text-secondary);
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.seg:hover { color: var(--text); border-color: var(--hairline-strong); }
.seg-num { color: var(--text); font-weight: var(--w-medium); }


/* ── KPI tile (Online 12 / Offline 4) ──────────────────────────────── */
.tile {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 18px 20px;
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: var(--r-tile);
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
  /* button reset for tiles that act as filter toggles */
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: background 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.tile:hover { background: rgba(255, 255, 255, 0.07); }
.tile:focus-visible {
  outline: 2px solid var(--info);
  outline-offset: 2px;
}

/* Active filter — brighter fill + tinted icon halo so it reads as "on" */
.tile.active {
  background: rgba(255, 255, 255, 0.10);
  box-shadow: var(--shadow-card), 0 0 0 1px rgba(255, 255, 255, 0.16) inset;
}
.tile.active .tile-icon.ok   { background: rgba(52, 209, 122, 0.28);  color: var(--ok); }
.tile.active .tile-icon.down { background: rgba(255, 77, 79, 0.28);   color: var(--down); }
.tile.active .tile-icon.warn { background: rgba(255, 159, 67, 0.28);  color: var(--warn); }

.tile-icon {
  width: 24px; height: 24px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.06);
  color: var(--text-secondary);
}
.tile-icon svg { width: 14px; height: 14px; }
.tile-icon.ok    { background: rgba(52, 209, 122, 0.14); color: var(--ok); }
.tile-icon.down  { background: rgba(255, 77, 79, 0.14);  color: var(--down); }
.tile-icon.warn  { background: rgba(255, 159, 67, 0.14); color: var(--warn); }

.tile-label {
  font-size: 0.875rem;
  color: var(--text-secondary);
  font-weight: var(--w-regular);
}

.tile-value {
  font-size: 1.5rem;
  font-weight: var(--w-light);
  color: var(--text);
  line-height: 1;
  font-feature-settings: "tnum";
}

.tile-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}


/* ════════════════════════════════════════════════════════════════════════
   Card (generic glass panel).

   Every card gets the "liquid glass" treatment — frosted backdrop +
   layered lighting that fakes the look of a curved lens sitting over
   the satellite background. Composed of:

   1. backdrop-filter blur on the live background
   2. Top edge highlight (light reflecting off the rim)
   3. Soft inner perimeter glow (light bleeding round the inside edge)
   4. Bottom inner shadow (gives a sense of thickness)
   5. Radial-gradient lens stack via ::before — bright upper-left,
      dim lower-right, diagonal sweep — together suggesting a convex
      curve. Apple uses this same stack in iOS where a real shader
      isn't an option.
   6. Slowly-rotating low-saturation conic gradient via ::after,
      masked to a 1px ring — light wrapping around the rim.

   Pure CSS, universal browser support. Card content stays above the
   pseudo-elements via direct-child z-index. Reduced-motion preference
   stops the rim rotation; everything else is static anyway.

   Opt-out: add `.card.no-liquid` if a specific card looks wrong.
   ════════════════════════════════════════════════════════════════════════ */
.card {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: var(--r-card);
  padding: 22px;
  position: relative;
  /* Lens lighting insets specific to .card (the radial-gradient
     pseudo-elements below add the upper-left highlight + curvature
     cues; here we just set the rim + thickness shadows) +
     the shared --glass-shadow-lift for the lift off the rail / map. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    inset 0 0 32px 2px rgba(255, 255, 255, 0.05),
    inset 0 -8px 24px -12px rgba(0, 0, 0, 0.3),
    var(--glass-shadow-lift);
  overflow: hidden;
  isolation: isolate;
}

/* Faux-refraction highlight stack — two radial gradients + a diagonal
   band suggesting convex curvature. Static, so no animation cost. */
.card::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    radial-gradient(
      ellipse 80% 60% at 22% 18%,
      rgba(255, 255, 255, 0.11) 0%,
      rgba(255, 255, 255, 0.00) 55%
    ),
    radial-gradient(
      ellipse 70% 50% at 80% 80%,
      rgba(0, 0, 0, 0.10) 0%,
      rgba(0, 0, 0, 0.00) 60%
    ),
    linear-gradient(
      115deg,
      rgba(255, 255, 255, 0.05) 0%,
      rgba(255, 255, 255, 0.02) 30%,
      transparent 60%
    );
  pointer-events: none;
  z-index: 0;
}

/* Conic chromatic rim — slowly rotating, masked to a 1px ring. */
.card::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: conic-gradient(
    from var(--liquid-rim-angle, 0deg),
    rgba(255, 255, 255, 0.00) 0%,
    rgba(180, 210, 255, 0.20) 25%,
    rgba(255, 255, 255, 0.00) 50%,
    rgba(255, 200, 220, 0.20) 75%,
    rgba(255, 255, 255, 0.00) 100%
  );
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask-composite: exclude;
  pointer-events: none;
  z-index: 1;
  animation: liquid-rim 18s linear infinite;
}

/* Direct children sit above both pseudo-elements so highlights never
   tint text or buttons. Nested descendants inherit normal positioning. */
.card > * { position: relative; z-index: 2; }

/* Opt-out for any card where the treatment looks wrong (e.g. one that
   needs overflow:visible for a dropdown, or where the conic rim
   clashes with surrounding chrome). Add `.no-liquid` and the card
   falls back to a plain frosted panel. */
.card.no-liquid {
  box-shadow: var(--shadow-card);
  /* Drop the hairline border too so a no-liquid card is fully plain. */
  border: none;
  overflow: visible;
  isolation: auto;
}
.card.no-liquid::before,
.card.no-liquid::after { content: none; }

/* Rotate the conic gradient by animating a custom property. Requires
   @property support (Chrome 85+, Safari 16.4+, Firefox 128+). Older
   browsers see a static rim — same as the reduced-motion fallback. */
@property --liquid-rim-angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
@keyframes liquid-rim {
  to { --liquid-rim-angle: 360deg; }
}

@media (prefers-reduced-motion: reduce) {
  .card::before,
  .card::after { animation: none; }
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.card-title {
  font-size: 0.9rem;
  font-weight: var(--w-regular);
  color: var(--text-secondary);
  letter-spacing: -0.005em;
}

.card-ext {
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  color: var(--text-tertiary);
  transition: background 0.15s, color 0.15s;
}
.card-ext:hover { background: rgba(255,255,255,0.06); color: var(--text); }

/* Hero numeric value (78.3% style) */
.hero-value {
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-weight: var(--w-light);
  letter-spacing: -0.04em;
  line-height: 1;
}
.hero-value .num {
  font-size: 4rem;
  color: var(--text);
  font-feature-settings: "tnum";
}
.hero-value .num-decimal { color: var(--text-tertiary); }
.hero-value .unit {
  font-size: 1.1rem;
  color: var(--text-secondary);
  font-weight: var(--w-light);
}
.hero-target {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  margin-top: 8px;
  letter-spacing: 0.02em;
}

/* ════════════════════════════════════════════════════════════════════════
   Map controls — fixed bottom-right cluster of round glass buttons
   (zoom in / recenter on me / zoom out). Same glass-body language as
   the map markers so they read as part of the same UI family.
   ════════════════════════════════════════════════════════════════════════ */
.map-controls {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none; /* container is just a positioning frame */
}
.map-control {
  pointer-events: auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255,255,255,0.10);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255,255,255,0.20);
  box-shadow:
    0 4px 14px rgba(0,0,0,0.45),
    inset 0 1px 0 rgba(255,255,255,0.15);
  color: rgba(255,255,255,0.92);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.12s var(--ease-quick), background 0.12s var(--ease-quick);
}
.map-control:hover {
  background: rgba(255,255,255,0.18);
  transform: translateY(-1px);
}
.map-control:active {
  transform: translateY(0) scale(0.96);
  background: rgba(255,255,255,0.22);
}
.map-control:focus-visible {
  outline: 2px solid rgba(255,255,255,0.55);
  outline-offset: 2px;
}
.map-control svg { display: block; }

/* On narrow viewports, drop slightly inward + downsize so the cluster
   doesn't crowd whatever's at the bottom of the right rail (mobile
   nav, etc). */
@media (max-width: 720px) {
  .map-controls { bottom: 16px; right: 16px; gap: 6px; }
  .map-control  { width: 40px; height: 40px; }
}

/* ════════════════════════════════════════════════════════════════════════
   Monitor popup — opens on click of a monitor pin. Glass body, lists
   the monitor name + status + any "other sites on this server" (i.e.
   monitors sharing the same resolved IP). Mapbox's default Popup
   skin is overridden via the .glass-popup className passed to the
   Popup() constructor.
   ════════════════════════════════════════════════════════════════════════ */
.mapboxgl-popup.glass-popup .mapboxgl-popup-content {
  background: rgba(10, 10, 16, 0.55);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 14px;
  box-shadow:
    0 12px 32px rgba(0,0,0,0.55),
    inset 0 1px 0 rgba(255,255,255,0.10);
  padding: 14px 16px;
  color: rgba(255,255,255,0.92);
  font-family: inherit;
}
/* Hide the default Mapbox tip arrow — looks wrong on a frosted glass
   surface. The popup floats clean, anchored at the pin via offset. */
.mapboxgl-popup.glass-popup .mapboxgl-popup-tip { display: none; }

.glass-popup-body { display: flex; flex-direction: column; gap: 10px; }

.glass-popup-head .glass-popup-title {
  font-size: 0.95rem;
  font-weight: var(--w-medium);
  letter-spacing: -0.01em;
  color: var(--text);
}
.glass-popup-head .glass-popup-sub {
  font-size: 0.75rem;
  color: var(--text-tertiary);
  margin-top: 2px;
  word-break: break-word;
}

.glass-popup-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.glass-popup-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: var(--w-medium);
  background: rgba(255,255,255,0.08);
  color: var(--text-secondary);
}
.glass-popup-pill.ok          { background: rgba(52,209,122,0.18);  color: #94e8b8; }
.glass-popup-pill.down        { background: rgba(255,77,79,0.18);   color: #ffb4b5; }
.glass-popup-pill.warn        { background: rgba(255,159,67,0.18);  color: #ffd1a3; }
.glass-popup-pill.maintenance { background: rgba(93,168,255,0.18);  color: #b8d6ff; }
.glass-popup-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.glass-popup-rt {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  font-feature-settings: "tnum";
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.glass-popup-ip {
  font-size: 0.7rem;
  color: var(--text-tertiary);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  background: rgba(255,255,255,0.05);
  padding: 2px 6px;
  border-radius: 4px;
}

.glass-popup-sites {
  border-top: 1px solid rgba(255,255,255,0.10);
  padding-top: 10px;
}
.glass-popup-sites-label {
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-tertiary);
  margin-bottom: 6px;
}
.glass-popup-sites-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 140px;
  overflow-y: auto;
}
.glass-popup-sites-list li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.78rem;
  color: var(--text-secondary);
}
.glass-popup-site-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
  background: rgba(255,255,255,0.4);
}
.glass-popup-site-dot.ok          { background: var(--ok); }
.glass-popup-site-dot.down        { background: var(--down); }
.glass-popup-site-dot.warn        { background: var(--warn); }
.glass-popup-site-dot.maintenance { background: var(--info); }
.glass-popup-site-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* GA realtime visitor pin — same glass body as monitor / user pins
   but white and pulsing. Width/height set inline so the dot scales
   with active-user count. SVG icon inside picks up the white color. */
.glass-pin-visitor {
  background: rgba(255,255,255,0.22);
  border-color: rgba(255,255,255,0.55);
  color: #ffffff;
  box-shadow:
    0 4px 12px rgba(0,0,0,0.45),
    inset 0 1px 0 rgba(255,255,255,0.3),
    0 0 16px rgba(255,255,255,0.18);
  animation: glass-visitor-pulse 2.4s ease-in-out infinite;
}
.glass-pin-visitor svg {
  width: 55%;     /* scales with the inline width/height for big crowds */
  height: 55%;
  max-width: 18px;
  max-height: 18px;
}
@keyframes glass-visitor-pulse {
  0%, 100% { box-shadow: 0 4px 12px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.3), 0 0 14px rgba(255,255,255,0.18); }
  50%      { box-shadow: 0 4px 12px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.3), 0 0 24px rgba(255,255,255,0.35); }
}

/* Hover tooltip on visitor pins. Body styling matches the click
   popup (.mapboxgl-popup.glass-popup .mapboxgl-popup-content) so
   the two surfaces feel like the same UI family — same translucent
   dark base, same blur, same radius, same drop shadow + inset
   highlight. Padding is tighter since this is a small two-line
   info card rather than the popup's data dense block.
   pointer-events:none so the tooltip never captures a click meant
   for the pin underneath. */
.glass-pin-tooltip {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%) translateY(-6px);
  white-space: nowrap;
  padding: 8px 12px;
  background: rgba(10, 10, 16, 0.55);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 14px;
  color: rgba(255,255,255,0.95);
  font-size: 0.72rem;
  line-height: 1.35;
  letter-spacing: 0.01em;
  box-shadow:
    0 12px 32px rgba(0,0,0,0.55),
    inset 0 1px 0 rgba(255,255,255,0.10);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s var(--ease-quick), transform 0.15s var(--ease-quick);
  z-index: 4;
}
.glass-pin-visitor:hover .glass-pin-tooltip {
  opacity: 1;
  transform: translateX(-50%) translateY(-10px);
}
.glass-pin-tooltip-place {
  font-weight: var(--w-medium);
  color: var(--text);
}
.glass-pin-tooltip-count {
  margin-top: 2px;
  font-size: 0.68rem;
  color: var(--text-tertiary);
  font-feature-settings: "tnum";
}


/* ── Monitor card (signature) ──────────────────────────────────────── */
.monitor-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

/* 3-across only inside the wider Client Detail panel */
.tab-panel[data-tab="client-detail"] .monitor-grid {
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 1100px) {
  .tab-panel[data-tab="client-detail"] .monitor-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
  .monitor-grid,
  .tab-panel[data-tab="client-detail"] .monitor-grid { grid-template-columns: 1fr; }
}

.monitor {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: var(--r-tile);
  padding: 16px;
  cursor: pointer;
  transition: background 0.2s var(--ease), transform 0.2s var(--ease);
  position: relative;
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
}
.monitor:hover {
  background: rgba(255, 255, 255, 0.06);
  transform: translateY(-1px);
}

.monitor-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 14px;
}

.monitor-title {
  font-size: 0.9rem;
  font-weight: var(--w-medium);
  color: var(--text);
  letter-spacing: -0.005em;
}

.monitor-sub {
  font-size: 0.72rem;
  color: var(--text-tertiary);
  margin-top: 2px;
  font-feature-settings: "tnum";
}

.monitor-illust {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 56px;
  margin: 8px 0 12px;
  color: var(--text-secondary);
  position: relative;
}
.monitor-illust svg { width: 100%; height: 100%; max-width: 180px; }
.monitor-illust .badge {
  position: absolute;
  background: rgba(20,20,24,0.78);
  backdrop-filter: var(--blur-light);
  -webkit-backdrop-filter: var(--blur-light);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  padding: 4px 10px;
  font-size: 0.7rem;
  color: var(--text);
  font-feature-settings: "tnum";
  display: flex;
  align-items: center;
  gap: 8px;
}
.monitor-illust .badge .badge-letter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: rgba(255,255,255,0.1);
  color: var(--text-secondary);
  font-size: 0.65rem;
}

.monitor-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px 4px 8px;
  border-radius: var(--r-pill);
  font-size: 0.72rem;
  font-weight: var(--w-regular);
  color: var(--text-secondary);
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--hairline);
}
.status-pill.ok    { color: var(--ok);   border-color: rgba(52,209,122,0.22); }
.status-pill.down  { color: var(--down); border-color: rgba(255,77,79,0.22); }
.status-pill.warn  { color: var(--warn); border-color: rgba(255,159,67,0.22); }

.signal-icons {
  display: flex;
  gap: 12px;
  font-size: 0.7rem;
  color: var(--text-tertiary);
}
.signal-icons span { display: inline-flex; align-items: center; gap: 4px; }
.signal-icons svg { width: 11px; height: 11px; }

/* Response-time sparkline at the bottom of each monitor card */
.monitor-spark {
  height: 64px;
  margin: 12px -16px -16px;
  border-radius: 0 0 var(--r-tile) var(--r-tile);
  background: rgba(0, 0, 0, 0.18);
  position: relative;
  overflow: hidden;
}
.monitor-spark svg {
  width: 100%;
  height: 100%;
  display: block;
}
.monitor-spark::before,
.monitor-spark::after {
  position: absolute;
  font-size: 0.62rem;
  font-weight: var(--w-medium);
  color: var(--text-tertiary);
  letter-spacing: 0.04em;
  pointer-events: none;
  z-index: 1;
}
.monitor-spark::before { content: attr(data-from); top: 6px;    left: 12px; }
.monitor-spark::after  { content: attr(data-to);   bottom: 6px; right: 12px; }
.monitor-spark-empty {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.72rem;
  color: var(--text-quaternary);
  letter-spacing: 0.02em;
}


/* ── Floating glass overlay card (Passenger Load style) ─────────────── */
/* Right-column stack on the map (Network Pulse + Alerts) */
.map-right {
  position: absolute;
  top: 62px;
  right: 32px;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 360px;
  max-width: calc(100vw - 64px);
}

.map-card {
  position: relative;
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: var(--r-card);
  padding: 18px 22px 20px;
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
}

.map-card .card-title { color: var(--text); }
.map-card-sub {
  font-size: 0.78rem;
  color: var(--text-tertiary);
  margin-top: 2px;
}
.map-card-value {
  font-size: 2.4rem;
  font-weight: var(--w-light);
  color: var(--text);
  margin-top: 14px;
  letter-spacing: -0.04em;
  line-height: 1;
  font-feature-settings: "tnum";
}
.map-card-value .unit { font-size: 1rem; color: var(--text-secondary); margin-left: 2px; }


/* ── Slide-up detail panel ──────────────────────────────────────────── */
.detail-panel {
  position: absolute;
  left: 640px;            /* clears the left rail (rail width 600 + 20 margin + gap) */
  bottom: 20px;
  width: 420px;
  max-width: calc(100vw - 660px);
  max-height: calc(100vh - 120px);
  /* `left` transitions in sync with the rail when navigating to/from the
     wider Client Detail tab. */
  transition: transform 0.45s var(--ease), opacity 0.3s var(--ease), left 0.35s var(--ease), max-width 0.35s var(--ease);
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: 22px;
  padding: 22px 24px 20px;
  z-index: 8;
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow: hidden;
  /* Hidden by default — translate fully off-screen, fade out */
  transform: translateY(calc(100% + 40px));
  opacity: 0;
  pointer-events: none;
}
.detail-panel.open {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}

@media (max-width: 1100px) {
  .detail-panel { left: 20px; max-width: calc(100vw - 40px); }
}

/* When the user is on the Client Detail panel the rail is 900px wide,
   so the slide-up detail panel needs to clear that. 900 + 20 + 20 = 940. */
.canvas:has(.tab-panel[data-tab="client-detail"]:not([hidden])) .detail-panel {
  left: 940px;
  max-width: calc(100vw - 960px);
}
@media (max-width: 1100px) {
  .canvas:has(.tab-panel[data-tab="client-detail"]:not([hidden])) .detail-panel {
    left: 20px;
    max-width: calc(100vw - 40px);
  }
}

.detail-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}
.detail-eyebrow {
  font-size: 0.62rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.detail-title {
  font-size: 1.25rem;
  font-weight: var(--w-light);
  letter-spacing: -0.02em;
  color: var(--text);
  margin-top: 2px;
}
.detail-host {
  font-size: 0.74rem;
  color: var(--text-secondary);
  margin-top: 4px;
  word-break: break-all;
}
.detail-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.92);
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.20);
  box-shadow:
    0 4px 14px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.15);
  z-index: 2;
  flex-shrink: 0;
  transition: background 0.15s, color 0.15s, transform 0.12s var(--ease-quick);
}
.detail-close:hover { background: rgba(255, 255, 255, 0.18); color: var(--text); transform: translateY(-1px); }
.detail-close:active { transform: translateY(0) scale(0.96); }

.detail-body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline-strong) transparent;
}

/* Quickstats row — Status / Response / Type / Last check */
.detail-quickstats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.detail-quickstats .qs {
  background: rgba(255, 255, 255, 0.04);
  border-radius: 10px;
  padding: 9px 12px;
}
.detail-quickstats .qs-label {
  font-size: 0.6rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.detail-quickstats .qs-value {
  font-size: 0.92rem;
  color: var(--text);
  margin-top: 2px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-feature-settings: "tnum";
}

/* Diagnostics grid — Platform / SSL / CDN / Hosting / Ping / Domain */
.detail-diag-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.detail-diag-grid .diag-cell {
  background: rgba(255, 255, 255, 0.04);
  border-radius: 10px;
  padding: 9px 12px;
}
.detail-diag-grid .diag-cell-wide { grid-column: 1 / -1; }
.detail-diag-grid .diag-label {
  font-size: 0.6rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.detail-diag-grid .diag-value {
  font-size: 0.85rem;
  color: var(--text);
  margin-top: 2px;
  word-break: break-all;
}
.detail-diag-grid .diag-list {
  margin-top: 4px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.detail-body::-webkit-scrollbar { width: 6px; }
.detail-body::-webkit-scrollbar-thumb { background: var(--hairline-strong); border-radius: 3px; }

.detail-section-title {
  display: block;
  font-size: 0.65rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-bottom: 8px;
}

/* "Fetch DNS" action button — sits inline in the panel body */
.detail-action {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  background: rgba(255, 255, 255, 0.06);
  border: none;
  border-radius: var(--r-pill);
  color: var(--text);
  font-size: 0.78rem;
  font-weight: var(--w-regular);
  cursor: pointer;
  align-self: flex-start;
  font-family: inherit;
  transition: background 0.15s var(--ease-quick);
}
.detail-action:hover  { background: rgba(255, 255, 255, 0.10); }
.detail-action:disabled {
  opacity: 0.55;
  cursor: progress;
}
.detail-action svg { opacity: 0.75; flex-shrink: 0; }

.detail-dns-result {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.detail-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.detail-mono {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.76rem;
  color: var(--text);
  background: none;
  padding: 4px 0;
  border-radius: 0;
}

.detail-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.76rem;
}
.detail-table th {
  text-align: left;
  font-size: 0.6rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  padding: 6px 10px 6px 0;
  border-bottom: 1px solid var(--hairline);
}
.detail-table td {
  padding: 6px 10px 6px 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
  vertical-align: middle;
}
.detail-table tr:last-child td { border-bottom: none; }
.detail-table .dot { display: inline-block; margin-right: 6px; vertical-align: middle; }

/* ── Mapbox overrides — kill the default light-mode chrome ──────────── */
.mapboxgl-ctrl-attrib,
.mapboxgl-ctrl-logo {
  opacity: 0.35;
  filter: invert(1) hue-rotate(180deg);
}
.mapboxgl-canvas:focus { outline: none; }

/* ════════════════════════════════════════════════════════════════════════
   Map markers — frosted-glass disc + centered icon. Three variants:

     .glass-pin-user     — operator's own location (you)
     .glass-pin-monitor  — each monitored service. Status colour drives
                           the dashed outer ring (.ok/.down/.warn/etc).
     .glass-pin-visitor  — GA realtime user clusters. White, sized by
                           user count.

   Critical positioning rule: do NOT set `position` on .glass-pin or
   any class on the marker root. Mapbox sets `position: absolute` via
   .mapboxgl-marker for projection — overriding it parks every pin at
   the map's (0,0). Dashed ring is on a child, not a pseudo-element on
   the root, for the same reason.
   ════════════════════════════════════════════════════════════════════════ */
.glass-pin {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(255,255,255,0.16);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border: 1px solid rgba(255,255,255,0.4);
  box-shadow:
    0 4px 12px rgba(0,0,0,0.45),
    inset 0 1px 0 rgba(255,255,255,0.25);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255,255,255,0.95);
  cursor: pointer;
  transition: transform 0.15s var(--ease-quick), box-shadow 0.15s var(--ease-quick);
}
.glass-pin svg { display: block; }
.glass-pin:hover {
  transform: scale(1.12);
  box-shadow:
    0 6px 18px rgba(0,0,0,0.55),
    inset 0 1px 0 rgba(255,255,255,0.3);
}

/* Status tints — applied as a subtle inner glow rather than a hard
   background colour, so the glass aesthetic is preserved while the
   status still reads at a glance. */
.glass-pin.ok          { box-shadow: 0 4px 12px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.25), 0 0 0 1px rgba(52,209,122,0.45); }
.glass-pin.down        { box-shadow: 0 4px 12px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.25), 0 0 0 1px rgba(255,77,79,0.55), 0 0 16px rgba(255,77,79,0.35); }
.glass-pin.warn        { box-shadow: 0 4px 12px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.25), 0 0 0 1px rgba(255,159,67,0.5),  0 0 14px rgba(255,159,67,0.3); }
.glass-pin.maintenance { box-shadow: 0 4px 12px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.25), 0 0 0 1px rgba(93,168,255,0.5),  0 0 14px rgba(93,168,255,0.3); }

/* User (operator) pin — slightly larger so it stands out from monitor
   pins; subtle warm tint to differentiate without breaking the glass
   look. */
.glass-pin-user {
  width: 40px;
  height: 40px;
  background: rgba(255,255,255,0.20);
  border-color: rgba(255,255,255,0.55);
}

/* Count badge — appears top-right of a monitor pin when multiple
   monitors share the same location (multiple sites on one server).
   Mapbox sets position:absolute on the pin root so this child can
   position absolutely against it. */
.glass-pin-count {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: rgba(0, 0, 0, 0.85);
  color: #ffffff;
  font-size: 0.65rem;
  font-weight: var(--w-medium);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  line-height: 18px;
  text-align: center;
  border: 1px solid rgba(255,255,255,0.4);
  pointer-events: none;
  box-sizing: border-box;
}

/* ════════════════════════════════════════════════════════════════════════
   FOCUS MARKER — appears on the map when the user clicks a monitor card.
   Animated dashed ring + glass icon disc with a status check / x / etc.
   ════════════════════════════════════════════════════════════════════════ */
.glass-focus-marker {
  position: relative;
  width: 96px;
  height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.glass-focus-marker .ring {
  position: absolute;
  inset: 0;
  border: 1px dashed rgba(255, 255, 255, 0.65);
  border-radius: 50%;
  opacity: 0;
  animation:
    glass-focus-ring-in   0.45s var(--ease) forwards,
    glass-focus-ring-spin 38s   linear      0.45s infinite;
}
@keyframes glass-focus-ring-in {
  from { transform: scale(0.55); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
@keyframes glass-focus-ring-spin {
  to { transform: rotate(360deg); }
}

.glass-focus-marker .icon {
  position: relative;
  z-index: 2;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: var(--text);
  transform: scale(0.6);
  opacity: 0;
  animation: glass-focus-icon-in 0.4s var(--ease) 0.1s forwards;
}
/* Inner solid dot, coloured by status. No SVG icon. */
.glass-focus-marker .icon::after {
  content: '';
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 12px currentColor;
}
.glass-focus-marker .icon.ok   { color: var(--ok); }
.glass-focus-marker .icon.down { color: var(--down); }
.glass-focus-marker .icon.warn { color: var(--warn); }
.glass-focus-marker .icon.maintenance { color: var(--info); }
.glass-focus-marker .icon.pending { color: var(--text-tertiary); }

@keyframes glass-focus-icon-in {
  to { transform: scale(1); opacity: 1; }
}


/* ════════════════════════════════════════════════════════════════════════
   CALLOUT CARD — floats next to the focus marker on the map.
   Shows monitor name, status pill, and the latest response time.
   ════════════════════════════════════════════════════════════════════════ */
.glass-callout {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 18px;
  padding: 13px 18px 14px;
  min-width: 190px;
  max-width: 240px;
  box-shadow: var(--shadow-card);
  font-family: var(--font);
  pointer-events: auto;
  /* DO NOT use `transform` here — Mapbox uses `transform` to position the
     marker at its lat/lng, and any transform on the marker element clobbers
     that. Only animate `opacity`. */
  opacity: 0;
  animation: glass-callout-in 0.35s var(--ease) 0.18s forwards;
}
@keyframes glass-callout-in {
  to { opacity: 1; }
}
.glass-callout-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.glass-callout-title {
  font-size: 0.92rem;
  font-weight: var(--w-medium);
  color: var(--text);
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.glass-callout-sub {
  font-size: 0.78rem;
  color: var(--text-secondary);
  margin-top: 6px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.glass-callout-sub .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-tertiary);
}
.glass-callout-sub .dot.ok    { background: var(--ok); }
.glass-callout-sub .dot.down  { background: var(--down); }
.glass-callout-sub .dot.warn  { background: var(--warn); }
.glass-callout-sub .dot.maintenance { background: var(--info); }
.glass-callout-value {
  font-size: 1.7rem;
  font-weight: var(--w-light);
  color: var(--text);
  margin-top: 8px;
  letter-spacing: -0.025em;
  line-height: 1;
  font-feature-settings: "tnum";
}
.glass-callout-value .unit {
  font-size: 0.78rem;
  color: var(--text-secondary);
  margin-left: 3px;
  font-weight: var(--w-regular);
}


/* (Old .glass-pin.you styles removed — replaced by .glass-pin-user
   in the new glass-pin block above.) */


/* ════════════════════════════════════════════════════════════════════════
   LOGIN PAGE
   Same shell as the dashboard, but the topbar + rail start hidden and
   slide in after a successful sign-in. The login form sits centered on
   top of the map and fades out as the chrome animates in.
   ════════════════════════════════════════════════════════════════════════ */

/* Hide the dashboard chrome until the entry animation runs */
body.login-page .topbar {
  opacity: 0;
  transform: translateY(-100%);
  pointer-events: none;
}
body.login-page .rail {
  opacity: 0;
  transform: translateX(-100%);
  pointer-events: none;
}

body.login-page .topbar.entering {
  animation: glass-slide-down 0.65s var(--ease) forwards;
}
body.login-page .rail.entering {
  animation: glass-slide-in 0.75s var(--ease) 0.18s forwards;
}

@keyframes glass-slide-down {
  to { opacity: 1; transform: translateY(0); }
}
@keyframes glass-slide-in {
  to { opacity: 1; transform: translateX(0); }
}

/* Login overlay — centred over the map, on top of everything */
.login-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 20;
  padding: 24px;
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
}
.login-overlay.fade-out {
  opacity: 0;
  transform: scale(0.96);
  pointer-events: none;
}

.login-card {
  width: 360px;
  max-width: 100%;
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: 22px;
  padding: 30px 30px 28px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
}
.login-card[hidden] { display: none; }

.login-title {
  font-size: 1.55rem;
  font-weight: var(--w-light);
  letter-spacing: -0.02em;
  color: var(--text);
  margin-bottom: 0;
  text-align: center;
}
.login-sub {
  font-size: 0.85rem;
  color: var(--text-secondary);
  margin-bottom: 10px;
  text-align: center;
}

.login-input {
  width: 100%;
  padding: 12px 14px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 12px;
  color: var(--text);
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: var(--w-regular);
  outline: none;
  transition: background 0.15s, border-color 0.15s;
}
.login-input::placeholder { color: var(--text-tertiary); }
.login-input:focus {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.24);
}
.login-input-totp {
  text-align: center;
  letter-spacing: 0.4em;
  font-size: 1.2rem;
  font-feature-settings: "tnum";
}

.login-button {
  width: 100%;
  padding: 12px;
  margin-top: 4px;
  background: rgba(255, 255, 255, 0.14);
  border: none;
  border-radius: 12px;
  color: var(--text);
  font-family: inherit;
  font-size: 0.92rem;
  font-weight: var(--w-medium);
  cursor: pointer;
  transition: background 0.15s var(--ease-quick);
}
.login-button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.22); }
.login-button:disabled { opacity: 0.55; cursor: progress; }

/* Secondary action — passkey sign-in. Lower visual weight than the
   primary password "Sign In" button so password remains the default
   path for users who don't have a passkey set up. */
.login-button-secondary {
  background: transparent;
  border: 1px solid rgba(255, 255, 255, 0.18);
}
.login-button-secondary:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.30);
}

/* Divider between password and passkey actions. */
.login-or {
  position: relative;
  text-align: center;
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin: 6px 0;
}
.login-or::before,
.login-or::after {
  content: '';
  position: absolute;
  top: 50%;
  width: calc(50% - 24px);
  height: 1px;
  background: rgba(255, 255, 255, 0.10);
}
.login-or::before { left: 0; }
.login-or::after  { right: 0; }

.login-error {
  background: rgba(255, 77, 79, 0.12);
  border: 1px solid rgba(255, 77, 79, 0.30);
  color: var(--down);
  padding: 10px 14px;
  border-radius: 10px;
  font-size: 0.82rem;
  margin-bottom: 4px;
}


/* ── Loading state ──────────────────────────────────────────────────── */
.skeleton {
  background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.04) 50%, transparent 100%);
  background-size: 200% 100%;
  animation: shimmer 1.6s infinite var(--ease-quick);
  border-radius: 4px;
}
@keyframes shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}


/* ── Utility ────────────────────────────────────────────────────────── */
.muted { color: var(--text-tertiary); }
.tabular { font-feature-settings: "tnum"; }


/* The gradient stop is a registered custom property so it can be
   transitioned smoothly. CSS can't animate `mask-image` directly, but
   it CAN animate a typed custom-property the gradient depends on. */
@property --fade-stop {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

/* `.cards-fade` is its own scroll container so the mask stays anchored
   to its box (doesn't move with the cards). The mask is always present;
   --fade-stop animates between 0% (no fade) at the top and 5% once
   scrolled, so the dissolve effect eases in and out. */
.cards-fade {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline-strong) transparent;

  --fade-stop: 0%;
  -webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0) var(--fade-stop));
          mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgb(0, 0, 0) var(--fade-stop));
  transition: --fade-stop 0.35s var(--ease);
}
.cards-fade::-webkit-scrollbar { width: 6px; }
.cards-fade::-webkit-scrollbar-thumb { background: var(--hairline-strong); border-radius: 3px; }

.cards-fade.is-scrolled {
  --fade-stop: 5%;
}


/* ════════════════════════════════════════════════════════════════════════
   TAB PANELS — one per top-bar tab. JS toggles `hidden`.
   `flex: 1` lets the active panel fill the rail; `min-height: 0` lets a
   child .cards-fade actually shrink and scroll instead of overflowing.
   ════════════════════════════════════════════════════════════════════════ */
.tab-panel {
  display: flex;
  flex-direction: column;
  gap: 14px;
  flex: 1;
  min-height: 0;
}
.tab-panel[hidden] { display: none; }

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 4px;
}
.panel-title {
  font-size: 1.4rem;
  font-weight: var(--w-light);
  letter-spacing: -0.02em;
  color: var(--text);
}

.empty-state {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border-radius: var(--r-tile);
  padding: 32px 24px;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-secondary);
}


/* ════════════════════════════════════════════════════════════════════════
   GLASS BUTTONS — reusable across modals, tabs, action rows.
   ════════════════════════════════════════════════════════════════════════ */
.btn-glass {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: rgba(255, 255, 255, 0.06);
  border: none;
  border-radius: var(--r-pill);
  color: var(--text);
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: var(--w-regular);
  cursor: pointer;
  transition: background 0.15s var(--ease-quick);
}
.btn-glass:hover { background: rgba(255, 255, 255, 0.12); }
.btn-glass:disabled { opacity: 0.55; cursor: progress; }

.btn-glass.btn-primary { background: rgba(255, 255, 255, 0.16); }
.btn-glass.btn-primary:hover { background: rgba(255, 255, 255, 0.24); }

.btn-glass.btn-danger { color: var(--down); }
.btn-glass.btn-danger:hover { background: rgba(255, 77, 79, 0.18); }

.btn-glass.btn-sm {
  padding: 6px 11px;
  font-size: 0.75rem;
}


/* ════════════════════════════════════════════════════════════════════════
   FILTER CHIPS — segmented filter bar (Monitors tab, etc.)
   Sits above the .cards-fade scroll container, so it's naturally fixed.
   ════════════════════════════════════════════════════════════════════════ */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 4px 0 8px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: rgba(255, 255, 255, 0.04);
  border: none;
  border-radius: var(--r-pill);
  color: var(--text-secondary);
  font-family: inherit;
  font-size: 0.78rem;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}
.chip:hover  { background: rgba(255, 255, 255, 0.08); color: var(--text); }
.chip.active { background: rgba(255, 255, 255, 0.14); color: var(--text); }
.chip-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 18px;
  padding: 0 6px;
  font-size: 0.68rem;
  font-feature-settings: "tnum";
  border-radius: var(--r-pill);
  background: rgba(0, 0, 0, 0.25);
  color: var(--text-secondary);
}
.chip.active .chip-count { background: rgba(0, 0, 0, 0.35); color: var(--text); }


/* Per-monitor inline action row (Monitors tab) */
.monitor-actions {
  display: flex;
  gap: 6px;
  margin-top: 12px;
  flex-wrap: wrap;
}

/* Group header — spans the full width of the .monitor-grid */
.monitor-grid .group-header {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 4px 4px;
  font-size: 0.74rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.monitor-grid .group-header:not(:first-child) {
  margin-top: 14px;
}
.group-color-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}
.group-name { line-height: 1; }
.group-name.muted { color: var(--text-tertiary); }
.group-count {
  margin-left: auto;
  font-size: 0.7rem;
  font-weight: var(--w-regular);
  letter-spacing: 0;
  color: var(--text-tertiary);
  text-transform: none;
  font-feature-settings: "tnum";
}

/* Optional description on client cards */
.client-desc {
  font-size: 0.78rem;
  color: var(--text-secondary);
  margin: 8px 0 6px;
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Incident card extras */
.incident-desc {
  font-size: 0.78rem;
  color: var(--text-secondary);
  margin: 6px 0 0;
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.incident-type-badge {
  font-size: 0.62rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #B594E5;
  background: rgba(175, 82, 222, 0.18);
  padding: 3px 8px;
  border-radius: 999px;
  flex-shrink: 0;
}

/* Incident edit-modal timeline.
   Appears at the top of the Edit Incident form, showing prior updates
   as a vertical list. Each row has a status pill, a relative time, and
   the message body underneath. Capped in height so a chatty incident
   doesn't push the form fields off-screen. */
.incident-timeline {
  margin: 0 0 4px 0;
  padding: 12px 14px;
  border-radius: 12px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  max-height: 280px;
  overflow-y: auto;
}
.incident-timeline-head {
  font-size: 0.7rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 10px;
}
.incident-timeline-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.incident-timeline-item {
  border-left: 2px solid rgba(255,255,255,0.12);
  padding: 0 0 0 12px;
}
.incident-timeline-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}
.incident-timeline-time {
  font-size: 0.72rem;
  color: var(--text-secondary);
}
.incident-timeline-msg {
  font-size: 0.82rem;
  color: var(--text-primary);
  line-height: 1.45;
  white-space: pre-wrap;
  word-wrap: break-word;
}
.incident-timeline-msg.muted {
  color: var(--text-secondary);
  font-style: italic;
}
.field-hint {
  display: block;
  margin-top: 4px;
  font-size: 0.7rem;
  color: var(--text-secondary);
}

/* Status pill — maintenance variant */
.status-pill.maintenance {
  color: #B594E5;
  border-color: rgba(175, 82, 222, 0.30);
}
.dot.maintenance { background: #B594E5; }

/* Client Detail aggregate chart card */
.client-chart-card { margin-top: 14px; margin-bottom: 14px; }


/* Back arrow on the Client Detail panel */
.btn-back {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.92);
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.20);
  box-shadow:
    0 4px 14px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.15);
  margin-right: 8px;
  flex-shrink: 0;
  transition: background 0.15s, color 0.15s, transform 0.12s var(--ease-quick);
}
.btn-back:hover { background: rgba(255, 255, 255, 0.18); color: var(--text); transform: translateY(-1px); }

/* Client Detail summary stats strip */
.client-detail-summary { padding: 0 4px; }
.client-detail-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin-bottom: 8px;
}
/* On narrow viewports four columns get cramped — fall back to two */
@media (max-width: 720px) {
  .client-detail-stats { grid-template-columns: repeat(2, 1fr); }
}
.client-detail-stats .stat-block {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: 12px;
  padding: 10px 12px;
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
}
.client-detail-stats .stat-label {
  font-size: 0.62rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.client-detail-stats .stat-value {
  font-size: 1rem;
  font-weight: var(--w-medium);
  color: var(--text);
  margin-top: 4px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-feature-settings: "tnum";
}


/* ════════════════════════════════════════════════════════════════════════
   MODAL — single overlay reused for forms (Add/Edit Monitor, etc.)
   ════════════════════════════════════════════════════════════════════════ */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, 0.52);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s var(--ease-quick);
}
.modal-overlay.open {
  opacity: 1;
  pointer-events: auto;
}
.modal-overlay[hidden] { display: none; }

.modal {
  position: relative;
  width: 480px;
  max-width: 100%;
  max-height: calc(100vh - 96px);
  display: flex;
  flex-direction: column;
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: var(--glass-border);
  border-radius: 22px;
  box-shadow:
    inset 0 1px 0 var(--glass-edge-light),
    var(--glass-shadow-lift);
  transform: scale(0.96);
  transition: transform 0.2s var(--ease);
}
.modal-overlay.open .modal { transform: scale(1); }

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 22px 12px;
}
.modal-title {
  font-size: 1.15rem;
  font-weight: var(--w-medium);
  letter-spacing: -0.015em;
  color: var(--text);
}
.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.92);
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.20);
  box-shadow:
    0 4px 14px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.15);
  z-index: 2;
  transition: background 0.15s, color 0.15s, transform 0.12s var(--ease-quick);
}
.modal-close:hover { background: rgba(255, 255, 255, 0.18); color: var(--text); transform: translateY(-1px); }
.modal-close:active { transform: translateY(0) scale(0.96); }

.modal-body {
  padding: 6px 22px 18px;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline-strong) transparent;
}

.modal-foot {
  padding: 14px 22px 18px;
  border-top: 1px solid var(--hairline);
}


/* ════════════════════════════════════════════════════════════════════════
   FORM CONTROLS — inputs, selects, toggle (used inside modal)
   ════════════════════════════════════════════════════════════════════════ */
.form-grid {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
}
.field > span {
  font-size: 0.72rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.field-row {
  display: flex;
  gap: 12px;
}

.input {
  width: 100%;
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 10px;
  color: var(--text);
  font-family: inherit;
  font-size: 0.88rem;
  outline: none;
  transition: background 0.15s, border-color 0.15s;
}
.input::placeholder { color: var(--text-tertiary); }
.input:focus {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.22);
}
textarea.input {
  resize: vertical;
  min-height: 60px;
  line-height: 1.45;
  font-family: inherit;
}
select.input {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none' stroke='%23ffffff99' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='1 1 5 5 9 1'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 32px;
}

.field-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  user-select: none;
}
.field-toggle input {
  width: 18px; height: 18px;
  accent-color: var(--text);
}
.field-toggle span {
  font-size: 0.85rem;
  color: var(--text);
}

.form-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}

.form-error {
  background: rgba(255, 77, 79, 0.10);
  border: 1px solid rgba(255, 77, 79, 0.30);
  color: var(--down);
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 0.78rem;
}

/* Panel-head action cluster (Manage Groups / Add Monitor) */
.panel-head-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* ── Groups manager (modal body) ─────────────────────────────────── */
.groups-modal { display: flex; flex-direction: column; gap: 12px; }
.group-list   { display: flex; flex-direction: column; gap: 8px; }
.group-row {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  gap: 8px;
  align-items: center;
}
.group-row .group-name { padding: 8px 10px; font-size: 0.85rem; }
.group-add {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 8px;
  align-items: center;
  padding-top: 12px;
  border-top: 1px solid var(--hairline);
}

/* ════════════════════════════════════════════════════════════════════════
   SETTINGS TAB
   Sections are .card with a section title + rows. Lists (Users,
   Notifications, Status Pages) use .settings-list-row pattern.
   ════════════════════════════════════════════════════════════════════════ */
.settings-stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-bottom: 24px;
}

.card-section-title {
  font-size: 0.78rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-bottom: 6px;
}

.card-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.card-section-head .card-section-title { margin-bottom: 0; }

/* Single-property rows (e.g. Username, Password) */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-top: 1px solid var(--hairline);
}
.settings-row:first-of-type,
.card-section-title + .settings-row { border-top: none; padding-top: 6px; }
.settings-row > .info { flex: 1; min-width: 0; }

.settings-label {
  font-size: 0.95rem;
  color: var(--text);
  font-weight: var(--w-regular);
}
.settings-sub {
  font-size: 0.78rem;
  color: var(--text-secondary);
  margin-top: 3px;
  /* `break-word` only breaks when an entire word would overflow (e.g.
     a long URL in a notification row). Natural sentences wrap at
     spaces, so help text doesn't get sliced mid-word. */
  overflow-wrap: break-word;
  word-break: normal;
}

/* Lists of items (Users, Notifications, Status Pages) */
.settings-list { display: flex; flex-direction: column; }
.settings-list-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-top: 1px solid var(--hairline);
}
.settings-list-row:first-of-type { border-top: none; padding-top: 4px; }
.settings-list-row .info    { flex: 1; min-width: 0; }
.settings-list-row .actions { display: flex; gap: 6px; flex-shrink: 0; }

.settings-empty {
  font-size: 0.85rem;
  color: var(--text-tertiary);
  padding: 14px 0 4px;
}

.settings-version {
  font-size: 0.78rem;
  color: var(--text-tertiary);
  font-feature-settings: "tnum";
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}

/* Make the About row clickable. We render it as a <button> so it's
   keyboard-focusable, but strip default button chrome so it lays out
   identically to a static .settings-row. */
.settings-row-btn {
  width: 100%;
  background: transparent;
  border: none;
  border-top: 1px solid var(--hairline);
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: background 0.15s ease;
}
.settings-row-btn:hover { background: rgba(255,255,255,0.03); }
.settings-row-btn:focus-visible {
  outline: 2px solid var(--accent, rgba(120,160,255,0.6));
  outline-offset: -2px;
  border-radius: 8px;
}

/* About modal body — logo + identity + key/value table.
   Lives inside a regular .modal so spacing follows the platform's
   modal grid. */
.about-modal-body { display: flex; flex-direction: column; gap: 18px; }
.about-hero {
  display: flex;
  align-items: center;
  gap: 16px;
}
.about-logo-img {
  width: 64px;
  height: 64px;
  object-fit: contain;
  flex-shrink: 0;
  filter: drop-shadow(0 4px 14px rgba(0,0,0,0.35));
}
.about-headings { display: flex; flex-direction: column; gap: 2px; }
.about-title {
  margin: 0;
  font-size: 1.25rem;
  font-weight: var(--w-medium);
  letter-spacing: -0.01em;
  color: var(--text);
}
.about-version {
  font-size: 0.78rem;
  color: var(--text-tertiary);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-feature-settings: "tnum";
}
.about-tagline {
  font-size: 0.82rem;
  color: var(--text-secondary);
  margin-top: 2px;
}
.about-meta {
  margin: 0;
  padding: 14px 16px;
  border-radius: 12px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.08);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.about-meta-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: 0.85rem;
}
.about-meta-row dt {
  width: 80px;
  flex-shrink: 0;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-tertiary);
}
.about-meta-row dd {
  margin: 0;
  color: var(--text);
  word-break: break-word;
}
.about-meta-row dd a { color: inherit; text-decoration: none; border-bottom: 1px dotted rgba(255,255,255,0.3); }
.about-meta-row dd a:hover { border-bottom-color: rgba(255,255,255,0.6); }
.about-credit {
  margin: 0;
  font-size: 0.78rem;
  color: var(--text-tertiary);
  text-align: center;
}


/* TOTP setup modal — QR + manual secret */
.totp-qr-wrap {
  display: flex;
  justify-content: center;
  padding: 6px 0;
}
.totp-qr {
  width: 180px;
  height: 180px;
  border-radius: 12px;
  background: white;        /* QR needs to be on white for scanners */
  padding: 10px;
}
.form-info {
  font-size: 0.82rem;
  color: var(--text-secondary);
  line-height: 1.5;
}


/* Native color input — restyle so it doesn't look default-OS */
.group-color {
  width: 36px;
  height: 36px;
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 10px;
  background: transparent;
  cursor: pointer;
  padding: 2px;
  /* Some browsers need this to honor padding on color inputs */
  -webkit-appearance: none;
  appearance: none;
}
.group-color::-webkit-color-swatch-wrapper { padding: 0; }
.group-color::-webkit-color-swatch { border: none; border-radius: 7px; }
.group-color::-moz-color-swatch    { border: none; border-radius: 7px; }


/* ════════════════════════════════════════════════════════════════════════
   TOAST — transient confirmation in the bottom-right.
   ════════════════════════════════════════════════════════════════════════ */
/* ── Notification channel picker (inside Edit Monitor modal) ────────── */
.notif-picker {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 220px;
  overflow-y: auto;
  padding: 4px;
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline-strong) transparent;
}
.notif-picker-empty {
  padding: 14px 12px;
  font-size: 0.82rem;
  color: var(--text-tertiary);
  text-align: center;
}
.notif-picker-empty a { color: var(--info); }
.notif-picker-empty a:hover { text-decoration: underline; }

.notif-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 9px;
  cursor: pointer;
  transition: background 0.12s;
}
.notif-row:hover { background: rgba(255, 255, 255, 0.05); }
.notif-row input[type="checkbox"] {
  flex-shrink: 0;
  width: 16px; height: 16px;
  accent-color: var(--info);
  cursor: pointer;
}
.notif-row-tag {
  flex-shrink: 0;
  padding: 2px 7px;
  border-radius: 5px;
  font-size: 0.62rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.06em;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-secondary);
}
.notif-row-tag-discord { background: rgba(88, 101, 242, 0.18); color: #aab1f8; }
.notif-row-tag-slack   { background: rgba( 74, 21, 75, 0.18); color: #d6a8d8; }
.notif-row-tag-email   { background: rgba( 93,168,255, 0.18); color: #b8d6ff; }
.notif-row-tag-webhook { background: rgba(255,255,255,0.10); color: var(--text-secondary); }

.notif-row-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.notif-row-name {
  font-size: 0.82rem;
  color: var(--text);
  font-weight: var(--w-medium);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.notif-row-sub {
  font-size: 0.7rem;
  color: var(--text-tertiary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}


/* ── Status-page monitor picker (inside Add/Edit Status Page modal) ── */
.sp-mon-field { gap: 8px; }
.sp-mon-help {
  font-size: 0.74rem;
  color: var(--text-tertiary);
  margin: -2px 0 4px;
  letter-spacing: 0;
  text-transform: none;
  font-weight: var(--w-regular);
}

.sp-mon-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0;
  margin: 0;
}
.sp-mon-empty {
  padding: 16px 14px;
  font-size: 0.82rem;
  color: var(--text-tertiary);
  text-align: center;
  background: rgba(255,255,255,0.03);
  border-radius: 12px;
  border: 1px dashed var(--hairline);
}

.sp-mon-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  cursor: grab;
  transition: background 0.15s var(--ease-quick), transform 0.15s var(--ease-quick), border-color 0.15s;
  user-select: none;
}
.sp-mon-row:hover { background: rgba(255,255,255,0.07); }
.sp-mon-row.dragging { opacity: 0.5; cursor: grabbing; }
.sp-mon-row.drop-above { box-shadow: 0 -2px 0 0 var(--info) inset; border-top-color: var(--info); }
.sp-mon-row.drop-below { box-shadow: 0  2px 0 0 var(--info) inset; border-bottom-color: var(--info); }

.sp-mon-handle {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  flex-shrink: 0;
  cursor: grab;
}
.sp-mon-row.dragging .sp-mon-handle,
.sp-mon-handle:active { cursor: grabbing; }

.sp-mon-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--text-tertiary);
}
.sp-mon-dot.ok   { background: var(--ok); }
.sp-mon-dot.down { background: var(--down); }
.sp-mon-dot.warn { background: var(--warn); }

.sp-mon-info { flex: 1; min-width: 0; }
.sp-mon-name {
  font-size: 0.86rem;
  color: var(--text);
  font-weight: var(--w-medium);
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sp-mon-sub {
  font-size: 0.74rem;
  color: var(--text-tertiary);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sp-mon-remove {
  width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  color: var(--text-tertiary);
  flex-shrink: 0;
  transition: background 0.15s, color 0.15s;
}
.sp-mon-remove:hover { background: rgba(255, 77, 79, 0.12); color: var(--down); }

/* Add-monitor button + popover */
.sp-mon-add-wrap { position: relative; margin-top: 4px; }
.sp-mon-add-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.82rem;
  padding: 8px 14px;
}
.sp-mon-add-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 280px;
  overflow-y: auto;
  z-index: 4;
  background: rgba(20,20,24,0.96);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  box-shadow: var(--shadow-card);
  padding: 6px;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline-strong) transparent;
}
.sp-mon-add-menu[hidden] { display: none; }
.sp-mon-add-group {
  padding: 8px 10px 4px;
  font-size: 0.66rem;
  font-weight: var(--w-medium);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-tertiary);
}
.sp-mon-add-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border-radius: 8px;
  transition: background 0.12s;
}
.sp-mon-add-item:hover { background: rgba(255,255,255,0.06); }
.sp-mon-add-empty {
  padding: 14px 10px;
  font-size: 0.78rem;
  color: var(--text-tertiary);
  text-align: center;
}


/* ── Alerts popup (bell-icon dialog) ────────────────────────────────── */
.alerts-popup-overlay { z-index: 110; }
.alerts-popup { width: 420px; max-width: 100%; }
.alerts-popup-body {
  padding: 6px 14px 18px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.alerts-popup-empty {
  padding: 24px 8px 18px;
  text-align: center;
  color: var(--text-tertiary);
  font-size: 0.85rem;
}
/* The shared alertSection markup uses .map-alerts-section* class names —
   they style themselves correctly inside any container, so no extra rules
   are needed for the items themselves. */


/* Stack container — newest toast appears at the bottom and animates up.
   `column-reverse` lets us appendChild() new toasts but visually stack
   them upwards so the most recent message stays nearest the viewport
   edge while older ones fade above. */
.toast-stack {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 200;
  display: flex;
  flex-direction: column-reverse;
  gap: 8px;
  pointer-events: none;
  align-items: center;
  max-width: calc(100vw - 32px);
}

.toast {
  background: var(--glass-strong);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  color: var(--text);
  padding: 10px 16px;
  border-radius: var(--r-pill);
  font-size: 0.82rem;
  box-shadow: var(--shadow-card);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s var(--ease-quick), transform 0.2s var(--ease-quick);
  pointer-events: auto;
  cursor: pointer;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.toast.show {
  opacity: 1;
  transform: translateY(0);
}
.toast-ok   { border-left: 3px solid var(--ok); }
.toast-down { border-left: 3px solid var(--down); }
.toast-warn { border-left: 3px solid var(--warn); }
.toast-info { border-left: 3px solid var(--info); }


/* ════════════════════════════════════════════════════════════════════════
   RESPONSIVE — tablet and mobile breakpoints.

   Strategy:
   • ≤1100px : tablet — detail panel becomes full-width; rail stays inset
   • ≤860px  : tighter rail + condensed topbar
   • ≤720px  : single-column mobile — rail becomes full-screen sheet,
               topbar collapses, detail panel becomes a bottom sheet,
               modals go full-screen
   • ≤480px  : small-phone density — bigger touch targets, smaller hero text
   ════════════════════════════════════════════════════════════════════════ */

/* ── Tablet ─────────────────────────────────────────────────────────── */
@media (max-width: 1100px) {
  /* Make the rail no wider than ~half the viewport so the map remains visible.
     The :has() rule overrides for client-detail. */
  .rail { width: min(560px, 60vw); }
  .rail:has(.tab-panel[data-tab="client-detail"]:not([hidden])) { width: min(700px, 75vw); }
}

/* ── Compact (tablet portrait + below) ──────────────────────────────────
   At ≤1024px the rail is wide enough that the floating `.map-right`
   panel on the right would overlap it. The JS relayout helper moves
   `.map-right` into the dashboard tab-panel; the rules below make sure
   it flows naturally and the rail switches to a single-scroll layout
   (no nested .cards-fade scroller) so touch scrolling feels native. */
@media (max-width: 1024px) {
  .map-right.map-right--inline {
    position: static;
    width: 100%;
    max-width: 100%;
    top: auto; right: auto;
    z-index: auto;
  }

  /* Single-scroll layout — the desktop architecture has a fixed header in
     each tab and an inner-scrolling .cards-fade. That feels broken on
     touch (two nested scroll containers). Flatten it: tab panels and
     .cards-fade size to their content, and the rail itself becomes the
     only scroll container. */
  .rail .tab-panel { flex: 0 0 auto; min-height: 0; }
  .rail .cards-fade {
    flex: 0 0 auto;
    min-height: 0;
    overflow: visible;
    -webkit-mask-image: none;
            mask-image: none;
  }
  /* Inline alerts panel needs to flow + scroll with the rail too, not
     cap itself with the desktop max-height. */
  .map-alerts-body { max-height: none; overflow: visible; }
}

/* ── Tighter tablet / large phone landscape ─────────────────────────── */
@media (max-width: 860px) {
  .topbar { gap: 16px; padding: 0 16px; }
  .topbar-actions { gap: 6px; }
  .tab { padding: 6px 12px; font-size: 0.78rem; }
  .rail { width: min(480px, 65vw); padding: 12px; }
  .rail:has(.tab-panel[data-tab="client-detail"]:not([hidden])) { width: min(600px, 80vw); }
  /* Hero numbers shrink so they don't dominate the narrower rail */
  .hero-value .num { font-size: 3rem; }
}

/* ── Mobile portrait ────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .app { height: 100dvh; }                    /* avoid mobile-Safari URL-bar jitter */

  /* Topbar — compact, scrollable nav, hidden brand text */
  .topbar {
    height: 56px;
    padding: 0 10px;
    gap: 8px;
    background: linear-gradient(180deg, rgba(13,13,16,0.78) 0%, rgba(13,13,16,0) 100%);
    backdrop-filter: var(--blur-light);
    -webkit-backdrop-filter: var(--blur-light);
  }
  .brand > span:not(.brand-mark) { display: none; }
  .topbar-spacer { display: none; }
  /* Hide the inline horizontal tabs on mobile — the dropdown takes over */
  .tabs { display: none; }
  .tabs-mobile { display: block; }
  .topbar-actions { gap: 4px; }
  .icon-btn { width: 32px; height: 32px; }
  .icon-btn svg { width: 16px; height: 16px; }

  /* Rail — full-screen sheet under the topbar */
  .rail,
  .rail:has(.tab-panel[data-tab="client-detail"]:not([hidden])) {
    width: 100%;
    max-width: 100%;
    margin: 0;
    border-radius: 0;
    top: 56px;
    height: calc(100dvh - 56px);
    padding: 12px;
  }

  /* Tile grid stays 2-col (labels are short) but tighter padding */
  .tile-grid { gap: 10px; }

  /* Cards trim padding so monitor cards fit neatly */
  .card { padding: 16px; border-radius: 18px; }
  .monitor { padding: 14px; border-radius: 16px; }

  /* Hero text scales for narrow viewport */
  .hero-value .num { font-size: 2.6rem; }
  .hero-value .unit { font-size: 0.95rem; }

  /* Operational efficiency chart shorter on mobile */
  .eff-chart { height: 160px !important; }

  /* Slide-up detail panel becomes a true bottom sheet */
  .detail-panel,
  .canvas:has(.tab-panel[data-tab="client-detail"]:not([hidden])) .detail-panel {
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    max-width: 100%;
    max-height: 85dvh;
    padding: 18px 16px 20px;
    border-radius: 22px 22px 0 0;
    /* Drag indicator sits above the title */
  }
  .detail-panel::before {
    content: '';
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 36px;
    height: 4px;
    border-radius: 2px;
    background: rgba(255,255,255,0.18);
  }
  .detail-head { padding-top: 8px; }

  /* Modal — full-screen sheet style */
  .modal-overlay { padding: 0; align-items: flex-end; }
  .modal {
    width: 100%;
    max-width: 100%;
    max-height: 92dvh;
    border-radius: 22px 22px 0 0;
  }
  .modal-head { padding: 16px 18px 10px; }
  .modal-body { padding: 4px 18px 14px; }
  .modal-foot { padding: 12px 18px 16px; }
  .field-row { flex-direction: column; gap: 14px; }

  /* Map alerts panel — single-scroll override now lives in the wider
     ≤1024px block below so tablets get the same flat layout. */


  /* Login card */
  .login-overlay { padding: 16px; }

  /* Toast moves up from the bottom edge so it's not hidden under home bar */
  .toast { bottom: 16px; max-width: calc(100vw - 32px); }
}

/* ── Small phone ────────────────────────────────────────────────────── */
@media (max-width: 480px) {
  .topbar { padding: 0 8px; gap: 6px; }
  .brand-mark { width: 22px; height: 22px; }
  .tab { padding: 5px 9px; font-size: 0.74rem; }
  .icon-btn { width: 30px; height: 30px; }

  .rail { padding: 10px; gap: 10px; }
  .card { padding: 14px; }
  .monitor { padding: 12px; }
  .tile-grid { gap: 8px; }

  .hero-value .num { font-size: 2.25rem; }
  .eff-chart { height: 140px !important; }

  /* Form inputs need a 16px+ font-size to prevent iOS auto-zoom on focus */
  .input, select.input, textarea.input { font-size: 16px; }
}
