/* CrowdBoard2 — Command Rail shell
 *
 * Theming: set data-theme on <html> (dark | darker | light).
 * All colors are CSS variables. Components use var(--*) only — never hard-coded hex.
 * Add a new theme by copying a [data-theme="…"] block and retuning tokens.
 *
 * Token roles:
 *   --accent*  — highlights (nav active, chips, focus, soft selection)
 *   --primary* — big CTAs (btn-primary, filter FAB)
 */

/* ── Structural tokens (shared across themes) ─ */

:root {
  --font: "Inter", system-ui, sans-serif;
  --font-display: "Outfit", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  /* R6: one dense mid rail on every page — never densifies when filters open. */
  --rail-w: 150px;
  --dash-display-max: 1800px;
  --context-pane-w: 268px;
  --chrome-handle-w: 14px;
  --bottom-h: calc(68px + var(--safe-b));
  /* Shape scale. Components may expose a local alias when their geometry is
     intentionally distinct, following the reference apps' component tokens. */
  --radius-compact: 2px;
  --radius-control: 3px;
  --radius-surface: 4px;
  --radius-panel: 5px;
  --radius-dialog: 6px;
  --radius-large: 4px; /* Dashboard, list tables, Metrics, and Settings panels */
  --radius-pill: 999px;
  --radius-round: 50%;
  /* Dense interface type scale. Larger display text remains component-owned. */
  --text-xx-small: 0.58rem;
  --text-micro: 0.62rem;
  --text-x-small: 0.68rem;
  --text-small: 0.72rem;
  --text-caption: 0.75rem;
  --text-control: 0.78rem;
  --text-compact: 0.8rem;
  --text-normal: 0.82rem;
  --text-medium: 0.9rem;

  --control-height-small: 2rem;
  --control-height-compact: 2.15rem;
  --control-height: 2.35rem;
  --tap-target: 44px;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --shadow-panel: 0 1px 2px rgba(0, 0, 0, 0.2);
  --transition-fast: 0.15s ease;
  --transition-chrome: 0.28s cubic-bezier(0.22, 1, 0.36, 1);
  /* Subtrees: list runs and Hub scenario members draw the same tree. */
  --tree-line: color-mix(in srgb, var(--muted) 48%, var(--panel));
  --tree-stroke: 1.5px;
  --tree-r: 0.45rem;
  --tree-stub: 0.8rem;
  --press-feedback-color: color-mix(in srgb, var(--text) 12%, transparent);
}

/* ── Theme: dark (default Command Rail) ─────── */

:root,
html[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0a0b10;
  --panel: #12141c;
  --panel-2: #181b26;
  --border: #262a38;
  --text: #f1f5f9;
  --muted: #8b93a7;
  /* Highlights / selection (nav, chips, focus) */
  --accent: #8b5cf6;
  --accent-text: #c4b5fd;
  --accent-soft: rgba(139, 92, 246, 0.18);
  /* Big CTAs — cool blue-steel (clear on near-black; not violet) */
  --primary: #3d6f9c;
  --primary-hover: #4d82b3;
  --primary-text: #f8fafc;
  --mark-brick: #6b5347;
  --mark-brick-edge: #2b1d16;
  --mark-tag: #f5f5f5;
  --mark-tag-edge: #1a0508;
  --success: #34d399;
  --danger: #fb7185;
  --warning: #fbbf24;
  --info: #22d3ee;
  --dot-idle: #475569;
  --overlay: rgba(18, 20, 28, 0.94);
  --focus-ring: rgba(139, 92, 246, 0.45);
  --nav-active: #c4b5fd;
}

/* ── Theme: darker (near-black / OLED-ish) ───── */

html[data-theme="darker"] {
  color-scheme: dark;
  --bg: #000000;
  --panel: #0a0a0c;
  --panel-2: #111114;
  --border: #1c1c22;
  --text: #e8eaed;
  --muted: #6b7280;
  --accent: #a78bfa;
  --accent-text: #ddd6fe;
  --accent-soft: rgba(167, 139, 250, 0.14);
  --primary: #4580ad;
  --primary-hover: #5692c0;
  --primary-text: #f8fafc;
  --mark-brick: #574036;
  --mark-brick-edge: #1f130d;
  --mark-tag: #f0f0f0;
  --mark-tag-edge: #050003;
  --success: #4ade80;
  --danger: #f87171;
  --warning: #fbbf24;
  --info: #22d3ee;
  --dot-idle: #374151;
  --overlay: rgba(0, 0, 0, 0.92);
  --focus-ring: rgba(167, 139, 250, 0.5);
  --nav-active: #ddd6fe;
}

/* ── Theme: light ───────────────────────────── */

html[data-theme="light"] {
  color-scheme: light;
  --bg: #f2f4f7;
  --panel: #ffffff;
  --panel-2: #edf1f5;
  --border: #d5dbe4;
  --text: #111827;
  /* Same slate hue and saturation, seven points darker: 8.3:1 on white and
     7.3:1 on the dimmest panel, so secondary text clears WCAG AAA on every
     light surface instead of only AA. Still clearly softer than --text, which
     is 17.7:1 — this reads as grey, not as body copy. */
  --muted: #434f60;
  --accent: #7c3aed;
  --accent-text: #6d28d9;
  --accent-soft: rgba(124, 58, 237, 0.12);
  /* Light can keep a stronger purple CTA — less harsh than on near-black */
  --primary: #7c3aed;
  --primary-hover: #6d28d9;
  --primary-text: #ffffff;
  --mark-brick: #c9a99a;
  --mark-brick-edge: #7a5a4a;
  --mark-tag: #ffffff;
  --mark-tag-edge: #7a5a4a;
  --success: #059669;
  --danger: #e11d48;
  --warning: #d97706;
  --info: #0284c7;
  --dot-idle: #7b8798;
  --overlay: rgba(255, 255, 255, 0.94);
  --focus-ring: rgba(124, 58, 237, 0.35);
  --nav-active: #6d28d9;
  --shadow-panel: 0 1px 2px rgba(15, 23, 42, 0.09);
}

/* ── Base ───────────────────────────────────── */

* { box-sizing: border-box; margin: 0; padding: 0; }

/* The scrollbar's width is reserved whether or not the page needs one, so a
   page that scrolls and a page that does not put their content in the same
   place. Without it every centred page shifts by half a scrollbar depending on
   how much data it happens to be showing — Alerts and the Dashboard sat 8px
   left of Decisions and Metrics. Only applies to classic scrollbars, so it
   reserves nothing on the overlay scrollbars phones use. */
html {
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;
}

body.app-body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

a { color: inherit; text-decoration: none; }

/* ── Shell ─────────────────────────────────── */

.app-shell {
  min-height: 100dvh;
  display: grid;
  grid-template-columns: 1fr;
  padding-bottom: var(--bottom-h);
}

.app-main-wrap {
  min-width: 0;
  display: flex;
  flex-direction: column;
  /* The shell already reserves this space for the fixed mobile navigation. */
  min-height: calc(100dvh - var(--bottom-h));
}

.app-main {
  flex: 1;
  min-width: 0;
  padding: var(--space-4);
  width: 100%;
  max-width: 1100px;
  margin-inline: auto;
}

/* ── Unified chrome (rail + optional filters) ─ */

.unified-chrome {
  display: none; /* mobile: bottom nav; desktop media enables */
  background: var(--panel);
  border-right: 1px solid var(--border);
  position: sticky;
  top: 0;
  height: 100dvh;
  min-width: 0;
  overflow: hidden;
  transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}

/* Idle handle carries both soft edges — hide chrome’s hard right border */
.unified-chrome:not(.has-filters) {
  border-right-color: transparent;
}

.unified-chrome.has-filters.filters-open {
  box-shadow: inset -1px 0 0 color-mix(in srgb, var(--accent) 18%, transparent);
}

.unified-chrome.context-pane-locked {
  --context-pane-w: 178px;
}

/* ── Desktop rail (R6 dense mid — constant on all pages) ─ */

.rail {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  background: transparent;
  border-right: 0;
  padding: 0.85rem 0.45rem 0.7rem;
  width: var(--rail-w);
  min-width: var(--rail-w);
  flex-shrink: 0;
  height: 100%;
  overflow: hidden;
  transition:
    background-color var(--transition-fast),
    border-color var(--transition-fast);
}

.rail-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.25rem 0.35rem 0.75rem;
  border-bottom: 1px solid var(--border);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.88rem;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.rail-mark {
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  display: inline-flex;
  border-radius: var(--radius-control);
}

.rail-mark svg {
  width: 100%;
  height: 100%;
  display: block;
}

.rail-nav {
  display: grid;
  gap: 0.12rem;
  flex: 1 1 auto;
  align-content: start;
  align-items: start;
  width: 100%;
  margin-top: 0.15rem;
}

.app-menu-item {
  display: flex;
  align-items: center;
  gap: 0.58rem;
  width: 100%;
  min-height: 2.25rem;
  padding: 0.42rem 0.52rem;
  border-radius: var(--radius-control);
  color: var(--muted);
  font-size: var(--text-control);
  font-weight: 520;
  line-height: 1.2;
  white-space: nowrap;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.app-menu-icon {
  width: 15px;
  height: 15px;
  flex: 0 0 15px;
  opacity: 0.84;
}

.rail-label {
  overflow: hidden;
  text-overflow: ellipsis;
}

.app-menu-item:hover {
  color: var(--text);
  background: color-mix(in srgb, var(--text) 4%, transparent);
}

.app-menu-item.on {
  color: var(--accent-text);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

.app-menu-item.on .app-menu-icon { opacity: 1; }

.rail-status {
  /* Shared lead column so dots line up with Settings/Theme icons */
  --rail-lead: 17px;
  --rail-pad-x: 0.45rem;
  --rail-gap: 0.45rem;
  margin-top: auto;
  border-top: 1px solid var(--border);
  padding-top: 0.65rem;
  display: grid;
  gap: 0.45rem;
  font-size: 0.7rem;
  color: var(--muted);
  flex-shrink: 0;
}

/* R6: status light + name, note on the line below — never side-by-side in the rail.
   Grid placement is resilient if .status-text is missing (e.g. error HTML). */
.status-row {
  display: flex;
  align-items: flex-start;
  gap: var(--rail-gap, 0.45rem);
  padding-left: var(--rail-pad-x, 0.45rem);
  padding-right: var(--rail-pad-x, 0.45rem);
  min-width: 0;
}

.status-text {
  display: grid;
  gap: 0.08rem;
  min-width: 0;
  flex: 1;
  overflow: hidden;
}

.status-name {
  font-weight: 650;
  color: color-mix(in srgb, var(--text) 78%, var(--muted));
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.status-note {
  opacity: 0.75;
  font-size: 0.66rem;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Rail: force name / note stack + clip overflow so the dense column never wraps sideways */
.rail-status .status-row {
  display: grid;
  grid-template-columns: var(--rail-lead) minmax(0, 1fr);
  column-gap: var(--rail-gap);
  row-gap: 0.08rem;
  align-items: start;
}

.rail-status .status-row > .dot {
  grid-column: 1;
  grid-row: 1;
}

.rail-status .status-row > .status-text {
  grid-column: 2;
  grid-row: 1;
  flex: unset;
}

/* Fallback when name/note are direct children of .status-row (missing .status-text) */
.rail-status .status-row > .status-name {
  grid-column: 2;
  grid-row: 1;
  min-width: 0;
}

.rail-status .status-row > .status-note {
  grid-column: 2;
  grid-row: 2;
  min-width: 0;
}

.dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-round);
  flex-shrink: 0;
  display: inline-block;
}

/* Rail: fixed lead column (same as Settings/Theme icons) with the 8px light
   centered on the "CrowdSec" / "Sync" name line. */
.rail-status .status-row > .dot {
  width: var(--rail-lead);
  height: calc(0.7rem * 1.25); /* match .status-name line box */
  margin: 0;
  border-radius: 0;
  background: transparent !important;
  box-shadow: none !important;
  position: relative;
  flex-shrink: 0;
}
.rail-status .status-row > .dot::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: var(--radius-round);
  background: var(--dot-idle);
}
.rail-status .status-row > .dot-ok::after {
  background: var(--success);
  box-shadow: 0 0 8px color-mix(in srgb, var(--success) 55%, transparent);
}
.rail-status .status-row > .dot-live::after {
  background: var(--info);
  box-shadow: 0 0 8px color-mix(in srgb, var(--info) 55%, transparent);
}
.rail-status .status-row > .dot-warn::after {
  background: var(--warning);
  box-shadow: 0 0 8px color-mix(in srgb, var(--warning) 45%, transparent);
}
.rail-status .status-row > .dot-bad::after {
  background: var(--danger);
  box-shadow: 0 0 8px color-mix(in srgb, var(--danger) 45%, transparent);
}

.tooltip {
  position: fixed;
  z-index: 1100;
  max-width: min(19rem, calc(100vw - 20px));
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 0.45rem;
  background: var(--panel-2);
  color: var(--text);
  box-shadow: var(--shadow-panel);
  font-size: var(--text-caption);
  line-height: 1.4;
  overflow-wrap: anywhere;
  pointer-events: none;
}

.tooltip[hidden] { display: none; }
.rail-status .status-row > .dot-muted::after {
  background: var(--dot-idle);
  box-shadow: none;
}

.dot-muted { background: var(--dot-idle); }
.dot-ok {
  background: var(--success);
  box-shadow: 0 0 8px color-mix(in srgb, var(--success) 55%, transparent);
}
.dot-live {
  background: var(--info);
  box-shadow: 0 0 8px color-mix(in srgb, var(--info) 55%, transparent);
}
.dot-warn {
  background: var(--warning);
  box-shadow: 0 0 8px color-mix(in srgb, var(--warning) 45%, transparent);
}
.dot-bad {
  background: var(--danger);
  box-shadow: 0 0 8px color-mix(in srgb, var(--danger) 45%, transparent);
}

/* Hidden cable sync marker (turbo frame target for broadcasts) */
.sync-indicator-marker,
#sync-indicator {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  pointer-events: none;
}

/* ── Theme control (rail + mobile) ─────────── */

.rail-divider {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 0.15rem 0 0;
  width: 100%;
}

/* Desktop: Settings lives with theme, not primary rail nav */
.rail-settings-link {
  display: flex;
  align-items: center;
  gap: var(--rail-gap, 0.45rem);
  padding: 0.4rem var(--rail-pad-x, 0.45rem);
  border-radius: var(--radius-control);
  border: 0;
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 600;
  text-decoration: none;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.rail-settings-link:hover {
  color: var(--text);
  background: var(--panel-2);
}

.rail-settings-link.on {
  color: var(--nav-active);
  background: var(--accent-soft);
}

.rail-settings-icon {
  width: var(--rail-lead, 17px);
  height: var(--rail-lead, 17px);
  box-sizing: border-box;
  padding: 3px;
  flex-shrink: 0;
  opacity: 0.9;
}

.theme-control {
  position: relative;
  display: grid;
  gap: 0.35rem;
}

.theme-picker-btn {
  display: flex;
  align-items: center;
  gap: var(--rail-gap, 0.45rem);
  width: 100%;
  border: 0;
  background: transparent;
  color: var(--muted);
  border-radius: var(--radius-control);
  padding: 0.4rem var(--rail-pad-x, 0.45rem);
  font-family: inherit;
  font-size: 0.7rem;
  font-weight: 600;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.theme-picker-btn:hover {
  color: var(--text);
  background: var(--panel-2);
}

.theme-picker-icon {
  width: var(--rail-lead, 17px);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-medium);
  line-height: 1;
}

.theme-picker-name { flex: 1; text-align: left; }

.theme-popover {
  position: absolute;
  bottom: calc(100% + 0.4rem);
  left: 0;
  right: 0;
  z-index: 80;
  display: grid;
  gap: 0.15rem;
  padding: 0.35rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-panel);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.04);
}

.theme-popover[hidden] { display: none; }

.theme-popover-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  border: 0;
  background: transparent;
  color: var(--text);
  border-radius: var(--radius-control);
  padding: 0.4rem 0.5rem;
  font-family: inherit;
  font-size: var(--text-caption);
  font-weight: 500;
  cursor: pointer;
  text-align: left;
}

.theme-popover-item:hover {
  background: var(--panel-2);
}

.theme-popover-item[aria-pressed="true"] {
  color: var(--accent-text);
  background: var(--accent-soft);
}

.theme-popover-item[aria-pressed="true"]::after {
  content: "✓";
  margin-left: auto;
  font-weight: 600;
}

.theme-popover-swatch {
  width: 14px;
  height: 14px;
  border-radius: var(--radius-round);
  border: 1px solid var(--border);
  flex-shrink: 0;
}

.theme-popover-swatch[data-swatch="system"] {
  background:
    linear-gradient(135deg, #0a0b10 50%, #f4f5f7 50%);
}
.theme-popover-swatch[data-swatch="dark"]   { background: linear-gradient(135deg, #12141c, #0a0b10); }
.theme-popover-swatch[data-swatch="darker"] { background: linear-gradient(135deg, #0a0a0c, #000000); }
.theme-popover-swatch[data-swatch="light"]  { background: linear-gradient(135deg, #ffffff, #f4f5f7); }

/* ── Mobile top ────────────────────────────── */

/* An iPhone home-screen app draws under its translucent status bar, so the
   header reaches up behind it and keeps its content below. */
.top-mobile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: calc(0.75rem + var(--safe-t)) 1rem 0.75rem;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 40;
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

.top-mobile-brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-weight: 700;
}

.pending-operation-spinner {
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
  border: 2px solid color-mix(in srgb, var(--info) 24%, transparent);
  border-top-color: var(--info);
  border-radius: var(--radius-pill);
  animation: status-spinner-spin 0.75s linear infinite;
}

/* Settings → Appearance: compact chip row */
/* Clock times: ClockHelper writes "16:00" and "4:00 PM" side by side and
   <html data-hour-cycle> (set before paint) picks one. 24-hour without it. */
.clock-12 { display: none; }
html[data-hour-cycle="h12"] .clock-12 { display: inline; }
html[data-hour-cycle="h12"] .clock-24 { display: none; }

.settings-appearance-options { display: flex; flex-wrap: wrap; gap: 0.4rem; }

.settings-appearance-options .compact-action { gap: 0.4rem; }
/* Date format's four choices don't fit a narrow column in one row. */
.settings-appearance-options .compact-action-bar { flex: 0 1 auto; flex-wrap: wrap; min-width: 0; }

.settings-appearance-options .theme-popover-swatch { width: 12px; height: 12px; }

/* ── Bottom nav ────────────────────────────── */

.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  height: var(--bottom-h);
  padding: 0.3rem 0.35rem calc(var(--safe-b) + 0.3rem);
  background: var(--overlay);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-top: 1px solid var(--border);
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}

.bottom-nav a {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  font-size: 0.6rem;
  font-weight: 600;
  color: var(--muted);
  border-radius: var(--radius-surface);
}

.bottom-nav a.on { color: var(--nav-active); }
/* A tapped tab whose page is still loading (lib/navigation_pending.js): it
   takes the highlight from the page on screen. */
html[data-navigation-tab] .bottom-nav a.on { color: var(--muted); }
html[data-navigation-tab="dashboard"] .bottom-nav a[data-nav-tab="dashboard"],
html[data-navigation-tab="decisions"] .bottom-nav a[data-nav-tab="decisions"],
html[data-navigation-tab="alerts"] .bottom-nav a[data-nav-tab="alerts"],
html[data-navigation-tab="bouncers"] .bottom-nav a[data-nav-tab="bouncers"],
html[data-navigation-tab="metrics"] .bottom-nav a[data-nav-tab="metrics"],
html[data-navigation-tab="settings"] .bottom-nav a[data-nav-tab="settings"] { color: var(--nav-active); }
.bottom-nav svg { width: 20px; height: 20px; }

.press-feedback-ripple {
  position: absolute;
  border-radius: 50%;
  background: var(--press-feedback-color);
  pointer-events: none;
}

/* ── Bouncers ─────────────────────────────── */

.bouncers-page { width: 100%; max-width: 1040px; margin-inline: auto; }

/* Enforcement overview (mockups/bouncers/b.html). The summary sits on the
   page; each monitored bouncer is its own contained item whose expanded body
   reuses the item's columns. Source colours are fixed per origin and were
   validated for colour-vision separation against each theme's panel; light
   mode relies on the visible labels beside every swatch. */
:root,
html[data-theme="dark"],
html[data-theme="darker"] {
  --series-0: color-mix(in srgb, var(--muted) 70%, var(--panel));
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #008300;
  --series-7: #9085e9;
  --bb-line: #3987e5;
}
html[data-theme="light"] {
  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;
  --series-5: #e87ba4;
  --series-6: #008300;
  --series-7: #4a3aa7;
  --bb-line: #2a78d6;
}

.bb-page { display: grid; gap: 1.75rem; min-width: 0; }
.bb-page > .page-head { margin-bottom: 0; }
.bb-pagehead { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-3); }
.bb-head-title { min-width: 0; }
.bb-freshness { display: flex; align-items: baseline; gap: 0.45rem; margin-top: 0.2rem; color: var(--muted); font-size: var(--text-small); }
.bb-freshness .bb-dot { align-self: center; }
.bb-dot { display: inline-block; flex: 0 0 auto; width: 0.45rem; height: 0.45rem; border-radius: var(--radius-round); background: currentColor; }
.bb-tone-good { color: var(--success); }
.bb-tone-mid { color: var(--warning); }
.bb-tone-bad { color: var(--danger); }
.bb-tone-muted { color: var(--muted); }
.bb-freshness .bb-dot.bb-tone-muted { animation: bouncer-loading-pulse 1.3s ease-in-out infinite; }
.bb-quiet { color: var(--muted); font-size: var(--text-normal); }
.desktop-inline { display: inline; }
.mobile-inline { display: none; }
@media (max-width: 959px) {
  .desktop-inline { display: none; }
  .mobile-inline { display: inline; }
}

.bb-units { display: inline-flex; padding: 2px; border: 1px solid var(--border); border-radius: var(--radius-control); background: var(--panel); }
.bb-unit { display: inline-grid; place-items: center; min-height: 1.9rem; padding: 0.25rem 0.75rem; border-radius: var(--radius-compact); color: var(--muted); font-size: var(--text-small); font-weight: 600; }
.bb-unit:hover { color: var(--text); }
.bb-unit.is-on { background: var(--accent-soft); color: var(--accent-text); }
.bb-unit:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* ── Summary: the one bold element ── */
.bb-summary { display: grid; gap: 0.8rem; min-width: 0; }
.bb-figures { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.4rem 2rem; }
.bb-total { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.2rem 0.65rem; line-height: 1; }
.bb-total-num { font-family: var(--font-display); font-size: clamp(2.25rem, 5.2vw, 3.1rem); font-weight: 700; letter-spacing: -0.035em; font-variant-numeric: tabular-nums; }
.bb-total-label { color: var(--muted); font-size: 0.95rem; font-weight: 500; }
.bb-rate { color: var(--muted); font-size: var(--text-medium); }
.bb-rate strong { margin-right: 0.2rem; color: var(--text); font-family: var(--font-display); font-size: 1.2rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.bb-empty { display: flex; align-items: center; gap: 0.6rem; font-family: var(--font-display); font-size: 1.25rem; font-weight: 600; }
.bb-scope { color: var(--muted); font-size: var(--text-small); }
.bb-meter { display: flex; gap: 3px; height: 1.4rem; min-width: 0; }
.bb-seg { flex: var(--w) 1 0; min-width: 0; border-radius: 2px; background: var(--c); }
.bb-meter .bb-seg:first-child { border-radius: 5px 2px 2px 5px; }
.bb-meter .bb-seg:last-child { border-radius: 2px 5px 5px 2px; }
.bb-meter .bb-seg:only-child { border-radius: 5px; }
.bb-sources { display: flex; flex-wrap: wrap; gap: 0.35rem 1.75rem; list-style: none; font-size: var(--text-normal); }
.bb-sources li { display: inline-flex; align-items: baseline; gap: 0.45rem; min-width: 0; overflow-wrap: anywhere; }
.bb-sources a { color: var(--text); text-decoration: underline; text-decoration-color: color-mix(in srgb, var(--text) 28%, transparent); text-underline-offset: 3px; }
.bb-sources a:hover { color: var(--accent-text); text-decoration-color: currentColor; }
.bb-swatch { flex: 0 0 auto; align-self: center; width: 0.65rem; height: 0.65rem; border-radius: 2px; background: var(--c); }
.bb-src-num { font-weight: 650; font-variant-numeric: tabular-nums; }
.bb-src-amount { color: var(--muted); font-variant-numeric: tabular-nums; }
.bb-summary.is-stale .bb-total-num,
.bb-summary.is-stale .bb-rate strong { color: var(--muted); }
.bb-summary.is-stale .bb-meter { opacity: 0.45; }

/* ── Attention: facts on a line, not a box ── */
.bb-alerts { display: flex; flex-wrap: wrap; gap: 0.35rem 1.5rem; margin-bottom: -0.6rem; list-style: none; font-size: var(--text-normal); }
.bb-alerts li { display: block; color: var(--muted); overflow-wrap: anywhere; }
.bb-alerts a { color: var(--text); font-weight: 600; }
.bb-alerts a:hover { color: var(--accent-text); }
.bb-alert-dot { display: inline-block; width: 0.5rem; height: 0.5rem; margin-right: 0.45rem; border-radius: var(--radius-round); background: var(--danger); vertical-align: 0.05rem; }

/* ── Bouncer items ── */
.bb-bouncers {
  --bb-cols: 2rem minmax(0, 1.6fr) minmax(0, 0.85fr) minmax(0, 0.85fr) minmax(0, 1.3fr) 1rem;
  container: bouncers / inline-size;
  min-width: 0;
}
.bb-colhead { display: grid; grid-template-columns: var(--bb-cols); gap: 0.9rem; padding: 0 1.1rem 0.45rem; color: var(--muted); font-size: var(--text-small); }
.bb-list { display: grid; gap: 0.5rem; list-style: none; }
.bb-item { min-width: 0; border: 1px solid var(--border); border-radius: var(--radius-panel); background: var(--panel); scroll-margin-top: 1rem; transition: border-color var(--transition-fast); }
.bb-item[data-open] { border-color: color-mix(in srgb, var(--text) 24%, var(--border)); }
.bb-item.is-editing { border-color: color-mix(in srgb, var(--accent) 70%, var(--border)); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent); }

/* No native tap highlight: the header stays in place while its body
   collapses, so the browser's highlight would flash on it. */
.bb-head {
  display: grid;
  grid-template-columns: var(--bb-cols);
  gap: 0.9rem;
  align-items: center;
  width: 100%;
  padding: 0.8rem 1.1rem;
  border: 0;
  border-radius: inherit;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.bb-head:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
/* A whole row is a large surface: a lighter press tint than usual keeps the press
   acknowledged without flashing the row. */
.bb-head { --press-feedback-color: color-mix(in srgb, var(--text) 6%, transparent); }
/* Touch screens keep :hover on the tapped element; only real pointers get it. */
@media (hover: hover) {
  .bb-head:hover .bb-name strong { color: var(--accent-text); }
}
.bb-mark { display: inline-grid; place-items: center; width: 2rem; height: 2rem; border-radius: var(--radius-surface); background: var(--panel-2); color: var(--muted); }
.bb-mark svg { width: 1.05rem; height: 1.05rem; }
.bb-name { display: grid; gap: 0.1rem; min-width: 0; }
.bb-name strong { font-family: var(--font-display); font-size: 1.02rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.25; overflow-wrap: anywhere; transition: color var(--transition-fast); }
.bb-name > span { color: var(--muted); font-size: var(--text-small); }
.bb-name em { color: var(--warning); font-style: normal; }
.bb-cell { min-width: 0; }
.bb-lbl { display: none; }
.bb-dash { color: var(--muted); }
.bb-pill { display: inline-flex; align-items: center; gap: 0.35rem; font-size: var(--text-small); font-weight: 600; white-space: nowrap; }
.bb-pill .bb-dot { width: 0.42rem; height: 0.42rem; }
.bb-pill.bb-tone-muted { font-weight: 500; }
.bb-cell-num { display: block; font-family: var(--font-display); font-size: 1.05rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.bb-cell-num.is-stale { color: var(--muted); }
.bb-cell-unit { color: var(--muted); font-family: var(--font); font-size: var(--text-small); font-weight: 400; }
.bb-cell-sub { display: block; color: var(--muted); font-size: var(--text-small); }
.bb-chev { width: 1rem; height: 1rem; color: var(--muted); transition: transform var(--transition-fast); }
.bb-item[data-open] .bb-chev { transform: rotate(180deg); }

/* The body reuses the header's columns, so each fact sits under its heading. */
.bb-body { margin: 0 1.1rem; padding: 0.9rem 0 1.1rem; border-top: 1px solid color-mix(in srgb, var(--border) 80%, transparent); }
.bb-body[hidden] { display: none; }
.bb-details { display: grid; grid-template-columns: var(--bb-cols); column-gap: 0.9rem; }
.bb-d-id { grid-column: 2; }
.bb-d-conn { grid-column: 3; }
.bb-d-rt { grid-column: 4; }
.bb-d-enf { grid-column: 5 / span 2; }
.bb-dsec { display: grid; align-content: start; gap: 0.6rem; min-width: 0; }
.bb-dsec > h3 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.bb-dl { display: grid; gap: 0.55rem; font-size: var(--text-normal); }
.bb-dl > div { display: grid; gap: 0.05rem; }
.bb-dl dt { color: var(--muted); font-size: var(--text-small); }
.bb-dl dd { overflow-wrap: anywhere; }
.bb-dl code, .bb-note code { font-family: var(--font-mono); font-size: 0.92em; }
.bb-note { color: var(--muted); font-size: var(--text-normal); line-height: 1.45; overflow-wrap: anywhere; }
.bb-note.bb-tone-bad { color: var(--danger); }
.bb-origins { display: grid; gap: 0.3rem; margin-top: 0.1rem; list-style: none; font-size: var(--text-normal); }
.bb-origins li { display: flex; align-items: center; gap: 0.45rem; min-width: 0; overflow-wrap: anywhere; }
.bb-num { margin-left: auto; font-variant-numeric: tabular-nums; }

/* ── History chart ── */
.bb-history { grid-column: 2 / -1; margin-top: 1.1rem; min-width: 0; }
.bb-history > h3 { margin-bottom: 0.4rem; color: var(--muted); font-size: var(--text-small); font-weight: 500; }
/* Same height as .bb-chart: its 9.5rem plot, the row gap and the 1rem date row. */
.bb-history-loading { height: calc(9.5rem + 0.2rem + 1rem); }
.bb-history-single { display: flex; align-items: center; gap: 0.6rem; padding: 0.8rem 0; font-size: var(--text-normal); }
.bb-single-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--bb-line); }
.bb-chart { display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: 9.5rem auto; gap: 0.2rem 0.5rem; }
.bb-chart-y { display: flex; flex-direction: column; justify-content: space-between; align-items: flex-end; color: var(--muted); font-size: var(--text-xx-small); font-variant-numeric: tabular-nums; transform: translateY(-0.2rem); }
.bb-chart-plot { position: relative; min-width: 0; cursor: crosshair; }
.bb-chart-plot svg { display: block; width: 100%; height: 100%; overflow: visible; }
.bb-grid { stroke: color-mix(in srgb, var(--border) 80%, transparent); stroke-width: 1; }
.bb-line { fill: none; stroke: var(--bb-line); stroke-width: 2; stroke-linejoin: round; }
.bb-gap { fill: color-mix(in srgb, var(--muted) 14%, transparent); }
.bb-gap-label { position: absolute; top: 0.1rem; padding: 0 0.25rem; background: var(--panel); color: var(--muted); font-size: var(--text-xx-small); white-space: nowrap; transform: translateX(-50%); pointer-events: none; }
.bb-chart-x { position: relative; grid-column: 2; height: 1rem; color: var(--muted); font-size: var(--text-xx-small); }
.bb-chart-x span { position: absolute; white-space: nowrap; transform: translateX(-50%); }
.bb-chart-x span:first-child { transform: none; }
.bb-chart-x span:last-child { transform: translateX(-100%); }
.bb-cross { position: absolute; top: 0; bottom: 0; width: 1px; background: color-mix(in srgb, var(--text) 35%, transparent); pointer-events: none; }
.bb-cross-dot { position: absolute; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%; background: var(--bb-line); box-shadow: 0 0 0 2px var(--panel); pointer-events: none; }
.bb-tip { position: absolute; top: -0.4rem; z-index: 4; display: grid; gap: 0.05rem; padding: 0.35rem 0.55rem; border: 1px solid var(--border); border-radius: var(--radius-surface); background: var(--panel-2); color: var(--text); font-size: var(--text-x-small); white-space: nowrap; transform: translate(-50%, -100%); pointer-events: none; }
.bb-tip span { color: var(--muted); }
.bb-cross[hidden], .bb-cross-dot[hidden], .bb-tip[hidden] { display: none; }

/* ── Narrow list: stack each item ── */
@container bouncers (max-width: 720px) {
  .bb-colhead { display: none; }
  .bb-head { grid-template-columns: 2rem minmax(0, 1fr) 1rem; grid-template-areas: "mark name chev" ". conn conn" ". rt rt" ". enf enf"; gap: 0.4rem 0.8rem; align-items: start; }
  .bb-head > :nth-child(1) { grid-area: mark; }
  .bb-head > :nth-child(2) { grid-area: name; }
  .bb-head > :nth-child(3) { grid-area: conn; }
  .bb-head > :nth-child(4) { grid-area: rt; }
  .bb-head > :nth-child(5) { grid-area: enf; }
  .bb-head > :nth-child(6) { grid-area: chev; align-self: center; }
  .bb-cell { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr); align-items: baseline; }
  .bb-lbl { display: block; color: var(--muted); font-size: var(--text-small); }
  .bb-enf .bb-cell-num, .bb-enf .bb-cell-sub { grid-column: 2; }
  .bb-details { grid-template-columns: minmax(0, 1fr); row-gap: 1.1rem; }
  .bb-details > * { grid-column: 1 !important; }
  .bb-dsec > h3 { position: static; width: auto; height: auto; overflow: visible; clip: auto; color: var(--muted); font-size: var(--text-small); font-weight: 600; }
  .bb-d-enf:not(:has(dl, ul)) { display: none; }
  .bb-history { margin-top: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bb-chev, .bb-item, .bb-name strong { transition: none; }
  .bb-freshness .bb-dot.bb-tone-muted { animation: none; }
}

.bouncer-monitor-chip { display: inline-block; margin-top: 0.35rem; padding: 0.1rem 0.35rem; border-radius: var(--radius-pill); background: color-mix(in srgb, var(--info) 14%, transparent); color: var(--info); font-size: 0.5rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; }
.bouncer-discovery-state.mid { color: var(--warning); }
.bouncer-discovery-state.bad { color: var(--danger); }

@keyframes bouncer-loading-pulse { 50% { opacity: 0.42; transform: scale(0.78); } }

.bouncer-empty { min-height: 17.5rem; display: grid; align-content: center; text-align: center; }
.bouncer-empty p { max-width: 26rem; margin-inline: auto; }

/* Monitoring uses the shared list pane shell and mobile sheet. */
.bouncer-monitoring-pane { --bouncer-pane-edge-inset: 0.35rem; --bouncer-pane-content-inset: 0.8rem; }
.bouncer-monitoring-pane > .list-filters-head { padding-left: calc(var(--bouncer-pane-edge-inset) + var(--bouncer-pane-content-inset)); }
.bouncer-monitoring-pane > .mobile-sheet-scroll {
  padding-inline: var(--bouncer-pane-edge-inset);
  overflow-anchor: none;
}
.bouncer-discovery-box { display: grid; gap: var(--space-2); flex-shrink: 0; margin: 0.35rem var(--bouncer-pane-edge-inset) 0.55rem; padding: 0.45rem var(--bouncer-pane-content-inset) 0.75rem; border-bottom: 1px solid var(--border); }
.bouncer-discovery-title, .bouncer-monitoring-label { color: var(--muted); font-size: 0.59rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
.bouncer-discovery-sources { display: grid; grid-template-columns: minmax(0, 1fr) max-content; gap: 0.4rem 0.5rem; color: var(--text); font-size: 0.64rem; }
.bouncer-discovery-row { display: contents; }
.bouncer-discovery-state { display: inline-flex; align-items: center; gap: 0.3rem; font-size: var(--text-micro); }
.bouncer-discovery-state.good { color: var(--success); }
.bouncer-discovery-state.muted { color: var(--muted); }
.bouncer-discovery-dot { width: 0.35rem; height: 0.35rem; border-radius: var(--radius-round); background: currentColor; box-shadow: 0 0 6px currentColor; }
.bouncer-discovery-loading { display: flex; align-items: center; gap: 0.45rem; }
.bouncer-loading-dot { display: inline-block; width: 0.48rem; height: 0.48rem; flex: 0 0 auto; border-radius: var(--radius-round); background: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); animation: bouncer-loading-pulse 1.3s ease-in-out infinite; }
.bouncer-loading-panel { justify-items: center; gap: 0.65rem; }
.bouncer-loading-panel h2 { margin: 0; }
.bouncer-monitoring-group + .bouncer-monitoring-group { margin-top: 0.85rem; }
.bouncer-monitoring-label { display: flex; align-items: center; gap: 0.35rem; padding: 0.35rem var(--bouncer-pane-content-inset) 0.45rem; }
.bouncer-monitoring-label span { display: inline-grid; place-items: center; min-width: 1.15rem; height: 1.15rem; padding-inline: 0.25rem; border-radius: var(--radius-pill); color: var(--muted); background: color-mix(in srgb, var(--text) 6%, transparent); font-size: 0.54rem; letter-spacing: 0; }
.bouncer-monitoring-list { display: grid; }
.bouncer-monitor-form { position: relative; margin: 0; border: 1px solid transparent; border-bottom-color: color-mix(in srgb, var(--border) 66%, transparent); border-radius: var(--radius-surface); transition: background var(--transition-fast); }
/* Each row's top edge lies on the separator above it, so an expanded row's
   background starts exactly where that separator was. */
.bouncer-monitor-form + .bouncer-monitor-form { margin-top: -1px; }
.bouncer-monitor-form + .bouncer-monitor-form .bouncer-monitor-summary { padding-top: calc(0.3rem + 1px); }
.bouncer-monitor-form:last-child,
.bouncer-monitor-form:has(+ .bouncer-monitor-form.is-expanded) { border-bottom-color: transparent; }
.bouncer-monitor-form.is-expanded {
  border-color: transparent;
  background: color-mix(in srgb, var(--accent-soft) 72%, transparent);
}
.bouncer-monitor-summary { position: relative; padding: 0.18rem var(--bouncer-pane-content-inset); }
.bouncer-monitor-details { display: block; width: 100%; min-width: 0; padding: 0.55rem 0; border: 0; color: inherit; background: transparent; font: inherit; text-align: left; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.bouncer-monitor-details:hover .bouncer-monitor-name { color: var(--accent-text); }
.bouncer-monitor-copy { min-width: 0; }
.bouncer-monitor-name { display: block; color: var(--text); font-size: 0.7rem; font-weight: 700; line-height: 1.35; overflow-wrap: anywhere; }
.bouncer-monitor-form.is-expanded .bouncer-monitor-name { color: var(--accent-text); }
.bouncer-monitor-secondary { display: flex; align-items: baseline; justify-content: space-between; gap: 0.45rem; min-width: 0; margin-top: 0.32rem; padding-right: 2.25rem; }
.bouncer-monitor-meta { display: flex; flex-wrap: wrap; gap: var(--space-1); min-width: 0; }
.bouncer-monitor-meta span { color: var(--muted); font-size: 0.5rem; line-height: 1; text-transform: lowercase; }
.bouncer-monitor-meta span + span::before { content: "·"; margin-right: 0.25rem; color: color-mix(in srgb, var(--muted) 55%, transparent); }
.bouncer-monitor-kind-group { display: inline-flex; align-items: center; gap: 0.2rem; flex-shrink: 0; }
.bouncer-monitor-kind { max-width: 4.8rem; overflow: hidden; padding: 0.18rem 0.35rem; border: 1px solid color-mix(in srgb, var(--border) 82%, transparent); border-radius: var(--radius-pill); color: var(--muted); background: color-mix(in srgb, var(--text) 3%, transparent); font-size: 0.49rem; font-weight: 700; letter-spacing: 0.04em; line-height: 1; text-overflow: ellipsis; text-transform: uppercase; white-space: nowrap; }
.bouncer-monitor-chevron { display: block; width: 0.75rem; height: 0.75rem; color: var(--muted); transition: transform var(--transition-fast); }
.bouncer-monitor-form.is-expanded .bouncer-monitor-chevron { transform: rotate(180deg); }
.bouncer-monitor-toggle { position: absolute; right: 0.75rem; bottom: 0.67rem; }
.bouncer-monitor-form.is-pending .bouncer-monitor-toggle { cursor: progress; }
.bouncer-monitor-form.is-pending .bouncer-monitor-toggle .switch input:disabled + .switch-track { opacity: 1; }
.bouncer-monitor-settings { display: grid; gap: 0.45rem; margin: 0 0.8rem 0.55rem; padding: 0.1rem 0.1rem 0.25rem; }
.bouncer-monitor-settings[hidden] { display: none; }
.bouncer-monitor-form.is-expanded .bouncer-monitor-settings { padding-top: 0.55rem; border-top: 1px solid color-mix(in srgb, var(--accent) 24%, var(--border)); }
.bouncer-monitor-settings > label, .bouncer-container-fields > label { color: var(--muted); font-size: var(--text-xx-small); font-weight: 650; }
.bouncer-monitor-settings label span { font-weight: 400; }
.bouncer-monitor-settings input[type="text"],
.bouncer-monitor-settings .custom-select-trigger {
  width: 100%;
  height: 1.85rem;
  min-width: 0;
  padding: 0.34rem 0.48rem;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  color: var(--text);
  background: var(--panel-2);
  font: inherit;
  font-size: 0.64rem;
  line-height: 1.2;
  transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.bouncer-monitor-settings .custom-select-trigger {
  min-height: 0;
  grid-template-columns: minmax(0, 1fr) 12px;
  gap: 0.4rem;
}
.bouncer-monitor-settings input[type="text"]:hover:not(:disabled):not(:focus) {
  background: color-mix(in srgb, var(--text) 3%, var(--panel-2));
}
.bouncer-monitor-settings input[type="text"]:focus {
  outline: 0;
  border-color: color-mix(in srgb, var(--primary) 78%, var(--border));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 78%, transparent);
}
.bouncer-monitor-settings .custom-select-icon-chevron { width: 11px; height: 11px; }
.bouncer-container-fields { display: grid; gap: 0.35rem; }
.bouncer-container-fields[hidden] { display: none; }
/* Sized for the narrow pane; colour comes from .btn-primary.btn-compact. */
.btn-compact.bouncer-monitor-save {
  justify-self: end;
  min-height: 1.4rem;
  margin-top: 0.28rem;
  padding: 0.2rem 0.44rem;
  border-radius: var(--radius-compact);
  font-size: 0.6rem;
  font-weight: 650;
  line-height: 1;
}

@media (max-width: 700px) {
  .bottom-nav a { font-size: 0.54rem; }
  .bottom-nav svg { width: 18px; height: 18px; }
}

@media (prefers-reduced-motion: reduce) {
  .resume-refresh-spinner,
  .pending-operation-spinner { animation: none; }
  .bouncer-loading-dot { animation: none; }
}

/* ── Page primitives ───────────────────────── */

.page-head {
  margin-bottom: var(--space-4);
}

/* Match list starts whether or not the header has an Add decision action. */
.list-page-head { min-height: 2.125rem; }

.page-head h1 {
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.page-title-status {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.resume-refresh-status.mobile-only {
  grid-template-columns: auto auto;
  align-items: center;
  gap: 0.35rem;
  color: var(--muted);
  font-size: var(--text-x-small);
  font-weight: 500;
  line-height: 1;
}

.resume-refresh-status[hidden] { display: none !important; }

.resume-refresh-spinner {
  width: 0.62rem;
  height: 0.62rem;
  border: 1.5px solid color-mix(in srgb, var(--muted) 28%, transparent);
  border-top-color: var(--muted);
  border-radius: var(--radius-pill);
  animation: status-spinner-spin 0.75s linear infinite;
}

@keyframes status-spinner-spin { to { transform: rotate(360deg); } }

/* A visit in progress (lib/navigation_pending.js): the old page gives way to
   an empty content area, at once for a bottom-nav tap and otherwise after a
   short delay, so it is not mistaken for the new one. It is hidden, not
   removed: its height and scroll stay put, so nothing jumps and Back returns
   to the same place. Menus and tooltips the page appended to <body> go too. */
html[data-navigation] .app-main,
html[data-navigation] .app-main *,
html[data-navigation] body > .custom-select-menu,
html[data-navigation] body > .custom-select-menu *,
html[data-navigation] body > .tooltip {
  visibility: hidden !important;
  pointer-events: none !important;
}

/* The spinner for a slow visit. Turbo keeps this element through the page
   swap, so it keeps turning while the new page renders behind it. It is sticky
   in the content column, centred in whatever part of the page is on screen,
   and takes no layout space of its own. */
.navigation-loader {
  position: sticky;
  z-index: 5;
  top: calc(50dvh - var(--bottom-h) / 2 - 1.5rem);
  flex: 0 0 0;
  height: 0;
}

/* The mark's wall, laid brick by brick from the bottom course, a beat once it
   stands, then a fade into the next. It only shows for a slow visit, at least
   300 ms and often not much longer, so a brick is down from the first frame
   and any moment of the build reads as work in progress. Each brick has its
   own keyframes because they go down at different moments but fade together:
   brick n of 14 starts down at n × 55 ms, all hold to 960 ms and fade by
   1140 ms of a 1150 ms cycle. Display none → block restarts it with every slow visit. */
.navigation-wall {
  display: none;
  width: 3rem;
  height: 3rem;
  margin: 0 auto;
  overflow: visible;
}
html[data-navigation="spinner"] .navigation-wall { display: block; }
.navigation-wall rect {
  transform-box: fill-box;
  transform-origin: center;
  animation-duration: 1150ms;
  animation-timing-function: linear;
  animation-delay: -90ms;
  animation-iteration-count: infinite;
}
.navigation-wall rect:nth-child(11) { animation-name: wall-brick-0; }
.navigation-wall rect:nth-child(12) { animation-name: wall-brick-1; }
.navigation-wall rect:nth-child(13) { animation-name: wall-brick-2; }
.navigation-wall rect:nth-child(14) { animation-name: wall-brick-3; }
.navigation-wall rect:nth-child(8) { animation-name: wall-brick-4; }
.navigation-wall rect:nth-child(9) { animation-name: wall-brick-5; }
.navigation-wall rect:nth-child(10) { animation-name: wall-brick-6; }
.navigation-wall rect:nth-child(4) { animation-name: wall-brick-7; }
.navigation-wall rect:nth-child(5) { animation-name: wall-brick-8; }
.navigation-wall rect:nth-child(6) { animation-name: wall-brick-9; }
.navigation-wall rect:nth-child(7) { animation-name: wall-brick-10; }
.navigation-wall rect:nth-child(1) { animation-name: wall-brick-11; }
.navigation-wall rect:nth-child(2) { animation-name: wall-brick-12; }
.navigation-wall rect:nth-child(3) { animation-name: wall-brick-13; }
@keyframes wall-brick-0 { 0% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 14.78%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-1 { 0%, 4.78% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 19.57%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-2 { 0%, 9.57% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 24.35%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-3 { 0%, 14.35% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 29.13%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-4 { 0%, 19.13% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 33.91%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-5 { 0%, 23.91% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 38.7%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-6 { 0%, 28.7% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 43.48%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-7 { 0%, 33.48% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 48.26%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-8 { 0%, 38.26% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 53.04%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-9 { 0%, 43.04% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 57.83%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-10 { 0%, 47.83% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 62.61%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-11 { 0%, 52.61% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 67.39%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-12 { 0%, 57.39% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 72.17%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }
@keyframes wall-brick-13 { 0%, 62.17% { opacity: 0; transform: translateY(-2.5px) scale(0.86); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); } 76.96%, 83.48% { opacity: 1; transform: none; } 99.13%, 100% { opacity: 0; transform: none; } }

@media (min-width: 960px) {
  .navigation-loader { top: calc(50dvh - 1.5rem); }
}

/* The empty page and spinner already say the page is loading. Turbo's bar
   stays for what they do not cover: form submissions and refreshing a cached
   preview. */
html[data-navigation] > .turbo-progress-bar { visibility: hidden; }

/* Without motion: the finished wall, breathing. */
@media (prefers-reduced-motion: reduce) {
  .navigation-wall rect { animation: none; }
  html[data-navigation="spinner"] .navigation-wall { animation: navigation-wall-breathe 2.4s ease-in-out infinite; }
}
@keyframes navigation-wall-breathe { 50% { opacity: 0.55; } }

.page-sub {
  color: var(--muted);
  font-size: 0.85rem;
  margin-top: 0.25rem;
}

/* Floating snackbar — list pages only (turbo-frame host is in-page, bar is fixed).
   Tinted with the live colour the rail's Sync light uses. On phones it shares a
   row with the filter button: its 40px height, its centre line, and the mirrored
   inset, so the two never collide. */
.list-data-chip-host { display: contents; }
.list-refresh-bar[hidden] { display: none; }

.list-refresh-bar {
  --live: var(--info);
  --tint: 13%;
  --lift: rgba(0, 0, 0, 0.6);
  position: fixed;
  /* Above the bottom nav (60) and filter button (70), below the filter
     sheet and its backdrop (80, 81): it belongs to the page under them. */
  z-index: 75;
  left: 1.55rem;
  bottom: calc(var(--bottom-h) + 1.3rem);
  transform: translateY(120%);
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  max-width: calc(100vw - 3.1rem - 40px - 0.75rem);
  padding: calc((40px - 1lh) / 2) 0.9rem calc((40px - 1lh) / 2) 0.75rem;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--live) var(--tint), var(--panel));
  color: var(--text);
  font-size: var(--text-control);
  font-weight: 600;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transition-fast);
  box-shadow: 0 10px 28px -8px var(--lift);
  animation: list-refresh-in 0.38s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

@media (min-width: 960px) {
  .list-refresh-bar {
    left: auto;
    right: 1.75rem;
    bottom: 1.75rem;
    padding-block: 0.45rem;
  }
}

@keyframes list-refresh-in {
  to { transform: translateY(0); }
}

.list-refresh-bar:hover { --tint: 22%; }

html[data-theme="light"] .list-refresh-bar {
  --tint: 8%;
  --lift: rgba(15, 23, 42, 0.3);
}

html[data-theme="light"] .list-refresh-bar:hover { --tint: 14%; }

/* Centred on the line box, the arrow sits low: Inter's line box has more room
   below its capitals than above. Baseline alignment rests the arrow on the
   baseline instead, and this lifts its centre to half the capital height. */
.list-refresh-bar-arrow {
  --icon: 0.8rem;
  flex: none;
  width: var(--icon);
  height: var(--icon);
  fill: none;
  stroke: var(--live);
  stroke-width: 2.1;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: translateY(calc(var(--icon) / 2 - 0.5cap));
}

.list-refresh-bar-text {
  white-space: nowrap;
}

/* Inline-block so the count can tick up on its own. */
.list-refresh-bar-count {
  display: inline-block;
}

@media (prefers-reduced-motion: reduce) {
  .list-refresh-bar { animation: none; transform: none; }
}

.filter-count {
  margin: -0.35rem 0 0.85rem;
}

.empty-panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 1.25rem 1.15rem;
  box-shadow: var(--shadow-panel);
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

.empty-panel h2 {
  font-size: 0.95rem;
  font-weight: 600;
  margin-bottom: 0.35rem;
}

.empty-panel p {
  color: var(--muted);
  font-size: 0.85rem;
  max-width: 48ch;
  line-height: 1.45;
}

.empty-panel-actions {
  margin-top: 0.85rem !important;
}

.panel-empty {
  display: grid;
  gap: var(--space-1);
  line-height: 1.45;
}

.panel-empty strong {
  color: var(--text);
  font-size: var(--text-medium);
  font-weight: 600;
}

.mono { font-family: var(--font-mono); font-size: 0.9em; }

.banner {
  display: grid;
  gap: 0.2rem;
  border-radius: var(--radius-panel);
  padding: 0.75rem 1rem;
  margin-bottom: var(--space-4);
  font-size: var(--text-normal);
  border: 1px solid var(--border);
}

.banner-danger {
  background: color-mix(in srgb, var(--danger) 12%, var(--panel));
  border-color: color-mix(in srgb, var(--danger) 35%, var(--border));
  color: var(--text);
}

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

.banner-warning {
  background: color-mix(in srgb, var(--warning) 9%, var(--panel));
  border-color: color-mix(in srgb, var(--warning) 30%, var(--border));
  color: var(--muted);
}

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

.info-admonition,
.warning-admonition {
  display: grid;
  gap: 0.8rem;
  margin-bottom: var(--space-4);
  padding: var(--space-4);
  border-radius: var(--radius-surface);
  background: color-mix(in srgb, var(--admonition-color, var(--info)) 9%, var(--panel));
  color: var(--muted);
  font-size: var(--text-normal);
  line-height: 1.55;
}

.warning-admonition { --admonition-color: #ff9100; }

.info-admonition-title,
.warning-admonition-title {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  color: var(--text);
  line-height: 1;
}

.info-admonition-title svg,
.warning-admonition-title svg {
  width: 1.25rem;
  height: 1.25rem;
  flex: 0 0 auto;
  color: var(--admonition-color, var(--info));
}

.info-admonition-title strong,
.warning-admonition-title strong { font-weight: 650; }

.info-admonition p,
.warning-admonition p { margin: 0; }

.warning-admonition-body { display: grid; gap: 0.8rem; }

html[data-theme="light"] .info-admonition,
html[data-theme="light"] .warning-admonition {
  background: color-mix(in srgb, var(--admonition-color, var(--info)) 16%, var(--panel));
}

/* ── Buttons ──────────────────────────────────
   One family for single buttons. Primary is the only filled colour; secondary
   is a soft tint, danger a soft red, compact a quiet text button for row-level
   actions. The compact action bar is its own component and is not styled here. */
.btn-primary,
.btn-secondary,
.btn-danger,
.btn-compact {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.1rem;
  padding: 0.42rem 0.85rem;
  border: 1px solid transparent;
  border-radius: var(--radius-surface);
  font-family: inherit;
  font-size: var(--text-control);
  font-weight: 600;
  line-height: 1.15;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}

/* Suppress native touch feedback only while the controller owns the press.
   Opt-outs and specialized controls keep their existing/native feedback. */
[data-press-feedback-active] {
  -webkit-tap-highlight-color: transparent;
}

:where(
  button,
  input:is([type="submit"], [type="button"], [type="reset"]),
  a:is(.btn-primary, .btn-secondary, .btn-danger, .btn-compact, .compact-action, .list-refresh-bar)
) {
  user-select: none;
  touch-action: manipulation;
}

:where(
  button,
  input:is([type="submit"], [type="button"], [type="reset"]),
  a:is(.btn-primary, .btn-secondary, .btn-danger, .btn-compact, .compact-action, .list-refresh-bar)
):not([data-press-feedback-active], [data-press-feedback="none"]):not(:disabled):not([aria-disabled="true"]):active {
  filter: brightness(0.92);
}

:where(
  button,
  input:is([type="submit"], [type="button"], [type="reset"]),
  a:is(.btn-primary, .btn-secondary, .btn-danger, .btn-compact, .compact-action, .list-refresh-bar)
):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

/* CTAs use --primary* (separate from --accent highlights) */
.btn-primary { background: var(--primary); color: var(--primary-text); }

.btn-secondary { background: color-mix(in srgb, var(--text) 7%, transparent); color: var(--text); }

.btn-danger {
  background: color-mix(in srgb, var(--danger) 10%, transparent);
  color: color-mix(in srgb, var(--danger) 88%, var(--text));
}

/* Ghost. The label mixes toward --text: plain --muted is under 4.5:1 on the
   darker theme's surfaces. */
.btn-compact {
  min-height: 2rem;
  padding: 0.35rem 0.6rem;
  background: transparent;
  color: color-mix(in srgb, var(--muted) 70%, var(--text));
  font-size: var(--text-small);
  white-space: nowrap;
}

/* Combinations: compact only changes size, except danger, which goes ghost. */
.btn-primary.btn-compact { background: var(--primary); color: var(--primary-text); }
.btn-secondary.btn-compact { background: color-mix(in srgb, var(--text) 7%, transparent); color: var(--text); }
.btn-compact.btn-danger { background: transparent; color: color-mix(in srgb, var(--danger) 88%, var(--text)); }

.btn-primary:hover:not(:disabled, [aria-disabled="true"]) { background: var(--primary-hover); }
.btn-secondary:hover:not(:disabled, [aria-disabled="true"]),
.btn-secondary.btn-compact:hover:not(:disabled, [aria-disabled="true"]) { background: color-mix(in srgb, var(--text) 11%, transparent); }
.btn-danger:hover:not(:disabled, [aria-disabled="true"]) { background: color-mix(in srgb, var(--danger) 16%, transparent); color: var(--danger); }
.btn-compact:hover:not(:disabled, [aria-disabled="true"]) { background: color-mix(in srgb, var(--text) 7%, transparent); color: var(--text); }
.btn-primary.btn-compact:hover:not(:disabled, [aria-disabled="true"]) { background: var(--primary-hover); color: var(--primary-text); }
.btn-compact.btn-danger:hover:not(:disabled, [aria-disabled="true"]) { background: color-mix(in srgb, var(--danger) 11%, transparent); color: var(--danger); }

:is(.btn-primary, .btn-secondary, .btn-danger, .btn-compact):is(:disabled, [aria-disabled="true"]) {
  opacity: 0.48;
  cursor: not-allowed;
}

.hidden { display: none !important; }

body.modal-open {
  overflow: hidden;
  touch-action: none;
}

html.alert-modal-open,
html.alert-modal-open body {
  overscroll-behavior-x: none;
}

html.alert-modal-open body.modal-open {
  touch-action: pan-y;
}

/* ── Toasts ────────────────────────────────── */

.toast-host {
  position: fixed;
  z-index: 200;
  left: 1rem;
  right: 1rem;
  bottom: calc(var(--bottom-h) + 0.85rem);
  pointer-events: none;
  display: flex;
  justify-content: center;
}

@media (min-width: 960px) {
  .toast-host {
    left: auto;
    right: 1.75rem;
    bottom: 1.75rem;
    justify-content: flex-end;
    max-width: 30rem;
  }
}

.toast-list {
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-3);
  width: 100%;
  max-width: 30rem;
  pointer-events: none;
}

.toast {
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 5rem;
  padding: 1.25rem 1.5rem;
  border-radius: var(--radius-large);
  border: 0;
  cursor: pointer;
  text-align: center;
  background: linear-gradient(180deg, #252836 0%, #1c1f2b 100%);
  color: var(--text);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.35),
    0 12px 28px rgba(0, 0, 0, 0.5),
    0 28px 56px rgba(0, 0, 0, 0.4),
    0 0 0 1px rgba(255, 255, 255, 0.1);
  opacity: 0;
  transform: translateY(130%);
  transition:
    opacity 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}

@media (min-width: 960px) {
  .toast {
    transform: translateX(130%);
  }
}

.toast-show {
  opacity: 1;
  transform: translateY(0) translateX(0);
}

.toast-leave {
  opacity: 0;
  transform: translateY(45%);
  transition:
    opacity 0.24s ease,
    transform 0.3s cubic-bezier(0.4, 0, 1, 1);
}

@media (min-width: 960px) {
  .toast-leave {
    transform: translateX(45%);
  }
}

.toast-status {
  font-size: var(--text-x-small);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.2;
}

.toast-text {
  margin: 0;
  font-size: var(--text-compact);
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0.01em;
  color: #e2e8f0;
  word-break: break-word;
  text-align: center;
  max-width: 30ch;
}

.toast-success {
  background: linear-gradient(180deg, #163528 0%, #12261e 100%);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.35),
    0 12px 28px rgba(0, 0, 0, 0.5),
    0 28px 56px rgba(0, 0, 0, 0.4),
    0 0 0 1px rgba(52, 211, 153, 0.4),
    0 0 48px rgba(52, 211, 153, 0.18);
}

.toast-success .toast-status { color: #4ade80; }
.toast-success .toast-text { color: #d1fae5; }

.toast-danger {
  background: linear-gradient(180deg, #3a1820 0%, #2a1218 100%);
  box-shadow:
    0 2px 4px rgba(0, 0, 0, 0.35),
    0 12px 28px rgba(0, 0, 0, 0.5),
    0 28px 56px rgba(0, 0, 0, 0.4),
    0 0 0 1px rgba(251, 113, 133, 0.45),
    0 0 48px rgba(251, 113, 133, 0.2);
}

.toast-danger .toast-status { color: #fb7185; }
.toast-danger .toast-text { color: #fecdd3; }

.toast:hover { filter: brightness(1.06); }
.toast:not([data-press-feedback-active]):active { filter: brightness(0.98); }

/* Light theme toasts */
html[data-theme="light"] .toast {
  background: linear-gradient(180deg, #ffffff 0%, #f4f5f8 100%);
  box-shadow:
    0 2px 6px rgba(15, 23, 42, 0.08),
    0 14px 32px rgba(15, 23, 42, 0.14),
    0 24px 48px rgba(15, 23, 42, 0.1),
    0 0 0 1px rgba(15, 23, 42, 0.1);
}

html[data-theme="light"] .toast-success {
  background: linear-gradient(180deg, #ecfdf5 0%, #d1fae5 100%);
  box-shadow:
    0 2px 6px rgba(15, 23, 42, 0.08),
    0 14px 32px rgba(15, 23, 42, 0.12),
    0 0 0 1px rgba(5, 150, 105, 0.28);
}

html[data-theme="light"] .toast-success .toast-status { color: #047857; }
html[data-theme="light"] .toast-success .toast-text { color: #065f46; }

html[data-theme="light"] .toast-danger {
  background: linear-gradient(180deg, #fff1f2 0%, #ffe4e6 100%);
  box-shadow:
    0 2px 6px rgba(15, 23, 42, 0.08),
    0 14px 32px rgba(15, 23, 42, 0.12),
    0 0 0 1px rgba(225, 29, 72, 0.28);
}

html[data-theme="light"] .toast-danger .toast-status { color: #be123c; }
html[data-theme="light"] .toast-danger .toast-text { color: #9f1239; }

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0.58);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
  overscroll-behavior: none;
}

@media (min-width: 640px) {
  .modal-overlay {
    align-items: center;
    padding: var(--space-5);
    background: rgba(0, 0, 0, 0.55);
  }
}

/* Shell keeps full border-radius; body scrolls inside so corners stay even */
.modal-panel {
  background: var(--panel);
  border: 1px solid var(--border);
  /* Mobile: full-height sheet */
  border-radius: 0;
  width: 100%;
  max-width: none;
  height: 100dvh;
  max-height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: relative;
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.5);
}

@media (min-width: 640px) {
  .modal-panel {
    border-radius: var(--radius-large);
    width: 100%;
    max-width: 480px;
    height: auto;
    max-height: min(90dvh, 760px);
  }
}

.modal-panel-wide { max-width: min(840px, 100%); }

@media (min-width: 640px) {
  .modal-panel-wide {
    max-width: min(840px, 100%);
    max-height: min(92dvh, 900px);
  }
}

.modal-chrome {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 0.7rem 0.85rem;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--panel) 92%, var(--bg));
  z-index: 2;
}

.modal-chrome-title {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 650;
  letter-spacing: -0.01em;
}

.modal-close {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  background: var(--panel-2);
  color: var(--text);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.modal-close:hover {
  border-color: color-mix(in srgb, var(--text) 22%, var(--border));
  background: color-mix(in srgb, var(--text) 6%, var(--panel-2));
}

.modal-body {
  flex: 1 1 auto;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem 1rem 1.25rem;
  scrollbar-gutter: stable;
}

.decision-form,
.form-row { display: grid; gap: 0.35rem; }
.form-row { margin-bottom: 0.75rem; }
.form-row label { font-size: var(--text-caption); font-weight: 600; color: var(--muted); }

.form-input {
  width: 100%;
  background: var(--panel-2);
  border: 1px solid transparent;
  color: var(--text);
  border-radius: var(--radius-surface);
  padding: 0.55rem 0.7rem;
  font-size: 0.85rem;
  font-family: inherit;
  transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.form-input:hover:not(:disabled):not(:focus) {
  background: color-mix(in srgb, var(--text) 3%, var(--panel-2));
}

.form-input:focus {
  outline: 0;
  border-color: color-mix(in srgb, var(--primary) 78%, var(--border));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 78%, transparent);
}

.custom-select {
  position: relative;
  width: 100%;
  min-width: 0;
}

.custom-select-native {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden !important;
  opacity: 0;
  pointer-events: none;
}

.custom-select-trigger {
  appearance: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 15px;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-height: var(--control-height);
  padding: 0.48rem 0.62rem;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: var(--text-compact);
  text-align: left;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--transition-fast), border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.custom-select-searchable .custom-select-trigger {
  grid-template-columns: 15px minmax(0, 1fr) 15px;
}

.custom-select-trigger:hover:not(:disabled) {
  border-color: transparent;
  background: color-mix(in srgb, var(--text) 3%, var(--panel-2));
}

.custom-select-trigger:focus-visible,
.custom-select.is-open .custom-select-trigger {
  outline: 0;
  border-color: color-mix(in srgb, var(--primary) 78%, var(--border));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 78%, transparent);
}

.custom-select-trigger:disabled { cursor: not-allowed; opacity: 0.5; }

.custom-select-value {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-select-icon-chevron {
  width: 15px;
  height: 15px;
  color: var(--muted);
  transition: transform var(--transition-fast);
}

.custom-select.is-open .custom-select-icon-chevron { transform: rotate(180deg); }

.custom-select-menu {
  position: fixed;
  z-index: 1200;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  background: var(--panel-2);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.42), 0 3px 12px rgba(0, 0, 0, 0.22);
  animation: custom-select-in 120ms ease-out;
}

.custom-select-menu[hidden] { display: none; }

html[data-theme="light"] .custom-select-menu {
  box-shadow: 0 18px 45px rgba(24, 32, 47, 0.16), 0 2px 8px rgba(24, 32, 47, 0.08);
}

@keyframes custom-select-in {
  from { opacity: 0; transform: translateY(-3px); }
}

@media (prefers-reduced-motion: reduce) {
  .custom-select-menu { animation: none; }
}

.custom-select-search {
  position: relative;
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--border);
}

.custom-select-search .custom-select-icon-search {
  position: absolute;
  left: 0.65rem;
  width: 15px;
  height: 15px;
  color: var(--muted);
  pointer-events: none;
}

.custom-select-search input {
  width: 100%;
  min-height: var(--control-height);
  padding: 0.45rem 0.65rem 0.45rem 2rem;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--text-control);
}

.custom-select-search input::placeholder { color: var(--muted); }

.custom-select-options {
  max-height: min(17rem, calc(100dvh - 6rem));
  overflow-y: auto;
  padding: 0.3rem;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--dot-idle) transparent;
}

.custom-select-group {
  padding: 0.55rem 0.55rem 0.3rem;
  color: var(--muted);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

/* Options inside a group are indented, as native selects do. */
.custom-select-option[data-group] { padding-left: 1.35rem; }

/* A heading that names something, such as a Hub item, keeps its exact case. */
.custom-select-group.is-name {
  font-size: var(--text-x-small);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}

.custom-select-option {
  -webkit-tap-highlight-color: transparent;
  appearance: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 15px;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  min-height: var(--control-height-compact);
  padding: 0.4rem 0.55rem;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 0.76rem;
  text-align: left;
  cursor: pointer;
}

.custom-select-option > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.custom-select-option:hover,
.custom-select-option:focus-visible {
  outline: 0;
  background: var(--panel-2);
  background: color-mix(in srgb, var(--text) 5%, var(--panel-2));
}

.custom-select-option.is-selected {
  background: color-mix(in srgb, var(--accent) 10%, var(--panel-2));
}

.custom-select-icon-search {
  width: 15px;
  height: 15px;
  color: var(--muted);
}

.custom-select-icon-check {
  display: none;
  width: 15px;
  height: 15px;
  color: var(--accent-text);
}

.custom-select-option.is-selected .custom-select-icon-check { display: block; }
.custom-select-option:disabled { opacity: 0.45; cursor: not-allowed; }
.custom-select-option[hidden],
.custom-select-group[hidden] { display: none; }

/* Multiple selects: checklist glyph, leading checkboxes and a Clear/Done footer.
   An exclusive option ("All scenarios") takes a round marker above a divider. */
.custom-select-multiple .custom-select-trigger {
  grid-template-columns: 15px minmax(0, 1fr) 15px;
}

.custom-select-icon-checklist {
  width: 15px;
  height: 15px;
  color: var(--muted);
}

.custom-select-menu .custom-select-option:has(> .custom-select-box) {
  grid-template-columns: 16px minmax(0, 1fr);
}

.custom-select-option.is-selected:has(> .custom-select-box) { background: transparent; }

.custom-select-option.is-selected:has(> .custom-select-box):hover,
.custom-select-option.is-selected:has(> .custom-select-box):focus-visible {
  background: color-mix(in srgb, var(--text) 5%, var(--panel-2));
}

/* The border is an inset shadow so the whole 14px box centers its mark. */
.custom-select-box {
  display: grid;
  place-items: center;
  width: 14px;
  height: 14px;
  border-radius: var(--radius-compact);
  box-shadow: inset 0 0 0 1.5px var(--dot-idle);
  transition: background var(--transition-fast), box-shadow var(--transition-fast);
}

.custom-select-option.is-selected > .custom-select-box {
  background: var(--accent);
  box-shadow: none;
}

.custom-select-option.is-selected > .custom-select-box::after {
  content: "";
  width: 10px;
  height: 10px;
  background: #ffffff;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.6 6.2 5 8.6l4.4-5' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

.custom-select-option.is-exclusive {
  position: relative;
  margin-bottom: 0.6rem;
}

.custom-select-option.is-exclusive::before {
  content: "";
  position: absolute;
  right: 0.2rem;
  bottom: -0.3rem;
  left: 0.2rem;
  height: 1px;
  background: var(--border);
}

.custom-select-option.is-exclusive > .custom-select-box { border-radius: var(--radius-round); }

.custom-select-option.is-exclusive.is-selected > .custom-select-box::after {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-round);
  mask: none;
}

.custom-select-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.35rem;
  padding: 0.45rem 0.55rem;
  border-top: 1px solid var(--border);
}

.custom-select-clear,
.custom-select-done {
  border: 0;
  border-radius: var(--radius-control);
  font: inherit;
  font-size: var(--text-x-small);
  cursor: pointer;
}

.custom-select-clear {
  padding: 0.25rem 0.4rem;
  background: transparent;
  color: var(--info);
}

.custom-select-clear:disabled { color: var(--muted); opacity: 0.5; cursor: default; }

.custom-select-done {
  padding: 0.25rem 0.75rem;
  background: var(--primary);
  color: var(--primary-text);
  font-weight: 600;
}

.custom-select-done:hover { background: var(--primary-hover); }

.custom-select-small {
  width: 11rem;
  max-width: 100%;
}

.custom-select-small .custom-select-trigger {
  min-height: var(--control-height-small);
  padding-block: 0.3rem;
  font-size: var(--text-caption);
}

/* Internal destination link: navigation to another CrowdBoard page. Not
   .alert-ext-link (underlined accent + ↗ reads as "leaves the app") and not a
   button (a filled surface reads as "commits something"). It carries the metrics
   and label type of the disclosure rows it sits among, so it shares their left
   edge and rhythm, but it stops at its own label instead of spanning the column:
   the arrow belongs to the words, not to the row. It travels along its shaft
   where a disclosure chevron rotates. */
.destination-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  width: fit-content;
  max-width: 100%;
  min-height: 2.05rem;
  padding: 0.36rem 0.65rem;
  color: var(--text);
  font-size: var(--text-x-small);
  font-weight: 650;
  letter-spacing: 0.015em;
  text-decoration: none;
  transition: color var(--transition-fast);
}

.destination-link-label { min-width: 0; }

.destination-link-arrow {
  flex: none;
  width: 1rem;
  height: 1rem;
  color: var(--muted);
  transition: color var(--transition-fast), transform var(--transition-fast);
}

.destination-link[href]:hover { color: var(--accent-text); }
.destination-link[href]:hover .destination-link-arrow { color: var(--accent-text); transform: translateX(2px); }

.destination-link:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 65%, transparent);
  outline-offset: 3px;
}

.destination-link[aria-disabled="true"] {
  color: var(--muted);
  cursor: not-allowed;
  opacity: 0.42;
}

@media (prefers-reduced-motion: reduce) {
  .destination-link,
  .destination-link-arrow { transition: none; }
  .destination-link[href]:hover .destination-link-arrow { transform: none; }
}

.form-help { font-size: var(--text-small); color: var(--muted); }
.form-inline { display: flex; gap: var(--space-2); }
.form-input-num { max-width: 6rem; }
.form-input-unit { flex: 1; }
.form-actions { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: 0.5rem; }

.clickable { cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  .clickable:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
}

/* ── Alert inspector modal ─────────────────── */

/* The report is a modal <dialog>. Opening and closing are transitions between
   its open and closed states, so every way of closing it — the buttons, Esc,
   a swipe, Android Back — animates the same way. */
dialog.alert-modal-overlay {
  --alert-exit: 140ms;
  --alert-swipe: 0;
  display: none;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  border: 0;
  color: inherit;
  /* Clip rather than hide: a hidden overflow can still scroll, and focusing
     the panel while it sits off-screen would scroll it into view and cancel
     the slide-in. */
  overflow: clip;
  opacity: 0;
  transition:
    display var(--alert-exit) allow-discrete,
    overlay var(--alert-exit) allow-discrete,
    opacity var(--alert-exit) ease-in,
    background-color var(--alert-exit) ease-in;
}
dialog.alert-modal-overlay[open] {
  display: flex;
  opacity: 1;
  transition: opacity 140ms ease-out, background-color 280ms ease-out;
}
dialog.alert-modal-overlay::backdrop { background: transparent; }
.alert-modal-overlay .alert-detail-panel {
  opacity: 0;
  transform: translateY(6px) scale(0.99);
  transition: opacity var(--alert-exit) ease-in, transform var(--alert-exit) ease-in;
}
.alert-modal-overlay[open] .alert-detail-panel {
  opacity: 1;
  transform: none;
  transition: opacity 180ms cubic-bezier(.22, 1, .36, 1), transform 180ms cubic-bezier(.22, 1, .36, 1);
}
@starting-style {
  dialog.alert-modal-overlay[open] { opacity: 0; }
  .alert-modal-overlay[open] .alert-detail-panel { opacity: 0; transform: translateY(10px) scale(0.985); }
}

/* Mobile: the report is a pushed screen. It slides in from the right and
   leaves the same way, uncovering the page beneath as it goes. */
@media (max-width: 639px) {
  dialog.alert-modal-overlay {
    --alert-exit: 220ms;
    opacity: 1;
    background-color: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  dialog.alert-modal-overlay[open] { background-color: rgb(0 0 0 / calc(0.45 * (1 - var(--alert-swipe)))); }
  .alert-modal-overlay .alert-detail-panel {
    opacity: 1;
    transform: translateX(100%);
    touch-action: pan-y;
    will-change: transform;
    transition: transform var(--alert-exit) cubic-bezier(.4, 0, 1, 1);
  }
  .alert-modal-overlay[open] .alert-detail-panel {
    transform: none;
    transition: transform 280ms cubic-bezier(.22, 1, .36, 1);
  }
  .alert-detail-panel .modal-body {
    touch-action: pan-y;
    -webkit-overflow-scrolling: touch;
  }
  dialog.alert-modal-overlay.is-dragging,
  .alert-modal-overlay .alert-detail-panel.is-dragging { transition: none; }
  @starting-style {
    dialog.alert-modal-overlay[open] { opacity: 1; background-color: transparent; }
    .alert-modal-overlay[open] .alert-detail-panel { transform: translateX(100%); }
  }
}

/* Inside the report, toasts sit at the bottom of the screen: there is no
   bottom navigation to clear. */
@media (max-width: 959px) {
  .alert-modal-toasts { bottom: calc(var(--safe-b) + 1rem); }
}

.alert-modal-content { min-height: 100%; }
.alert-detail-panel:focus { outline: none; }

.alert-modal-close {
  position: absolute;
  z-index: 6;
  top: 0.8rem;
  right: 3.5rem;
  border-color: color-mix(in srgb, var(--border) 76%, transparent);
  background: color-mix(in srgb, var(--panel) 72%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

@media (min-width: 640px) {
  .alert-detail-panel {
    height: min(92dvh, 56rem);
    min-height: min(36rem, 88dvh);
  }

  /* Keep the scrollbar inside the rounded shell instead of letting the
     outer modal body run its rail into the bottom-right corner. */
  .alert-detail-panel .modal-body {
    overflow: hidden;
    padding: 0.35rem 0 0.45rem;
    scrollbar-gutter: auto;
  }

  .alert-modal-content {
    --alert-scroll-thumb: color-mix(in srgb, var(--muted) 68%, var(--panel));
    height: 100%;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-gutter: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--alert-scroll-thumb) transparent;
  }

  .alert-modal-content::-webkit-scrollbar { width: 8px; }
  .alert-modal-content::-webkit-scrollbar-button {
    display: none;
    width: 0;
    height: 0;
  }
  .alert-modal-content::-webkit-scrollbar-track {
    margin-block: 0.45rem;
    background: transparent;
  }
  .alert-modal-content::-webkit-scrollbar-thumb {
    min-height: 2.5rem;
    border-radius: var(--radius-pill);
    background-color: var(--alert-scroll-thumb);
  }
  .alert-modal-content:hover::-webkit-scrollbar-thumb {
    background-color: color-mix(in srgb, var(--muted) 84%, var(--panel));
  }

  .alert-detail-panel:not(.is-update) .modal-body { padding-right: 0.35rem; }
  .alert-detail-panel:not(.is-update) .alert-modal-close { right: 1.35rem; }
}

.alert-modal-content .alert-inspector { opacity: 0; transform: translateY(4px); }
.alert-modal-content.is-ready .alert-inspector { opacity: 1; transform: none; transition: opacity 100ms ease-out, transform 120ms ease-out; }

.alert-inspector {
  gap: 0;
}

.alert-inspector-hero {
  position: relative;
}

.alert-inspector-identity { min-width: 0; }
.alert-inspector-identity h2 {
  margin: 0;
  font-family: var(--font-display);
  line-height: 1.18;
  letter-spacing: -0.025em;
  overflow-wrap: anywhere;
}

.alert-scenario-full {
  font-size: var(--text-small);
  color: var(--muted);
  margin-top: 0.2rem;
  word-break: break-word;
}

.alert-inspector-hero .alert-chips,
.alert-inspector-hero .alert-message,
.alert-inspector-hero .alert-timeline,
.alert-inspector-hero .alert-links,
.alert-inspector-hero .alert-coverage-expander {
  grid-column: 1 / -1;
}

.alert-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.alert-message {
  line-height: 1.45;
  margin: 0;
}

.alert-timeline {
  display: flex;
  flex-wrap: wrap;
}

.alert-metric {
  display: grid;
  gap: 0.1rem;
}

.alert-metric-label {
  font-size: var(--text-micro);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.alert-metric-value {
  font-size: var(--text-compact);
  font-variant-numeric: tabular-nums;
}

.alert-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.alert-ext-link {
  font-size: var(--text-compact);
  font-weight: 500;
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent-text) 40%, transparent);
  text-underline-offset: 0.15em;
}

.alert-ext-link:hover {
  color: var(--text);
  text-decoration-color: color-mix(in srgb, var(--text) 50%, transparent);
}

.alert-ext-link[aria-disabled="true"] {
  color: var(--muted);
  text-decoration-color: color-mix(in srgb, var(--muted) 35%, transparent);
  cursor: not-allowed;
}

.alert-ext-link[aria-disabled="true"]:hover {
  color: var(--muted);
  text-decoration-color: color-mix(in srgb, var(--muted) 35%, transparent);
}

.alert-coverage-expander {
  width: min(100%, var(--alert-coverage-collapsed-width, 15.5rem));
  min-width: 0;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--border) 82%, transparent);
  border-radius: var(--radius-surface);
  background: color-mix(in srgb, var(--panel-2) 94%, var(--accent) 6%);
  transition:
    width 120ms ease-out,
    border-color var(--transition-fast),
    box-shadow 120ms ease-out;
}

@media (min-width: 640px) {
  .alert-links { width: fit-content; }
}

.alert-coverage-expander.is-open {
  width: 100%;
  border-color: color-mix(in srgb, var(--accent) 24%, var(--border));
  box-shadow: var(--shadow-panel);
}

.alert-coverage-expander.is-sizing { transition: none; }

.alert-coverage-trigger {
  -webkit-tap-highlight-color: transparent;
  appearance: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 1rem;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 2.05rem;
  padding: 0.36rem 0.65rem;
  border: 0;
  border-radius: inherit;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.69rem;
  font-weight: 650;
  letter-spacing: 0.015em;
  text-align: left;
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

.alert-coverage-trigger:hover:not(:disabled),
.alert-coverage-trigger[aria-expanded="true"] {
  background: transparent;
  color: var(--text);
}

.alert-coverage-trigger:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--accent) 65%, transparent);
  outline-offset: 3px;
}

.alert-coverage-trigger-chevron {
  width: 1rem;
  height: 1rem;
  color: var(--muted);
  transition: color var(--transition-fast), transform var(--transition-fast);
}

.alert-coverage-trigger:hover:not(:disabled) .alert-coverage-trigger-chevron,
.alert-coverage-trigger[aria-expanded="true"] .alert-coverage-trigger-chevron { color: var(--accent-text); }
.alert-coverage-trigger[aria-expanded="true"] .alert-coverage-trigger-chevron { transform: rotate(180deg); }

.alert-coverage-trigger:disabled {
  background: transparent;
  color: var(--muted);
  cursor: not-allowed;
  opacity: 0.42;
}

.alert-coverage-disclosure {
  display: grid;
  grid-template-rows: 0fr;
  min-width: 0;
  opacity: 0;
  transition:
    grid-template-rows 120ms ease-out,
    opacity 80ms ease-out;
}

.alert-coverage-expander.is-open .alert-coverage-disclosure {
  grid-template-rows: 1fr;
  opacity: 1;
}

.alert-coverage-disclosure > turbo-frame {
  display: block;
  min-height: 0;
  overflow: hidden;
}

.alert-coverage-disclosure[hidden],
.alert-coverage-result[hidden] { display: none !important; }

.alert-coverage-card {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-4);
  border: 0;
  border-top: 1px solid color-mix(in srgb, var(--accent) 20%, var(--border));
  border-radius: 0;
  background: transparent;
}

.alert-coverage-summary {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
}

.alert-coverage-heading h3 {
  margin: 0;
  font-size: var(--text-normal);
  font-weight: 700;
}

.alert-coverage-logic {
  margin: 0.22rem 0 0;
  color: var(--muted);
  font-size: var(--text-small);
  line-height: 1.45;
}

.alert-coverage-picker {
  display: grid;
  gap: 0.38rem;
  width: min(100%, 28rem);
}

.alert-coverage-picker > label {
  color: var(--muted);
  font-size: 0.66rem;
  font-weight: 600;
}

.alert-coverage-result { display: grid; gap: 0.85rem; }
.alert-coverage-summary { align-items: center; }
.alert-coverage-summary > div { display: grid; gap: 0.18rem; }
.alert-coverage-summary strong { font-size: var(--text-normal); font-weight: 650; }

.alert-coverage-state {
  width: fit-content;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.alert-coverage-result.is-covered .alert-coverage-state { color: var(--success); }
.alert-coverage-result.is-not-covered .alert-coverage-state { color: var(--danger); }
.alert-coverage-result.is-unavailable .alert-coverage-state { color: var(--warning); }

.alert-coverage-requirements {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.55rem;
}

.alert-coverage-requirement {
  display: grid;
  grid-template-columns: 1.35rem minmax(0, 1fr);
  gap: 0.55rem;
  min-width: 0;
  padding: 0.7rem;
  border-radius: var(--radius-surface);
  background: color-mix(in srgb, var(--panel) 80%, transparent);
}

.alert-coverage-requirement-icon {
  display: grid;
  place-items: center;
  width: 1.2rem;
  height: 1.2rem;
  border-radius: var(--radius-round);
  background: color-mix(in srgb, var(--muted) 12%, transparent);
  color: var(--muted);
  font-size: var(--text-caption);
  font-weight: 750;
}

.alert-coverage-requirement.is-match .alert-coverage-requirement-icon {
  background: color-mix(in srgb, var(--success) 14%, transparent);
  color: var(--success);
}

.alert-coverage-requirement.is-no_match .alert-coverage-requirement-icon {
  background: color-mix(in srgb, var(--danger) 13%, transparent);
  color: var(--danger);
}

.alert-coverage-requirement.is-unavailable .alert-coverage-requirement-icon {
  background: color-mix(in srgb, var(--warning) 13%, transparent);
  color: var(--warning);
}

.alert-coverage-requirement strong {
  display: block;
  font-size: 0.73rem;
  font-weight: 680;
}

.alert-coverage-requirement dl { display: grid; gap: 0.2rem; margin: 0.4rem 0 0; }
.alert-coverage-requirement dl > div { display: grid; grid-template-columns: 4rem minmax(0, 1fr); gap: 0.45rem; }
.alert-coverage-requirement dt {
  color: var(--muted);
  font-size: var(--text-xx-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.alert-coverage-requirement dd {
  min-width: 0;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  overflow-wrap: anywhere;
}
.alert-coverage-requirement p { margin: 0.4rem 0 0; color: var(--muted); font-size: 0.66rem; line-height: 1.4; }

.alert-coverage-empty { color: var(--muted); font-size: var(--text-small); }
.alert-coverage-empty strong { color: var(--text); font-size: var(--text-control); }

.alert-coverage-loading { display: grid; gap: 0.45rem; padding: var(--space-4); }
.alert-coverage-loading span {
  width: 100%;
  height: 0.7rem;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--panel), var(--panel-2), var(--panel));
  background-size: 220% 100%;
  animation: alert-skeleton-shimmer 1.15s linear infinite;
}
.alert-coverage-loading span:first-child { width: 38%; }
.alert-coverage-loading span:last-child { width: 72%; }

.alert-detail-section {
  padding: 1rem 0.15rem;
  border-bottom: 1px solid var(--border);
}

.alert-section-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: 0.7rem;
}

.alert-section-heading h3 {
  font-size: var(--text-small);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text);
  margin: 0;
  font-weight: 700;
}

.alert-section-heading > span { color: var(--muted); font-size: 0.7rem; }
.alert-context-section { padding-top: 1.15rem; }

.alert-muted {
  font-size: var(--text-compact);
  color: var(--muted);
  margin: 0;
}

.alert-kv-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.45rem 1rem;
}

@media (min-width: 520px) {
  .alert-kv-grid { grid-template-columns: 1fr 1fr; }
  .alert-context-section .alert-kv-grid { grid-template-columns: auto auto; }
}

.alert-kv {
  display: grid;
  align-content: start;
  gap: 0.1rem;
  min-width: 0;
}

.alert-kv dt,
.alert-kv dd { margin: 0; }

.alert-kv-key {
  font-size: var(--text-micro);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
}

.alert-kv-value {
  font-size: 0.84rem;
  word-break: break-word;
  line-height: 1.35;
}

.alert-kv-value.is-unlogged {
  color: color-mix(in srgb, var(--muted) 60%, var(--text));
  font-style: italic;
}

.alert-context-line {
  display: block;
  overflow-wrap: anywhere;
}

.alert-update-inspector {
  --update-surface: var(--panel-2);
  --update-line: var(--border);
}

.alert-update-details {
  grid-column: 1 / -1;
  display: grid;
  gap: var(--space-3);
  min-width: 0;
}

.alert-update-details .alert-detail-section { padding: 0; overflow: hidden; }
.alert-update-details .alert-section-heading {
  margin: 0;
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--update-line);
}

/* Two metrics on the left against four on the right, so the sides split 1:2 —
   every metric column then comes out the same width across the whole panel. */
.alert-update-comparison {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
}

.alert-update-comparison-side { padding: 1.15rem 1.25rem; }
.alert-update-comparison-side > strong { display: block; margin-bottom: 0.8rem; font-size: var(--text-normal); }
.alert-update-comparison-side.is-reported {
  border-right: 1px solid var(--update-line);
}

.alert-update-number-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
.alert-update-number-grid.is-effective { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.alert-update-number {
  min-width: 0;
  padding: 0.2rem 0.8rem;
  border-left: 1px solid var(--update-line);
}
.alert-update-number:first-child {
  padding-left: 0;
  border-left: 0;
}
.alert-update-number span,
.alert-update-flow div span {
  display: block;
  color: var(--muted);
  font-size: var(--text-micro);
  letter-spacing: 0.055em;
  text-transform: uppercase;
}
.alert-update-number strong { display: block; margin-top: 0.3rem; font: 700 1.45rem/1 var(--font-mono); }
.alert-update-number.is-positive strong,
.alert-update-summary-row .is-success { color: var(--success); }
.alert-update-number.is-negative strong { color: var(--danger); }

.alert-update-flow {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  padding: 1px 0 0;
  border-top: 1px solid var(--update-line);
  background: var(--update-line);
}
.alert-update-flow > div { padding: 0.85rem 1.25rem; background: color-mix(in srgb, var(--update-surface) 72%, var(--panel)); }
.alert-update-flow > div strong { display: block; margin-top: 0.15rem; font-family: var(--font-mono); font-size: var(--text-control); }

.alert-update-summary-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
.alert-update-summary-row .alert-kv-grid { padding: 1rem; }
.alert-update-categories { display: grid; gap: 0.65rem; padding: 1rem; }
.alert-update-category-label { display: flex; justify-content: space-between; gap: var(--space-3); margin-bottom: 0.3rem; color: var(--muted); font-size: var(--text-small); }
.alert-update-category-label strong { color: var(--text); font-family: var(--font-mono); }
.alert-update-category-track { height: 0.3rem; overflow: hidden; border-radius: var(--radius-compact); background: var(--update-surface); }
.alert-update-category-track span { display: block; min-width: 2px; height: 100%; background: var(--info); }
.alert-update-pending { padding-bottom: 1rem !important; }
.alert-update-pending > p { padding: 0 1rem; }

@media (max-width: 639px) {
  .alert-update-comparison { grid-template-columns: minmax(0, 1fr); }
  .alert-update-comparison-side.is-reported { border-right: 0; border-bottom: 1px solid var(--update-line); }
  /* Two-up rather than one-up. Stacked one per row, the outcome ran four rows
     deep and pushed itself away from the announced figures it exists to be
     compared against; at two columns both sides read at the same width. */
  .alert-update-number-grid.is-effective {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 0.9rem;
  }
  /* Every row starts a fresh column, so the divider belongs to the second of
     each pair — not to the first child alone, as it does in one row of four. */
  .alert-update-number-grid.is-effective .alert-update-number:nth-child(odd) {
    padding-left: 0;
    border-left: 0;
  }
  .alert-update-summary-row { grid-template-columns: minmax(0, 1fr); }
}

.alert-context-line + .alert-context-line { margin-top: 0.12rem; }

.alert-source-country {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.alert-source-country-flag {
  display: block;
  width: 2rem;
  height: 1.375rem;
  flex: 0 0 auto;
  object-fit: contain;
}

.alert-decision-list {
  display: grid;
  gap: 0.38rem;
}

.alert-decision {
  --decision-tone: var(--accent-text);
  --decision-surface: color-mix(in srgb, var(--bg) 78%, var(--panel));
  --decision-action-surface: var(--panel-2);
  isolation: isolate;
  display: grid;
  grid-template-columns: 1rem minmax(0, 1fr) auto;
  grid-template-areas: "kind body actions";
  align-items: center;
  gap: 0.55rem;
  min-width: 0;
  overflow: hidden;
  padding: 0.7rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-surface);
  background: var(--decision-surface);
  font-size: var(--text-compact);
}

.alert-decision[data-type="ban"] { --decision-tone: var(--danger); }
.alert-decision[data-type="captcha"] { --decision-tone: var(--warning); }
.alert-decision[data-type="throttle"] { --decision-tone: var(--info); }
.alert-decision.is-inactive { background: color-mix(in srgb, var(--decision-surface) 72%, transparent); }
.alert-decision.is-inactive .alert-decision-kind { opacity: 0.55; }

.alert-decision-kind {
  grid-area: kind;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--decision-tone);
}

.alert-decision-type {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: 0.16em;
  line-height: 1;
  text-transform: uppercase;
}

.alert-decision-body {
  grid-area: body;
  display: grid;
  gap: 0.42rem;
  min-width: 0;
  padding: 0;
}

.alert-decision-headline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.28rem 0.55rem;
  min-width: 0;
}

.alert-decision-value {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

.alert-decision-state,
.alert-decision-simulated {
  color: var(--muted);
  font-size: 0.6rem;
  font-weight: 550;
  line-height: 1.2;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.alert-decision-state {
  display: inline-flex;
  align-items: center;
}

.alert-decision-state::before {
  content: "";
  display: block;
  flex: 0 0 auto;
  width: 0.32rem;
  height: 0.32rem;
  margin-right: 0.28rem;
  border-radius: var(--radius-pill);
  background: currentColor;
}

.alert-decision-state.is-active { color: color-mix(in srgb, var(--success) 48%, var(--muted)); }
.alert-decision-state.is-inactive,
.alert-decision-state.is-unknown { color: var(--muted); }
.alert-decision-simulated { color: color-mix(in srgb, var(--warning) 55%, var(--muted)); }

.alert-decision-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.85rem;
}

.alert-decision-fact {
  display: grid;
  gap: 0.08rem;
  min-width: 0;
}

.alert-decision-fact-key {
  color: var(--muted);
  font-size: var(--text-xx-small);
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.alert-decision-fact-value .nowrap { white-space: nowrap; }

.alert-decision-fact-value {
  color: var(--text);
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.25;
}

.alert-decision-actions {
  grid-area: actions;
  align-self: center;
  margin: 0;
}

.compact-action-bar {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.2rem;
  padding: 0.2rem;
  border: 1px solid color-mix(in srgb, var(--border) 86%, transparent);
  border-radius: var(--radius-surface);
  background: color-mix(in srgb, var(--panel) 68%, transparent);
}
.alert-decision .compact-action-bar {
  padding: 0.1rem;
  background: var(--decision-action-surface);
}
.compact-action-bar form { display: contents; margin: 0; }
.compact-action {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-height: 1.9rem;
  margin: 0;
  padding: 0.35rem 0.52rem;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: var(--text-x-small);
  font-weight: 680;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}
.compact-action-bar > .compact-action:not(:first-child)::before,
.compact-action-bar > form:not(:first-child) .compact-action::before {
  content: "";
  position: absolute;
  top: 22%;
  bottom: 22%;
  left: -0.1rem;
  width: 1px;
  background: color-mix(in srgb, var(--border) 72%, transparent);
  transition: opacity var(--transition-fast);
  pointer-events: none;
}
.compact-action:focus-visible::before,
.compact-action-bar > .compact-action:focus-visible + .compact-action::before,
.compact-action-bar > .compact-action:focus-visible + form .compact-action::before {
  opacity: 0;
}
.compact-action svg { width: 0.82rem; height: 0.82rem; flex: 0 0 auto; }
.alert-decision .compact-action {
  gap: 0.24rem;
  min-height: 1.65rem;
  padding: 0.27rem 0.33rem;
  font-size: var(--text-micro);
}
.compact-action-danger { color: color-mix(in srgb, var(--danger) 88%, var(--text)); }

/* Selected. The bar has always had a hover state and never an on state, so a
   pressed action was indistinguishable from its neighbours. */
.compact-action.is-on,
.compact-action[aria-pressed="true"] {
  color: var(--accent-text);
  background: var(--accent-soft);
}

/* A divider against a filled action reads as an edge on the fill. */
.compact-action.is-on::before,
.compact-action[aria-pressed="true"]::before,
.compact-action-bar > .compact-action.is-on + .compact-action::before,
.compact-action-bar > .compact-action[aria-pressed="true"] + .compact-action::before { opacity: 0; }

/* Shown but not available, e.g. to a demo guest. */
.compact-action[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }

@media (hover: hover) and (pointer: fine) {
  .compact-action:not([aria-disabled="true"]):hover { color: var(--text); background: color-mix(in srgb, var(--text) 7%, transparent); }
  .compact-action-danger:not([aria-disabled="true"]):hover { color: var(--danger); background: color-mix(in srgb, var(--danger) 11%, transparent); }
  .compact-action:hover::before,
  .compact-action-bar > .compact-action:hover + .compact-action::before,
  .compact-action-bar > .compact-action:hover + form .compact-action::before { opacity: 0; }
}
.alert-preview-note { margin: 0.65rem 0 0; color: var(--muted); font-size: var(--text-small); line-height: 1.4; }
/* The address carries the caution the per-card badge used to, so the sentence
   around it can stay plain. */
.alert-decision-notes .mono { color: color-mix(in srgb, var(--warning) 55%, var(--muted)); }

.alert-event-list {
  display: grid;
  gap: 0.4rem;
}

.alert-event {
  border: 1px solid var(--border);
  border-radius: var(--radius-surface);
  padding: 0.35rem 0.55rem 0.45rem;
  background: var(--panel-2);
}

.alert-event-summary {
  -webkit-tap-highlight-color: transparent;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.55rem;
  cursor: pointer;
  list-style: none;
  font-size: var(--text-compact);
}

.alert-event-summary::-webkit-details-marker { display: none; }

.alert-event-index {
  font-family: var(--font-mono);
  font-size: var(--text-small);
  color: var(--muted);
}

.alert-event-title {
  font-weight: 500;
  flex: 1;
  min-width: 12ch;
  word-break: break-word;
}

.alert-event-time {
  font-size: var(--text-small);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.alert-event-meta {
  margin-top: 0.55rem;
  padding-top: 0.45rem;
  border-top: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
}

.alert-inspector > .alert-detail-section:last-of-type { padding-bottom: 0.25rem; border-bottom: 0; }

.alert-skeleton { display: grid; gap: 0.85rem; padding: var(--space-4); }
.alert-skeleton-hero,
.alert-skeleton-section {
  display: grid;
  gap: 0.7rem;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  background: var(--panel-2);
}
.alert-skeleton-section { border-radius: var(--radius-panel); background: var(--panel); }
.alert-skeleton-line,
.alert-skeleton-chips span {
  display: block;
  height: 0.72rem;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, color-mix(in srgb, var(--text) 7%, transparent), color-mix(in srgb, var(--text) 13%, transparent), color-mix(in srgb, var(--text) 7%, transparent));
  background-size: 220% 100%;
  animation: alert-skeleton-shimmer 1.15s linear infinite;
}
.alert-skeleton-line.is-short { width: 24%; }
.alert-skeleton-line.is-medium { width: 58%; }
.alert-skeleton-line.is-title { width: 72%; height: 1.45rem; }
.alert-skeleton-chips { display: flex; gap: 0.4rem; }
.alert-skeleton-chips span { width: 4.5rem; height: 1.25rem; }
@keyframes alert-skeleton-shimmer { from { background-position: 100% 0; } to { background-position: -120% 0; } }

/* Open report: one presentation, shared by every theme. */
.alert-detail-panel {
  border-radius: var(--radius-dialog);
}
.alert-report-bar {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.4rem 0.4rem 0.4rem 1.4rem;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font: var(--text-x-small) var(--font-mono);
}
.alert-detail-panel .alert-modal-close {
  position: static;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  background: transparent;
  border-color: transparent;
  backdrop-filter: none;
}
.alert-detail-panel .modal-body { padding: 0; min-height: 0; }
.alert-modal-back {
  display: none;
  flex: none;
  align-items: center;
  gap: 0.1rem;
  min-height: var(--tap-target);
  padding: 0 0.75rem 0 0.35rem;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--accent-text);
  font: 500 var(--text-medium) var(--font);
  cursor: pointer;
}
.alert-modal-back svg { width: 1.25rem; height: 1.25rem; }
.alert-inspector { display: block; padding: 1.5rem 1.9rem; }
.alert-inspector-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.8rem;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  overflow: visible;
}
.alert-inspector-identity h2 { font-size: 1.9rem; font-weight: 600; }
.alert-message { font-size: var(--text-caption); color: var(--muted); }
.alert-timeline { border-bottom: 1px solid var(--border); padding: 0.3rem 0 1.1rem; gap: 1rem 1.75rem; }
.alert-metric-value { font: var(--text-x-small) var(--font-mono); }
.alert-report-nav { display: flex; gap: 1.25rem; overflow-x: auto; scrollbar-width: thin; }
.alert-report-nav a { padding: 0.85rem 0; color: var(--muted); font-size: var(--text-x-small); white-space: nowrap; text-decoration: none; }
.alert-report-nav a:hover { color: var(--accent-text); }
.alert-report-sections > .alert-detail-section {
  position: relative;
  min-width: 0;
  min-height: 5.5rem;
  padding: 1.4rem 0 1.4rem 10.4rem;
  border: 0;
  border-top: 1px solid var(--border);
  scroll-margin: 1rem;
}
.alert-report-sections > .alert-detail-section:focus { outline: none; }
.alert-report-sections > .alert-detail-section:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.alert-report .alert-section-heading {
  position: absolute;
  top: 1.4rem;
  left: 0;
  width: 9rem;
  display: flex;
  flex-direction: column;
  align-items: start;
  justify-content: flex-start;
  gap: 0.35rem;
  margin: 0;
}
.alert-report .alert-section-heading h3 { font-size: var(--text-normal); font-weight: 600; letter-spacing: 0; text-transform: none; }
.alert-report .alert-section-heading .alert-section-number { color: var(--accent-text); font: var(--text-micro) var(--font-mono); margin-bottom: 0.3rem; }
.alert-report .alert-kv-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem 1.5rem; }
.alert-context-grid { align-items: start; }
.alert-report .alert-context-grid.is-left-wide { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.alert-report .alert-context-grid.is-right-wide { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
.alert-report .alert-context-grid.is-single-wide { grid-template-columns: minmax(0, 1fr); }
.alert-report .alert-kv-key { text-transform: none; letter-spacing: 0; font-size: var(--text-micro); }
.alert-report .alert-kv-value { font-size: var(--text-caption); }
.alert-report .alert-source-country-flag { width: 1.75rem; height: 1.15rem; }
.alert-source-address { font-size: 1.3rem; font-weight: 500; letter-spacing: -0.035em; margin-bottom: 1rem; overflow-wrap: anywhere; }
.alert-source-section .alert-links { margin-top: 1rem; }
.alert-whitelist-section .alert-links { margin-bottom: 0.35rem; }
.alert-reputation { display: grid; gap: 0.85rem; min-width: 0; }
/* The heading column (number, title, "CrowdSec CTI") outgrows a lone button. */
@media (min-width: 640px) {
  .alert-report-sections > .alert-reputation-section { min-height: 6.75rem; }
}
.alert-reputation form { display: contents; }
.alert-reputation .info-admonition { margin: 0; }
.alert-reputation-verdict { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; }
.alert-reputation-confidence { color: var(--muted); font-size: var(--text-x-small); }
.alert-reputation-problem { margin: 0; color: var(--warning); font-size: var(--text-small); line-height: 1.4; }
.alert-reputation-action,
.alert-reputation-footer { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.9rem; }
.alert-reputation-footer,
.alert-reputation-hint { color: var(--muted); font-size: var(--text-x-small); }
.alert-reputation-refresh {
  appearance: none;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--accent-text);
  font: inherit;
  font-weight: 500;
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent-text) 40%, transparent);
  text-underline-offset: 0.15em;
  cursor: pointer;
}
.alert-reputation-refresh:hover:not(:disabled) { color: var(--text); }
.alert-reputation-refresh:disabled { color: var(--muted); cursor: progress; }
.alert-report .alert-coverage-expander { width: 100%; background: transparent; border: 0; border-radius: 0; box-shadow: none; }
.alert-report .alert-coverage-trigger { padding-inline: 0; }
.alert-report .destination-link { padding-inline: 0; }
.alert-report .alert-coverage-card { padding-inline: 0; }
.alert-report .alert-decision {
  width: fit-content;
  max-width: 100%;
  justify-self: start;
  gap: 0.6rem;
  padding: 0.7rem;
}
.alert-report .alert-decision-actions { justify-self: end; }
.alert-report .alert-decision .compact-action { min-height: 1.9rem; font-size: var(--text-x-small); padding: 0.35rem 0.52rem; }
.alert-report .alert-event { background: transparent; border: 0; border-top: 1px solid var(--border); border-radius: 0; }
.alert-report .alert-event-summary { padding: 0.65rem 0; }
.alert-report .alert-event-meta { padding: 0.8rem; background: var(--panel-2); }
.alert-report .alert-event-title { font-size: var(--text-small); }
.alert-report .alert-preview-note { font-size: var(--text-x-small); }

/* Community updates share the shell and typography, retaining their comparison. */
.alert-update-inspector .alert-update-details { margin-top: 1.25rem; }
.alert-update-inspector .alert-detail-section { border: 1px solid var(--border); border-radius: var(--radius-surface); padding: 0; }

@media (min-width: 640px) {
  .alert-detail-panel { width: min(60rem, calc(100vw - 3rem)); max-width: min(60rem, calc(100vw - 3rem)); }
  .alert-report .alert-decision-actions { margin-left: 3rem; }
}
@media (max-width: 639px) {
  .alert-detail-panel { border: 0; border-radius: 0; }
  .alert-report-bar { padding: 0.35rem 1rem 0.35rem 0.25rem; }
  .alert-detail-panel .alert-modal-close { display: none; }
  .alert-modal-back { display: inline-flex; }
  .alert-inspector { padding: 1.2rem 1.1rem calc(1.2rem + var(--safe-b)); }
  .alert-inspector-identity h2 { font-size: 1.65rem; }
  .alert-timeline { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.5rem; }
  .alert-metric-value { font-size: var(--text-micro); line-height: 1.6; }
  .alert-report-sections > .alert-detail-section { padding: 1.25rem 0; }
  .alert-report .alert-section-heading { position: static; width: auto; flex-direction: row; align-items: baseline; gap: 0.6rem; margin-bottom: 1rem; }
  .alert-report .alert-section-heading > span:last-child:not(.alert-section-number) { margin-left: auto; }
  .alert-report .alert-section-heading .alert-section-number { margin: 0; }
  .alert-report .alert-kv-grid { gap: 0.9rem 1rem; }
  .alert-report .alert-context-grid.has-long-value { grid-template-columns: minmax(0, 1fr); }
  .alert-report .alert-decision { width: 100%; }
  .alert-event-time { display: none; }
  .alert-coverage-requirements { grid-template-columns: minmax(0, 1fr); }
  .alert-coverage-summary { align-items: flex-start; }
  .alert-coverage-requirement dl > div { grid-template-columns: 3.65rem minmax(0, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
  dialog.alert-modal-overlay, .alert-modal-overlay .alert-detail-panel { transition: none !important; }
  .alert-skeleton-line, .alert-skeleton-chips span { animation: none !important; }
  .alert-modal-content.is-ready .alert-inspector,
  .alert-coverage-expander, .alert-coverage-disclosure { transition: none; }
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

/* The dashboard shows two cards, so two columns suits it. Metrics shows four,
   and two-up gave each of them ~590px to hold a label and a number. */
@media (min-width: 720px) {
  .metrics-page .stats-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* One card used the small value size and three used the large one, which read
   as an accident rather than a distinction. */
.metrics-page .stat-value-sm { font-size: 1.55rem; font-weight: 700; }

.stat-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 0.9rem 1rem;
  box-shadow: var(--shadow-panel);
}

.stat-label {
  font-size: var(--text-x-small);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 600;
}

.stat-value {
  font-family: var(--font-display);
  font-size: 1.55rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  margin-top: 0.15rem;
  line-height: 1.15;
}

.stat-value-sm { font-size: 1.05rem; font-weight: 600; }

.stat-card.danger .stat-value { color: var(--danger); }
.stat-card.warning .stat-value { color: var(--warning); }
.stat-card.success .stat-value { color: var(--success); }
.stat-card.info .stat-value { color: var(--info); }
.stat-card.accent .stat-value { color: var(--accent-text); }

/* ── Dashboard console ─────────────────────────────────────────────────────
   A 12-column grid placed entirely by auto-flow. Each slot stores only its
   width; position falls out of order + wrapping, so there are no coordinates
   to keep consistent. Placement is sparse: a row whose remainder cannot fit
   the next card ends ragged. grid-auto-flow:dense would close those gaps by
   pulling later cards forward, which silently breaks the order the customise
   panel promises. */
/* Holds only the catch-up indicator, which is hidden until a catch-up runs.
   Reserving its height unconditionally put ~48px of empty space above the
   first card, so it collapses to nothing until it has something to show. */
.dash-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
}

.dash-toolbar:has(> :not([hidden])) {
  margin-bottom: var(--space-4);
  min-height: 2rem;
}

/* Sections stack; columns sit side by side inside one; cards stack inside a
   column. That third level is the whole point — it is what lets two short
   cards share a row with one tall one, which a flat grid cannot express. */
/* One gap, named once. The divider is positioned by arithmetic that includes
   the gap, so a second place to change it is a second place to get it wrong —
   editing widens this and every dependent follows. */
.dash-console {
  --dash-gap: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--dash-gap);
}

.dash-section {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--dash-gap);
}

.dash-column {
  grid-column: span var(--col-w, 12);
  display: flex;
  flex-direction: column;
  gap: var(--dash-gap);
  min-width: 0;
}

.tile-slot { min-width: 0; }

/* Explicit rather than relying on the UA rule for [hidden]: hidden cards stay
   in the DOM so the broadcast keeps morphing them. */
.dash-console .tile-slot[hidden] { display: none; }

/* A row holding no cards is a spacer, so a board can be composed with empty
   space at the top, the bottom, or between two groups — the same job the
   empty columns already do inside a row.

   The test is for the slot, not for a visible card, and it deliberately does
   not match the editing rule further down that keys on `:not([hidden])`. That
   one is asking "can a card be dropped here", and a column whose only cards are
   hidden can. This one is asking "were any cards ever put in this row", and a
   hidden card's slot stays in the DOM (see above). Key this on visibility
   instead and hiding the last card in a row grows 2rem of whitespace where the
   row was, pushing the board down — hiding a card would add space rather than
   reclaim it.

   `:empty` cannot serve either: a section always holds its columns, and while
   editing the controller appends dividers, adders and the drag ghost into them.

   One rule on the row rather than one per column: a part-empty row has slots
   and is not a spacer, so its gaps stay the grid's business. */
.dash-section:not(:has(.tile-slot)) { min-height: 2rem; }
/* display: grid above beats the UA's [hidden] rule on its own. */
.dash-section[hidden] { display: none; }

/* ── Layout editing ─────────────────────────────────────────────────────────
   A mode, not a page: the grid is the same DOM, with handles revealed, cards
   made inert so a row underneath cannot be clicked or tabbed into, and the
   two-column dividers rendered by the controller. */
.tile-slot { position: relative; }

.tile-drag {
  position: absolute;
  top: 0.35rem;
  right: 0.35rem;
  z-index: 2;
  display: none;
  place-items: center;
  /* Square, so it reads as a grip rather than a button with a label in it. */
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-compact);
  background: var(--panel-2);
  color: var(--muted);
  cursor: grab;
  /* Handles only: the page still has to scroll under a finger everywhere else. */
  touch-action: none;
}

.tile-drag svg { width: 0.95rem; height: 0.95rem; }

/* The board loosens up while it is being edited: wider gaps for the divider
   and the row inserters to live in without overhanging a card, and a lane
   either side for the column adders. It reflows once, on an explicit click —
   unlike a hover affordance, which must never move the page. */
[data-editing="true"] .dash-console {
  --dash-gap: 1.5rem;
  padding-inline: 1.5rem;
}

[data-editing="true"] .tile-drag { display: grid; }
[data-editing="true"] .tile-drag:hover { color: var(--text); border-color: var(--accent); }
[data-editing="true"] .dash-console { user-select: none; }
[data-editing="true"] .tile-slot { outline: 1px dashed var(--border); outline-offset: 2px; }

/* An empty column is invisible until you are arranging, and then it is the
   thing you are aiming at.

   The floor sits on every column rather than on :empty ones alone. A column
   holding the placeholder is not :empty, and the drop measurement hides the
   placeholder rather than removing it — so an :empty-only floor collapses the
   column to nothing at the exact moment it is measured. The target would then
   exist while the placeholder is elsewhere and vanish the instant it arrives,
   which is a flip on every pointer move. */
[data-editing="true"] .dash-column { min-height: 4rem; }

/* Outlined by what it holds rather than by :empty, so a column whose only
   cards are hidden reads as the drop target it is. The placeholder is excluded
   because it brings its own outline. */
[data-editing="true"] .dash-column:not(:has(> .tile-slot:not([hidden]), > .tile-ghost)) {
  border: 1px dashed var(--border);
  border-radius: var(--radius-large);
}

/* Why a column that reads as empty refuses to be removed. Centred in the drop
   area it explains, and only while editing — the controller builds it with the
   rest of the editing chrome. */
.dash-column-hidden {
  margin: auto;
  padding: 0.85rem 0.75rem;
  color: var(--muted);
  font-size: var(--text-small);
  line-height: 1.35;
  text-align: center;
  text-wrap: balance;
}

/* Placed in viewport coordinates by the controller, so margins must not add
   an offset the maths does not know about. */
.tile-slot.is-dragging {
  position: fixed;
  margin: 0;
  z-index: 120;
  pointer-events: none;
  opacity: 0.9;
  cursor: grabbing;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
}

.tile-ghost {
  border: 1px dashed var(--accent);
  border-radius: var(--radius-large);
  background: var(--accent-soft);
}

/* Add and remove, on the board. Absolutely positioned in the gaps the editing
   mode opens up, so revealing one on hover changes no layout at all: a control
   that reflows the page under the cursor is how both drag oscillations began.

   Location is the meaning. A gap between two columns resizes; the outer edges
   of a row add a column; the gaps between rows add a row. Nothing is ever two
   things at once, so a near miss cannot do the wrong thing. */
.dash-add {
  position: absolute;
  z-index: 3;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--accent-text);
  font: inherit;
  font-size: var(--text-compact);
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition-fast);
}

.dash-add:hover,
.dash-add:focus-visible { opacity: 1; }

/* The line is the affordance; the chip is where to aim. */
.dash-add::before {
  content: "";
  position: absolute;
  background: var(--accent);
  border-radius: var(--radius-pill);
}

.dash-add-mark {
  position: relative;
  display: grid;
  place-items: center;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: var(--radius-round);
  background: var(--accent);
  color: var(--primary-text);
}

/* Between two rows: spans the width, sits in the vertical gap. */
.dash-add-row {
  left: 0;
  right: 0;
  height: 1.25rem;
  top: calc(var(--dash-gap) / -2);
  transform: translateY(-50%);
}

.dash-add-row.is-last {
  top: auto;
  bottom: calc(var(--dash-gap) / -2);
  transform: translateY(50%);
}

.dash-add-row::before { left: 0; right: 0; top: 50%; height: 1px; margin-top: -0.5px; }

/* At a row's outer edge: adds a column on that side. Lives in the lane the
   editing padding opens, so it never covers a card. */
.dash-add-column {
  top: 0;
  bottom: 0;
  width: 1.25rem;
}

.dash-add-column.is-start { left: calc(var(--dash-gap) / -2); transform: translateX(-50%); }
.dash-add-column.is-end { right: calc(var(--dash-gap) / -2); transform: translateX(50%); }
.dash-add-column::before { top: 0; bottom: 0; left: 50%; width: 1px; margin-left: -0.5px; }

.dash-add:disabled { display: none; }

/* Removing an empty column: the same corner a card keeps its handle in, so the
   drop area itself stays a harmless place to click. */
[data-editing="true"] .dash-column { position: relative; }

.dash-column-remove {
  position: absolute;
  top: 0.35rem;
  right: 0.35rem;
  z-index: 3;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-compact);
  background: var(--panel-2);
  color: var(--muted);
  font: inherit;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--transition-fast);
}

.dash-column:hover > .dash-column-remove,
.dash-column-remove:focus-visible { opacity: 1; }
.dash-column-remove:hover { color: var(--text); border-color: var(--accent); }

/* Every one of them is noise while a card is in the air. */
[data-dragging] .dash-add,
[data-dragging] .dash-column-remove,
[data-dragging] .dash-divider { display: none; }

/* Sits on the boundary the split names, so it is where the eye expects it.
   The section is twelve tracks and the eleven gaps between them, not twelve
   equal slices of the width: a track is (100% - 11 gaps) / 12, and the
   boundary after n of them is n tracks plus the n - 1 gaps they span, put half
   a gap further along to land in the middle of the nth gap. Slicing by a plain
   100% / 12 only looks right at 6·6, where the error either side cancels. */
.dash-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: calc(
    (100% - 11 * var(--dash-gap)) / 12 * var(--divider-at, 6) +
    (var(--divider-at, 6) - 0.5) * var(--dash-gap)
  );
  width: 11px;
  /* Half the width, so the grab area straddles the boundary evenly. */
  margin-left: -5.5px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  cursor: col-resize;
  touch-action: none;
}

.dash-section { position: relative; }
.dash-divider::after {
  content: "";
  position: absolute;
  inset: 0 4px;
  border-radius: var(--radius-pill);
  background: var(--border);
}
.dash-divider:hover::after { background: var(--accent); }

/* A grid is hidden only while its stored layout is being rebuilt, and only for
   the devices that stored one — a default layout is correct as rendered. */
[data-layout-pending] .dash-console { visibility: hidden; }

@media (max-width: 899px) {
  .dash-section { grid-template-columns: minmax(0, 1fr); }
  .dash-column { grid-column: 1 / -1; }

  /* Every section is one full-width column here, so the composition a spacer
     was placed to serve does not exist. Editing is off below this width too,
     so no spacer on this side of the breakpoint was put there on purpose —
     it belongs to a wide layout being viewed narrow (a snapped window, a
     rotated tablet, browser zoom). */
  .dash-section:not(:has(.tile-slot)) { min-height: 0; }
}

.tile {
  height: 100%;
  display: flex;
  flex-direction: column;
}

/* .panel is defined later in this file, so its margin-bottom beat .tile's and
   every card carried a stray 16px below it — every card except the map, which
   is not a .panel. That is why one gap in the column was half the others. The
   grid gap is the only spacing here. */
.tile-slot .tile,
.tile-slot .panel { margin-bottom: 0; }

.tile-h {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 0.85rem 1rem 0.35rem;
}

.tile-title {
  font-size: var(--text-medium);
  font-weight: 600;
}

.tile-window {
  font-size: 0.72rem;
  color: var(--muted);
}

.tile-body { padding: 0.35rem 1rem 1rem; }

/* Pressure hero */
.tile-hero {
  font-size: 2.6rem;
  line-height: 1.05;
  font-weight: 650;
  letter-spacing: -0.02em;
}

.tile-delta { font-size: 0.74rem; color: var(--muted); margin-top: 0.15rem; }
.tile-delta.is-down { color: var(--success); }
.tile-delta.is-up { color: var(--danger); }

.hist-wrap { margin-top: 1rem; }

.hist-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: 0.68rem;
  color: var(--muted);
  margin-bottom: 0.4rem;
}

.hist-peak { text-align: right; }
.hist-sep { margin: 0 0.25rem; }

.hist { display: block; width: 100%; height: 3.4rem; }
.hist-plot { touch-action: pan-y; user-select: none; -webkit-touch-callout: none; }
.hist-bar { fill: color-mix(in srgb, var(--accent) 35%, transparent); }
.hist-bar.is-recent { fill: var(--accent); }
.hist-bar.is-empty { fill: var(--border); }
.hist-bar.is-highlighted { fill: var(--accent-text); }

/* Keep the peak's layout box and accessible chart label during inspection. */
.hist-readout { display: grid; justify-items: end; }
.hist-readout > * { grid-area: 1 / 1; }
.hist-peak.is-replaced { visibility: hidden; }
.hist-value { font-variant-numeric: tabular-nums; white-space: pre; }
.hist-value[hidden] { display: none; }

.hist-axis {
  display: flex;
  justify-content: space-between;
  font-size: 0.62rem;
  color: var(--dim, var(--muted));
  margin-top: 0.3rem;
}

/* Metric cards */
.tile-metric { --tile-metric-note-size: 0.7rem; }
.tile-metric-label { font-size: 0.72rem; color: var(--muted); }
.tile-metric-value {
  font-size: 1.9rem;
  font-weight: 650;
  line-height: 1.15;
  letter-spacing: -0.02em;
}
.tile-metric-note { font-size: var(--tile-metric-note-size); color: var(--muted); }

/* A metric card with no note stands one line shorter than one with a note, and
   nothing else levels the two: a column stretches to its row, but the slot and
   the card inside it size to their content — only the map asks to grow. So
   Locally decided, which carries no note, would sit short beside Active bans.

   The stand-in is a line box and nothing else: no text to reach the
   accessibility tree, and a height of `1lh` at the note's own font size, so it
   is one note line by construction rather than a measurement copied from it. */
.tile-metric .tile-body:not(:has(.tile-metric-note))::after {
  content: "";
  display: block;
  font-size: var(--tile-metric-note-size);
  height: 1lh;
}

/* Attack surface */
.surface-cols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2.25rem;
  padding: 0.35rem 1rem 1rem;
}

/* Without a divider the previous column's counts sit against the next
   column's names and the three lists read as one. */
.surface-col + .surface-col {
  padding-left: 2.25rem;
  border-left: 1px solid var(--border-soft, var(--border));
}

.surface-col-title {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-bottom: 0.5rem;
}

.surface-list { list-style: none; margin: 0; padding: 0; }

.surface-row {
  display: grid;
  /* Fixed count track, not auto: each row is a separate grid, so an auto track
     is measured per row and a shorter number pushes that row's bar sideways. */
  grid-template-columns: minmax(0, 1fr) 3rem 2.9rem;
  align-items: center;
  gap: 0.5rem;
  padding: 0.22rem 0;
  font-size: 0.74rem;
}

.surface-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.surface-bar {
  display: block;
  height: 3px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}

.surface-bar-fill { display: block; height: 100%; background: var(--accent); }
.surface-count { font-variant-numeric: tabular-nums; color: var(--muted); text-align: right; }

@media (max-width: 1100px) {
  .surface-cols { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
  .surface-col + .surface-col { padding-left: 0; border-left: 0; }
}

/* Origin map — no chrome by design */
/* The map card stretches to whatever height its row ends up and letterboxes
   the world inside, so the hero can be two-thirds without the map beside it
   leaving a hole underneath. The turbo-frame sits between the slot and the
   card, so the height has to be handed down through it. */
/* The map card is the one that should fill its space rather than sit at the
   top: it letterboxes the world inside whatever box it is given, so a short map
   beside a tall neighbour leaves a hole.
   It used to reach the row's height through the grid. Its parent is a flex
   column now, so it grows within that instead — same result, one level down.
   The turbo-frame sits between the slot and the card. */
.dash-column > .tile-slot:has(.tile-map) { flex: 1; min-height: 0; }
.tile-slot:has(.tile-map) > turbo-frame { display: block; height: 100%; }

.tile-map {
  /* width must be explicit. This card also carries .tile, which sets
     height: 100% — and a definite height next to an aspect ratio makes the
     browser derive the *width* from it (257px x 2.647 = 680px), overflowing the
     column. With both dimensions definite the ratio is simply ignored; it still
     applies wherever the height is auto, which is where it is wanted. */
  width: 100%;
  position: relative;
  /* Matches the projection (80N…56S over 360 degrees), so the card is exactly
     the map when the row does not give it a height — on mobile, and anywhere
     the map is not sharing a row with a taller card. */
  aspect-ratio: 360 / 136;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  overflow: hidden;
}

.origin-map-canvas { display: block; width: 100%; height: 100%; }

/* Issues */
.attention-list { list-style: none; margin: 0; padding: 0; }

.attention-row {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.35rem 0;
}

.attention-text { display: flex; flex-direction: column; gap: 0.1rem; }
.attention-title { font-size: 0.8rem; }
.attention-detail,
.attention-unknown { font-size: 0.7rem; color: var(--muted); }
.attention-clear { display: flex; align-items: center; gap: 0.5rem; font-size: 0.8rem; }
.attention-unknown { margin-top: 0.5rem; }

/* Community ingest */
.ingest-list { list-style: none; margin: 0; padding: 0; }

.ingest-row {
  display: grid;
  grid-template-columns: 6.5rem auto minmax(0, 1fr);
  align-items: baseline;
  gap: 0.6rem;
  /* Matches .tile-body — the rows sit directly in the panel, so they carry
     their own gutter rather than inheriting one. */
  padding: 0.35rem 1rem;
  font-size: 0.74rem;
  border-bottom: 1px solid var(--border-soft, var(--border));
}

.ingest-row:last-child { border-bottom: 0; }
.ingest-row[role="button"] { cursor: pointer; }
.ingest-row[role="button"]:hover { background: color-mix(in srgb, var(--accent) 5%, transparent); }
.ingest-when { color: var(--muted); }
.ingest-net { color: var(--success); font-weight: 600; }
.ingest-removed { color: var(--danger); margin-left: 0.3rem; }
.ingest-result.is-failed { color: var(--danger); font-weight: 600; }
.ingest-claimed { color: var(--muted); }
.ingest-noise { margin-left: 0.35rem; }

/* Live feed */
.feed-sep { margin: 0 0.3rem; }

/* Customise panel */
/* Its container frames it — the context pane on desktop, the mobile sheet on a
   phone — so the panel itself carries no chrome. */
.customise { display: flex; flex-direction: column; min-height: 0; }

.dashboard-sheet .customise { height: 100%; }
.dashboard-sheet .customise-rows { overflow-y: auto; }

/* align-content matters: in the sheet this list is the flex:1 scroll area, so
   a grid left to stretch spreads eight rows over the whole panel. */
.customise-rows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  align-content: start;
  gap: 0.08rem;
}

.customise-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 0.6rem;
  padding: 0.15rem 0.85rem;
}

/* The hover surface is the row boundary. Eight rules for eight checkboxes is
   noise the filter panes on the sibling pages already do without. */
.customise-visible {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.38rem 0.4rem;
  border-radius: var(--radius-control);
  cursor: pointer;
  user-select: none;
}

.customise-visible:hover { background: color-mix(in srgb, var(--text) 5%, transparent); }
.customise-name { font-size: var(--text-compact); }
.customise-visible input:not(:checked) + .customise-name { color: var(--muted); text-decoration: line-through; }
.customise-move { display: flex; gap: 0.2rem; }

.btn-icon {
  width: 1.5rem;
  height: 1.4rem;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  line-height: 1;
}

.btn-icon:disabled { opacity: 0.3; cursor: not-allowed; }

/* ── Dashboard context pane ─────────────────────────────────────────────── */
.dash-pane {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-4) 0.85rem;
  overflow-y: auto;
  /* Pinned to the pane's open width so the content clips during the open and
     close transition rather than reflowing at every intermediate width. Same
     reason .context-pane .list-filters-form does it. */
  width: var(--context-pane-w);
  min-width: var(--context-pane-w);
}

/* One section shape, used by every block in the pane: label on the left,
   actions on the right, content below. Two sections built from one template
   read as siblings without rules having to say so. */
.pane-section { display: flex; flex-direction: column; gap: var(--space-2); }

.pane-section-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: 1.6rem;
  padding-inline: 0.85rem;
}

/* The shared action bar is sized for a table row. The pane is a denser surface
   beside a dense board, so it runs a size down — here only, so Decisions and
   Alerts keep the size their rows were built for. */
.dash-pane .compact-action-bar { padding: 0.12rem; }

.dash-pane .compact-action {
  min-height: 1.5rem;
  padding: 0.22rem 0.42rem;
  font-size: var(--text-micro);
}

.pane-section-title {
  margin: 0;
  font-size: var(--text-x-small);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}

.dash-pane-note { font-size: var(--text-x-small); color: var(--muted); line-height: 1.45; margin: 0; }

/* In the pane the customiser is the pane, so it drops the popover framing —
   .dash-pane's own padding is the inset. */
.dash-pane .customise-row,
.dash-pane .pane-section-h { padding-inline: 0; }

/* The header sits outside the scrolling list, so it has to add that list's
   padding to its own to line up with the rows inside it. Nothing sits above it
   in the sheet either, so it carries the top space too — the same job
   .list-filters-head does in the filter sheet. */
.dashboard-sheet .pane-section-h {
  padding-inline: calc(0.35rem + 0.85rem);
  padding-block: 0.85rem 0.25rem;
}

/* The sheet is touched, not clicked, and it has the room: eight rows in a
   684px list. Every target is a full 44px, and the two move buttons sit a
   clear gap apart because they are opposite actions — a near miss has to land
   on nothing rather than on the other one. */
.dashboard-sheet .customise-rows { gap: 0.25rem; }

.dashboard-sheet .customise-row {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-2);
  padding-block: 0.15rem;
}

/* The label is the target, not just the box: the whole name toggles it. */
.dashboard-sheet .customise-visible {
  min-height: var(--tap-target);
  gap: var(--space-3);
}

.dashboard-sheet .customise-visible input[type="checkbox"] {
  flex: none;
  width: 20px;
  height: 20px;
}

.dashboard-sheet .customise-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dashboard-sheet .customise-move { gap: var(--space-2); }

.dashboard-sheet .customise-move .btn-icon {
  width: var(--tap-target);
  height: var(--tap-target);
  /* Past the interface scale on purpose: a 14px glyph in a 44px box reads as a
     small button someone stretched. */
  font-size: 1.05rem;
}

/* ── Display mode ───────────────────────────────────────────────────────────
   For a screen left running: no navigation, full width, everything on one
   screen. Its own stored layout, so it cannot disturb the console's. */
[data-display-mode="display"] .rail { display: none; }

/* Three columns of roughly the width two occupy on the console — not two
   stretched ones. A half card on the console is about 600px, and a third of
   this cap is the same, so cards gain a neighbour rather than gaining girth. */
[data-display-mode="display"] .app-main {
  max-width: var(--dash-display-max);
  padding: 1rem 1.25rem;
}

/* Without this the cap, not the rail, is what keeps a wall monitor at 1200px:
   the rail is 150px, the cap costs over 1200px on a 2560px screen. */
[data-display-mode="display"] .app-main-wrap { min-height: 100dvh; }

/* The point of display mode is every card on one screen, and the feed is the
   one card that will not fit on its own. It clips rather than scrolls — a
   scrollbar on a wall hides rows behind an affordance nobody will use — and
   list_fit_controller drops whole rows from the end until the rest fits. Where
   nothing bounds the list, as on the console, all ten render. */
.feed-list { overflow: hidden; }

/* .item-row sets display:grid, which beats the UA rule for [hidden] — so a row
   the fit controller hides would keep its space and the list would never
   shrink. Same trap as .tile-slot[hidden]. */
.feed-list .item-row[hidden] { display: none; }

[data-display-mode="display"] .tile-feed .feed-list { max-height: 32vh; }

@media (max-width: 899px) {
  /* Display mode is a desktop affordance; the pane that exits it is desktop-only. */
  [data-display-mode="display"] .rail { display: flex; }
  [data-display-mode="display"] .app-main { padding: var(--space-4); }
}

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  overflow: hidden;
  box-shadow: var(--shadow-panel);
  margin-bottom: 1rem;
}

.panel-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 0.85rem 1rem;
  border-bottom: 1px solid var(--border);
}

.panel-h h2 {
  font-size: var(--text-medium);
  font-weight: 600;
}

.panel-empty {
  padding: 1.1rem 1rem;
  color: var(--muted);
  font-size: 0.85rem;
}

/* One line per alert, on the same grid as .ingest-row. The two list cards are
   both half width and sit side by side, so a two-line row here read as a
   mistake next to the ingest ledger's single-line one — and cost the feed half
   the rows in the same height. Time leads, so the column scans down a gutter
   of aligned ages rather than a ragged right edge.

   The tracks live on the list and the rows borrow them, because a row sizing
   its own columns is a row that only lines up by luck: one .10 address at the
   end of a list of .1 addresses shunts that row's scenario out of the column. */
.item-list { display: grid; }

/* Two lines per alert: who it was on the first, what they did on the second.
   The scenario owns a line of its own, so it never has to compete with the
   address for room and never ends in an ellipsis on a narrow card — which is
   also why this needs no width query. Only the spacing is tight; the original
   was padded like a settings form, at 72px a row against the ingest ledger's
   29px right beside it. */
.item-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0 0.75rem;
  align-items: baseline;
  line-height: 1.35;
  padding: 0.4rem 1rem;
  border-bottom: 1px solid var(--border-soft, var(--border));
}

.item-row:last-child { border-bottom: 0; }
.item-row:hover { background: color-mix(in srgb, var(--accent) 5%, transparent); }

.feed-source {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  min-width: 0;
  font-size: var(--text-compact);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* The pill's vertical padding is the only thing making this row taller than
   its own content; at this density the badge reads from its background. */
.feed-source .cn-pill { padding-block: 0; }

.feed-when {
  font-size: var(--text-caption);
  color: var(--muted);
  white-space: nowrap;
  text-align: right;
}

.feed-scenario {
  grid-column: 1 / -1;
  font-size: 0.76rem;
  color: var(--muted);
}

/* The address is the one thing here that can run long — an IPv6 source is
   three times an IPv4 one — so it is the one thing allowed to clip, and its
   title carries the rest. */
.feed-ip,
.feed-scenario {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.feed-events {
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--text) 70%, var(--muted));
}

.panel-link {
  font-size: var(--text-compact);
  font-weight: 500;
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--accent-text) 40%, transparent);
  text-underline-offset: 0.15em;
}

.panel-link:hover {
  color: var(--text);
  text-decoration-color: color-mix(in srgb, var(--text) 55%, transparent);
}

.badge {
  display: inline-flex;
  align-items: center;
  font-size: 0.7rem;
  font-weight: 650;
  padding: 0.22rem 0.55rem;
  border-radius: var(--radius-pill);
  text-transform: lowercase;
  letter-spacing: 0.01em;
  line-height: 1.2;
  font-family: var(--font);
}

.badge-danger { background: color-mix(in srgb, var(--danger) 14%, var(--panel)); color: var(--danger); }
.badge-warning { background: color-mix(in srgb, var(--warning) 14%, var(--panel)); color: var(--warning); }
.badge-success { background: color-mix(in srgb, var(--success) 14%, var(--panel)); color: var(--success); }
.badge-info { background: color-mix(in srgb, var(--info) 14%, var(--panel)); color: var(--info); }
.badge-muted { background: color-mix(in srgb, var(--muted) 12%, var(--panel)); color: var(--muted); }

/* ── Filters / list pages ──────────────────── */

.page-head-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* Desktop filter pane (inside unified chrome).
   Always in-flow; width animates 0 ↔ pane width so chrome never undershoots. */
.context-pane {
  width: 0;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  background: color-mix(in srgb, var(--bg) 55%, var(--panel));
  border-left: 0 solid color-mix(in srgb, var(--border) 85%, transparent);
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition:
    width var(--transition-chrome),
    opacity 0.18s ease,
    border-left-width var(--transition-chrome);
}

.unified-chrome.has-filters.filters-open .context-pane {
  width: var(--context-pane-w);
  border-left-width: 1px;
  opacity: 1;
  pointer-events: auto;
}

/* Keep inner form at full pane width so content clips instead of reflowing during collapse */
.context-pane .list-filters-form {
  width: var(--context-pane-w);
  min-width: var(--context-pane-w);
}

.chrome-handle {
  display: none;
  width: var(--chrome-handle-w);
  min-width: var(--chrome-handle-w);
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--panel-2) 70%, transparent);
  border: 0;
  border-left: 1px solid var(--border);
  color: var(--muted);
  cursor: pointer;
  padding: 0;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.chrome-handle:hover {
  background: var(--accent-soft);
  color: var(--accent-text);
}

.chrome-handle-bar {
  width: 3px;
  height: 36px;
  border-radius: var(--radius-pill);
  background: currentColor;
  opacity: 0.45;
}

/* Always present on desktop (list pages + stub on others) so width doesn’t jump */
.unified-chrome .chrome-handle { display: flex; }

.unified-chrome.has-filters.filters-open .chrome-handle:not(.chrome-handle--idle) {
  color: var(--accent-text);
}

/* Dashboard / Metrics / Settings: same footprint, quiet on both edges */
.chrome-handle--idle {
  pointer-events: none;
  cursor: default;
  color: color-mix(in srgb, var(--muted) 28%, transparent);
  background: color-mix(in srgb, var(--panel-2) 22%, transparent);
  border-left: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
  /* Match softness on the right so only one edge doesn’t “pop” */
  border-right: 1px solid color-mix(in srgb, var(--border) 40%, transparent);
  box-sizing: border-box;
}

.chrome-handle--idle .chrome-handle-bar {
  opacity: 0.18;
  height: 32px;
  width: 2px;
}

.chrome-handle--idle:hover {
  background: color-mix(in srgb, var(--panel-2) 22%, transparent);
  color: color-mix(in srgb, var(--muted) 28%, transparent);
}

.list-filters-form {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}

.list-filters-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.85rem 0.85rem 0.5rem;
  flex-shrink: 0;
}

.list-filters-title {
  font-size: var(--text-normal);
  font-weight: 700;
  letter-spacing: -0.01em;
  flex: 1;
  margin: 0;
}

.list-filters-count {
  font-size: var(--text-x-small);
  color: var(--muted);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0.1rem 0.45rem;
  font-weight: 600;
}

.list-filters-search {
  padding: 0 0.75rem 0.65rem;
  flex-shrink: 0;
}

.list-filters-search-input {
  width: 100%;
  height: var(--control-height-compact);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-surface);
  padding: 0.5rem 0.7rem 0.5rem 2rem;
  font-size: var(--text-compact);
  color: var(--text);
  font-family: inherit;
  outline: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='none' stroke='%238b93a7' stroke-width='2' viewBox='0 0 24 24'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3-3'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 0.6rem 50%;
}

/* As the Created fields: a lighter border on hover, and the open half's tint
   while typing, rather than an accent ring. */
.list-filters-search-input:hover { border-color: color-mix(in srgb, var(--text) 22%, var(--border)); }
.list-filters-search-input:focus { background-color: color-mix(in srgb, var(--text) 5%, var(--panel)); }

.list-filters-search-input::placeholder { color: color-mix(in srgb, var(--muted) 80%, transparent); }

.mobile-sheet-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 0 0.35rem 0.75rem;
  min-height: 0;
  /* Keep scroll, hide the scrollbar chrome */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.mobile-sheet-scroll::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

.list-filters-foot {
  border-top: 1px solid var(--border);
  padding: 0 0.85rem;
  min-height: 3rem;
  flex-shrink: 0;
  display: flex;
  align-items: center;
}

.list-filters-clear {
  border: 0;
  background: none;
  padding: 0;
  color: var(--accent-text);
  font: inherit;
  font-size: var(--text-control);
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
}

.list-filters-clear:hover { text-decoration: underline; }

.filter-section {
  border-bottom: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
  padding: 0.3rem 0.35rem 0.5rem;
}

.filter-section:last-child { border-bottom: 0; }

.filter-section-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.45rem 0.35rem;
  color: var(--text);
  font-size: var(--text-control);
  font-weight: 650;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.filter-section-h::-webkit-details-marker { display: none; }

.filter-section-chev {
  color: var(--muted);
  font-size: 0.7rem;
  transition: transform var(--transition-fast);
}

.filter-section:not([open]) .filter-section-chev {
  transform: rotate(-90deg);
}

.filter-section-body {
  display: grid;
  gap: 0.08rem;
  padding: 0.05rem 0.15rem 0.2rem;
}

.filter-section-empty {
  font-size: var(--text-caption);
  color: var(--muted);
  padding: 0.35rem 0.4rem;
  margin: 0;
}

.filter-check {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.38rem 0.4rem;
  border-radius: var(--radius-control);
  font-size: var(--text-compact);
  color: var(--text);
  cursor: pointer;
  user-select: none;
}

.filter-check:hover {
  background: color-mix(in srgb, var(--text) 5%, transparent);
}

.filter-check.is-grouped { font-weight: 600; }

/* Sized against --text-compact, which is what sits beside it. The old 15px box
   centred its tick on a half pixel and looked soft; the tick below is drawn to
   the border box now, so the box size no longer has to be even. */
.filter-check-input,
.customise-visible input[type="checkbox"] {
  appearance: none;
  width: 13px;
  height: 13px;
  border: 1.5px solid color-mix(in srgb, var(--muted) 55%, var(--border));
  border-radius: var(--radius-control);
  background: transparent;
  flex-shrink: 0;
  margin: 0;
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast);
}

/* A drawn tick rather than two rotated borders. The old one nudged itself with
   a translate applied *after* the rotation, so the correction ran diagonally
   and pulled the mark off centre; and a 2px stroke on a 5px arm was heavy for
   the box. Sized to the border box, so it scales with the sheet's 20px target
   instead of needing its own rule. */
.filter-check-input:checked,
.customise-visible input[type="checkbox"]:checked {
  background-color: var(--accent);
  border-color: var(--accent);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.5 6.8 11.3 12 5.7' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% 100%;
  background-origin: border-box;
}

.filter-check-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.filter-check-hint {
  font-size: 0.65rem;
  color: color-mix(in srgb, var(--muted) 90%, transparent);
  font-weight: 500;
  margin-left: 0.25rem;
}

.filter-check-n {
  margin-left: auto;
  color: var(--muted);
  font-size: var(--text-small);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

/* Created range: a date-and-time field per end, after Atlassian's
   DateTimePicker. Both halves are buttons; the calendar and the hours open in
   a .custom-select-menu popup that the datetime-field controller positions. */
.dtp-body { display: grid; gap: 0.65rem; padding: 0.15rem 0.4rem 0.45rem; }
.dtp-field { display: grid; gap: 0.3rem; }
.dtp-label { color: var(--muted); font-size: var(--text-small); }
.dtp {
  display: grid;
  /* Fixed columns, so nothing moves when × comes and goes; Time is wide
     enough for "12:00 AM". */
  grid-template-columns: minmax(0, 1fr) 1px 5.25rem 1.7rem;
  align-items: center;
  /* The search field's height, so the filters' fields line up. */
  height: var(--control-height-compact);
  border: 1px solid var(--border);
  border-radius: var(--radius-surface);
  background: var(--panel);
  transition: border-color var(--transition-fast);
}
.dtp:hover { border-color: color-mix(in srgb, var(--text) 22%, var(--border)); }
.dtp-field.is-invalid .dtp { border-color: color-mix(in srgb, var(--danger) 60%, var(--border)); }
.dtp-rule { align-self: stretch; margin: 0.4rem 0; background: var(--border); }
.dtp-part {
  height: 100%;
  min-width: 0;
  padding: 0 0.55rem;
  border: 0;
  border-radius: var(--radius-surface);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--text-compact);
  font-variant-numeric: tabular-nums;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  outline: 0;
}
.dtp-part.is-empty { color: color-mix(in srgb, var(--muted) 75%, transparent); }
.dtp-part:hover,
.dtp-part[aria-expanded="true"] { background: color-mix(in srgb, var(--text) 5%, transparent); }
/* A divider against a highlighted half reads as an edge on it, as in .compact-action-bar. */
.dtp:has(.dtp-part:hover, .dtp-part[aria-expanded="true"]) .dtp-rule { visibility: hidden; }
.dtp-part:focus-visible { box-shadow: inset 0 0 0 2px var(--focus-ring); }
.dtp-field.is-invalid .dtp-part:not(.is-empty) { color: var(--danger); }
/* A segment like Date and Time: its fill reaches the field's edges. */
.dtp-clear {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--radius-surface);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
/* × only once there is something to clear; until then Time takes its column
   too, reaching the edge without its text moving. */
.dtp-field:not(.has-value) .dtp-clear { display: none; }
.dtp-field:not(.has-value) .dtp-part[data-datetime-field-target="time"] { grid-column: 3 / -1; }
.dtp-clear:hover { color: var(--text); background: color-mix(in srgb, var(--text) 5%, transparent); }
/* Beside an open half, a second fill reads as a clash; × only brightens. */
.dtp:has(.dtp-part[aria-expanded="true"]) .dtp-clear:hover { background: transparent; }
.dtp-clear:focus-visible { outline: 0; box-shadow: inset 0 0 0 2px var(--focus-ring); }
.dtp-clear svg { width: 0.625rem; height: 0.625rem; }

.dtp-pop { max-height: var(--dtp-max-height, none); overflow: auto; overscroll-behavior: contain; }
.dtp-cal { width: 15.5rem; padding: 0.55rem; }
.dtp-cal-head { display: grid; grid-template-columns: 1.9rem 1fr 1.9rem; align-items: center; margin-bottom: 0.3rem; text-align: center; font-size: var(--text-compact); font-weight: 650; }
.dtp-nav { height: 1.9rem; border: 0; border-radius: var(--radius-control); background: transparent; color: var(--text); font: inherit; font-size: 1rem; cursor: pointer; }
.dtp-nav:hover:not(:disabled) { background: color-mix(in srgb, var(--text) 6%, transparent); }
.dtp-nav:disabled { opacity: 0.3; cursor: default; }
.dtp-grid { width: 100%; border-collapse: separate; border-spacing: 1px; table-layout: fixed; }
.dtp-grid th { padding: 0.2rem 0; color: var(--muted); font-size: var(--text-x-small); font-weight: 600; text-align: center; }
.dtp-day {
  height: 1.95rem;
  border-radius: var(--radius-control);
  color: var(--text);
  font-size: var(--text-small);
  font-variant-numeric: tabular-nums;
  text-align: center;
  cursor: pointer;
  outline: 0;
}
.dtp-day.is-outside { color: color-mix(in srgb, var(--muted) 70%, transparent); }
.dtp-day:hover:not(.is-selected):not([aria-disabled="true"]) { background: color-mix(in srgb, var(--text) 8%, transparent); }
.dtp-day:focus-visible { box-shadow: inset 0 0 0 2px var(--focus-ring); }
.dtp-day.is-today { color: var(--accent-text); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.dtp-day.is-selected { background: var(--accent); color: #fff; font-weight: 650; text-decoration: none; }
.dtp-day[aria-disabled="true"] { color: color-mix(in srgb, var(--muted) 40%, transparent); text-decoration: none; cursor: default; }

.dtp-times { min-width: 7.5rem; }
.dtp-times .custom-select-options { position: relative; max-height: min(14rem, var(--dtp-max-height, 14rem)); margin: 0; list-style: none; }
.dtp-pop-time { overflow: hidden; }
.dtp-times .custom-select-option { grid-template-columns: minmax(0, 1fr); font-variant-numeric: tabular-nums; font-size: var(--text-compact); outline: 0; }
.dtp-times .custom-select-option.is-selected { color: var(--accent-text); font-weight: 650; }

@media (max-width: 959px) {
  .dtp { grid-template-columns: minmax(0, 1fr) 1px 5.25rem 2.4rem; }
  .dtp-cal { width: auto; }
  .dtp-day { height: 2.6rem; font-size: var(--text-compact); }
  .dtp-times { min-width: 9rem; }
  .dtp-times .custom-select-option { min-height: 2.6rem; font-size: var(--text-normal); }
}

/* While a Created range is on, the list shows the clock time it matched. */
.alert-created-clock { font-variant-numeric: tabular-nums; }
.alert-created-day { color: var(--muted); }

.active-filter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 0.65rem;
}

.active-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0.22rem 0.55rem;
  font-size: var(--text-small);
  color: var(--muted);
  text-decoration: none;
  transition: border-color var(--transition-fast), color var(--transition-fast);
}

.active-filter-chip:hover {
  border-color: color-mix(in srgb, var(--danger) 40%, var(--border));
  color: var(--text);
}

.active-filter-chip strong {
  color: var(--text);
  font-weight: 600;
}

.active-filter-chip-x {
  font-size: var(--text-medium);
  line-height: 1;
  opacity: 0.7;
}

/* Mobile filter FAB + sheet (M1)
   Note: .mobile-only { display: grid } can override the HTML [hidden] attribute,
   so closed sheet/backdrop must use pointer-events: none (backdrop was eating FAB taps). */
.mobile-fab {
  position: fixed;
  /* In from corner (toward center): right inset + higher off the nav */
  right: 1.55rem;
  bottom: calc(var(--bottom-h) + 1.3rem);
  z-index: 70; /* above bottom-nav (60) */
  width: 40px;
  height: 40px;
  border-radius: var(--radius-surface);
  border: 0;
  background: var(--primary);
  color: var(--primary-text);
  display: grid;
  place-items: center;
  box-shadow: 0 3px 10px color-mix(in srgb, var(--primary) 18%, transparent);
  cursor: pointer;
  padding: 0;
}

.mobile-fab svg {
  width: 18px;
  height: 18px;
}

.mobile-fab:hover { background: var(--primary-hover); }
.mobile-fab:not([data-press-feedback-active]):active { transform: scale(0.97); }

.mobile-fab-badge {
  position: absolute;
  top: -3px;
  right: -3px;
  min-width: 16px;
  height: 16px;
  border-radius: var(--radius-pill);
  background: var(--danger);
  color: white;
  font-size: 0.6rem;
  font-weight: 700;
  display: grid;
  place-items: center;
  padding: 0 0.22rem;
  border: 2px solid var(--bg);
}

/* display:grid above must not win over [hidden] (zero active filters) */
.mobile-fab-badge[hidden] {
  display: none !important;
}

.mobile-sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(0, 0, 0, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease;
  border: 0;
  padding: 0;
}

.mobile-sheet-backdrop.is-open {
  opacity: 1;
  pointer-events: auto;
}

.mobile-sheet {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 81;
  width: min(380px, 92vw);
  background: color-mix(in srgb, var(--bg) 40%, var(--panel));
  border-left: 1px solid var(--border);
  box-shadow: -16px 0 40px rgba(0, 0, 0, 0.4);
  transform: translateX(105%);
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
  display: flex;
  flex-direction: column;
  padding-top: var(--safe-t);
  padding-left: 0;
  will-change: transform;
  pointer-events: none;
  visibility: hidden;
  /* Critical: pan-y lets the browser steal horizontal swipes from the form body.
     We own gestures in JS (manual vertical scroll + horizontal dismiss). */
  touch-action: none;
}

.mobile-sheet.is-open {
  transform: translateX(0);
  pointer-events: auto;
  visibility: visible;
  touch-action: none;
}
.mobile-sheet.is-dragging { transition: none; }

/* Keep [hidden] actually hidden even if .mobile-only sets display */
.mobile-sheet[hidden],
.mobile-sheet-backdrop[hidden] {
  display: none !important;
}

/* Visual grab cue only — swipe works from the whole sheet */
.mobile-sheet-handle {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  z-index: 2;
  touch-action: none;
  pointer-events: none; /* don't intercept; sheet handler covers everything */
}

.mobile-sheet-handle::before {
  content: "";
  width: 4px;
  height: 48px;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--muted) 50%, transparent);
  pointer-events: none;
}

.mobile-sheet .list-filters-form {
  padding-left: 12px;
  height: 100%;
  min-height: 0;
  touch-action: none;
}

.mobile-sheet .mobile-sheet-scroll {
  touch-action: none;
  overscroll-behavior: contain;
}

body.mobile-sheet-open {
  overflow: hidden;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Type hierarchy for lists */
.cell-primary {
  display: inline-flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font);
  font-size: var(--text-compact);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.cell-secondary {
  display: block;
  font-family: var(--font);
  font-size: var(--text-normal);
  font-weight: 450;
  color: var(--muted);
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.cell-muted { color: var(--muted); }
.mono-soft {
  font-family: var(--font-mono);
  font-size: var(--text-control);
  font-weight: 450;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.time-text {
  font-size: 0.86rem;
  color: color-mix(in srgb, var(--text) 88%, var(--muted));
  white-space: nowrap;
}

.cn-pill {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  margin-left: 0;
  padding: 0.08rem 0.4rem;
  border-radius: var(--radius-compact);
  background: color-mix(in srgb, var(--text) 6%, transparent);
  color: var(--muted);
  font-size: var(--text-small);
  font-weight: 600;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

/* Trailing markers on an action that navigates rather than acts: ↗ leaves the
   app, → goes elsewhere in CrowdBoard. Inside a compact-action-bar this is how
   navigation is marked, since the bar's segmented shape is what holds the
   actions together — see .destination-link for the standalone row form. */
.ext-ico,
.int-ico {
  font-size: var(--text-small);
  opacity: 0.85;
  line-height: 1;
}

.meta-sep { opacity: 0.45; }

/* ── Mobile alerts tickets ──────────────────── */

.alert-ticket-stack {
  display: grid;
  gap: 0.8rem;
}

.alert-ticket {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 0.55rem 0.7rem 0.6rem;
  display: grid;
  gap: 0.3rem;
  box-shadow: var(--shadow-panel);
}

.alert-ticket-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-2);
}

.alert-ticket-ip {
  font-weight: 700;
  font-size: var(--text-medium);
  letter-spacing: -0.02em;
  min-width: 0;
}

.alert-ticket-top .badge {
  flex-shrink: 0;
  font-size: 0.65rem;
  padding: 0.18rem 0.45rem;
}

.alert-ticket-scenario {
  font-size: var(--text-compact);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.alert-ticket-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  margin-top: 0.05rem;
}

.alert-ticket-stats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem 0.75rem;
  font-size: var(--text-small);
  color: var(--muted);
  min-width: 0;
}

.alert-ticket-stats strong {
  color: var(--text);
  font-weight: 650;
}

.alert-ticket-ago {
  flex-shrink: 0;
  font-size: var(--text-x-small);
  color: var(--muted);
  white-space: nowrap;
}

.list-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.65rem 1rem;
  margin-bottom: 0.75rem;
}

.list-toolbar .filter-count { margin: 0; }

.decision-row-actions { width: fit-content; margin-left: auto; }

/* —— Alerts and Decisions tables (desktop) ——
   Consecutive rows from one source form a run (Crowdsec::Lists::Runs): one
   band, the source written once with its count, a thread down the rest. No
   inner lines: the header fill and the bands carry the structure. Columns are
   fixed, so a narrow screen scrolls the frame rather than crushing them. */
.list-table-shell {
  --table-scroll-thumb: color-mix(in srgb, var(--muted) 68%, var(--panel));
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  scrollbar-width: thin;
  scrollbar-color: var(--table-scroll-thumb) transparent;
}
.list-table-shell::-webkit-scrollbar { height: 8px; }
.list-table-shell::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
.list-table-shell::-webkit-scrollbar-track { margin-inline: 0.45rem; background: transparent; }
.list-table-shell::-webkit-scrollbar-thumb { background: var(--table-scroll-thumb); border-radius: var(--radius-pill); }

.list-table {
  --list-row: 2.1rem; /* 2.2 and 2.3 were tried: taller rows broke up the run blocks */
  --list-head: 2rem;
  --list-band: color-mix(in srgb, var(--text) 2.6%, transparent);
  --list-value-size: 0.79rem;
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
  font-size: var(--text-control);
}
html[data-theme="light"] .list-table { --list-band: color-mix(in srgb, var(--panel-2) 60%, var(--panel)); }
/* Wide enough that the flexible Scenario / Reason column keeps a readable width. */
.alerts-table { min-width: 58rem; }
/* Two-line Expires and 30px action buttons need the air. */
.decisions-table { --list-row: 2.3rem; min-width: 68rem; }

.list-c-id { width: 4.75rem; }
.list-c-id-wide { width: 5.6rem; }
.list-c-src { width: 16rem; }
.decisions-table .list-c-src { width: 12.25rem; }
/* Widest label (CROWDSEC) is ~59px; padding plus slack for font differences. */
.list-c-kind { width: 5.5rem; }
.list-c-dec { width: 6rem; }
.list-c-ev { width: 8.5rem; }
.list-c-time { width: 6.5rem; }
/* "11:58 PM 23m" is ~88px; the 24-hour clock fits the mockup's width. */
html[data-hour-cycle="h12"] .list-c-time { width: 7.25rem; }
.list-c-country { width: 8.75rem; }
.list-c-origin { width: 6.5rem; }
.list-c-exp { width: 7rem; }
/* The action bar is ~175px; slack for font differences so Unban never clips. */
.list-c-act { width: 12.75rem; }

.list-table th {
  height: var(--list-head);
  padding: 0 0.65rem;
  text-align: left;
  font-size: var(--text-x-small);
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
  background: color-mix(in srgb, var(--panel) 94%, var(--text));
}
.list-table .r { text-align: right; }
.list-table .num { font-variant-numeric: tabular-nums; }
/* Values, not decoration: zeros, dashes and IDs stay at the muted token rather
   than below it. Only repeated cells (.is-quiet) go fainter, on purpose: the
   row above already says the same thing. */
.list-table .faint { color: var(--muted); }

.list-row td {
  height: var(--list-row);
  padding: 0 0.65rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: color-mix(in srgb, var(--text) 85%, var(--muted));
}
.list-row.is-banded td { background: var(--list-band); }
.list-row:hover td { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.list-row.clickable:hover { background: none; }

.list-row .list-id { font-family: var(--font-mono); font-size: var(--text-x-small); color: var(--muted); }
.list-src { position: relative; }
/* Too long for the column, the value gives way, never its chips or count
   (the cell's title has the whole value). */
.list-src-line { display: flex; align-items: center; min-width: 0; }
.list-src-line > * { flex: none; }
.list-src-line > .list-value { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.list-blocklist { color: var(--muted); }
.list-value { font-family: var(--font-mono); font-size: var(--list-value-size); font-weight: 600; color: var(--text); }
.list-chip {
  margin-left: 0.45rem;
  padding: 0.02rem 0.32rem;
  border-radius: 3px;
  font-size: var(--text-xx-small);
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--muted);
  background: color-mix(in srgb, var(--text) 6%, transparent);
}
.list-chip.is-lead { margin: 0 0.45rem 0 0; }
.list-count {
  margin-left: 0.45rem;
  padding: 0.02rem 0.35rem;
  border-radius: 999px;
  font-size: var(--text-xx-small);
  font-weight: 700;
  color: var(--accent-text);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
/* Rows under a run's first one draw a thread instead of repeating the source.
   The trunk runs under the middle of the value's first character, so the
   pieces that draw it take the value's font and count in its `ch`. */
.list-thread,
.list-row.is-in-run.is-run-start .list-src::after {
  position: absolute;
  left: calc(0.65rem + 0.5ch - var(--tree-stroke) / 2);
  font-family: var(--font-mono);
  font-size: var(--list-value-size);
}
.list-thread { top: 0; bottom: 0; width: var(--tree-stub); }
/* The trunk leaves from just under the first row's value... */
.list-row.is-in-run.is-run-start .list-src::after {
  content: "";
  top: calc(50% + 0.6rem);
  bottom: 0;
  border-left: var(--tree-stroke) solid var(--tree-line);
}
/* ...carries on past each row, and stops at the last row's elbow. */
.list-thread::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; border-left: var(--tree-stroke) solid var(--tree-line); }
.list-row.is-run-end .list-thread::before { content: none; }
.list-thread::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 50%;
  width: var(--tree-stub);
  border: 0 solid var(--tree-line);
  border-width: 0 0 var(--tree-stroke) var(--tree-stroke);
  border-bottom-left-radius: var(--tree-r);
}

/* Kind and Action as a log level, in the table's own sans so it doesn't read
   as another address: small uppercase in the tone colour, no marker. */
.list-label {
  --c: var(--info);
  font-family: var(--font);
  font-size: var(--text-micro);
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--c) 88%, var(--text));
}
.list-label.is-success { --c: var(--success); }
.list-label.is-danger { --c: var(--danger); }
.list-label.is-warning { --c: var(--warning); }
/* CROWDSEC is long and on nearly every alert row; one step smaller there. */
.alerts-table .list-label { font-size: var(--text-xx-small); letter-spacing: 0.06em; }

.list-row .list-scen { color: var(--text); }
.list-row .list-origin { color: var(--muted); }
.list-row .is-quiet,
.list-row .is-quiet * { color: color-mix(in srgb, var(--muted) 62%, transparent); }
.list-row .is-quiet .list-chip { background: transparent; }

/* A blocklist update is a change, not good or bad news. */
.list-change { font-variant-numeric: tabular-nums; }
.list-n { color: var(--text); }
.list-sep { margin: 0 0.45rem; color: color-mix(in srgb, var(--muted) 60%, transparent); }
.list-dec { font-weight: 600; color: var(--text); }
/* One digit wide (1ch in tabular figures), as tall as a figure, on the baseline. */
.pending-mark { display: inline-block; width: 1ch; text-align: center; color: color-mix(in srgb, var(--muted) 85%, transparent); }
.pending-mark svg { width: 0.4375rem; height: 0.6875rem; vertical-align: -0.03rem; } /* 7×11px */

/* The count is the fill: as long as its share, never shorter than the
   number, so the edge always clears it. */
.list-bar { --c: var(--accent); display: block; height: 1.25rem; border-radius: 4px; overflow: hidden; }
.list-bar b {
  display: block;
  box-sizing: border-box;
  width: var(--p);
  min-width: max-content;
  padding: 0 calc(0.15rem + 3px) 0 0.3rem;
  border-radius: 4px;
  background: color-mix(in srgb, var(--c) 22%, transparent);
  box-shadow: inset -2px 0 0 color-mix(in srgb, var(--c) 70%, transparent);
  line-height: 1.25rem;
  font-weight: 600;
  color: var(--text);
}
.list-bar.is-zero b { background: none; box-shadow: none; font-weight: 500; color: var(--muted); }

/* The clock stays under the left-aligned header; the age sits on the right edge. */
.list-time .num { color: var(--text); }
.list-when { display: flex; align-items: baseline; justify-content: space-between; gap: 0.4rem; }
.list-age { color: var(--muted); font-size: var(--text-x-small); }
.list-exp { display: grid; gap: 0.2rem; width: 5.5rem; }
.list-exp .num { color: var(--text); line-height: 1; }
.list-track { display: block; height: 3px; border-radius: 2px; background: color-mix(in srgb, var(--text) 9%, transparent); overflow: hidden; }
.list-track i { display: block; height: 100%; border-radius: 2px; background: color-mix(in srgb, var(--accent) 80%, var(--text)); }

/* The shared action bar without its frame: the dividers keep the actions
   apart, and only the action under the pointer tints. */
.list-row td.list-act { overflow: visible; padding-right: 0.35rem; }
.list-table .decision-row-actions { padding: 0; border: 0; background: transparent; }

.decision-card-list { display: grid; gap: 0.55rem; }
.decision-card {
  min-width: 0;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  background: var(--panel);
}
.decision-card-top,
.decision-card-foot { display: flex; align-items: center; }
.decision-card-top,
.decision-card-foot { justify-content: space-between; gap: 0.65rem; }
.decision-card-expiry { color: var(--muted); font-size: var(--text-small); }
.decision-card-value { margin-top: 0.65rem; font-size: 0.88rem; overflow-wrap: anywhere; }
.decision-card-reason {
  margin-top: 0.25rem;
  color: color-mix(in srgb, var(--text) 88%, var(--muted));
  font-size: var(--text-control);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.decision-card-meta { margin-top: 0.35rem; color: var(--muted); font-size: var(--text-x-small); }
.decision-card-foot {
  align-items: flex-end;
  flex-wrap: wrap;
  margin-top: 0.65rem;
  padding-top: 0.6rem;
  border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.decision-card-country { color: var(--muted); font-size: 0.7rem; }

.mobile-only { display: grid; }
.desktop-only { display: none; }

.pagy-nav {
  margin-top: var(--space-4);
}

/* Alerts: where the list carries on. The wrapper is what list-more observes,
   so it keeps an unclipped box; the link inside stays out of sight while
   batches load on their own, and comes back on keyboard focus, past the
   auto-load ceiling, after a failed batch, or without JS. */
.list-results:focus { outline: none; }
.list-more {
  display: flex;
  justify-content: center;
  min-height: 1px;
  margin-top: var(--space-4);
}
.list-more-link.is-quiet:not(:focus-visible) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Alerts: the day rail, in the empty space right of the table (day-rail
   places it and shows it only where it fits). Each day is a segment beside
   its rows; its date is sticky inside it and trails a short line that fades
   out. overflow-y: clip keeps the line inside its day without making the
   segment a scroll container, which would stop the date sticking. */
.list-results { position: relative; }
.day-rail {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 100%;
  width: 6.6rem;
  margin-inline: 0.85rem 0.5rem;
  pointer-events: none;
}
.day-rail[hidden] { display: none; }
.day-rail-day { position: absolute; left: 0; right: 0; overflow-x: visible; overflow-y: clip; }
.day-rail-date {
  position: sticky;
  top: 0.9rem;
  display: block;
  width: max-content;
  margin: 0.55rem 0 0 0.45rem;
  padding-left: 0.65rem;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--text-x-small);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  line-height: 1;
  white-space: nowrap;
}
.day-rail-date::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.1rem;
  height: 7rem;
  border-left: 1px solid transparent;
  border-image: linear-gradient(color-mix(in srgb, var(--muted) 45%, transparent), transparent) 1;
}

.pagy-nav nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  justify-content: center;
}

.pagy-nav a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2rem;
  padding: 0.35rem 0.55rem;
  border-radius: var(--radius-control);
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--muted);
  font-size: var(--text-control);
  font-weight: 600;
  text-decoration: none;
}

.pagy-nav a[href]:hover { color: var(--text); }
.pagy-nav [aria-current="page"] {
  background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
  color: var(--accent-text);
}
.pagy-nav a[aria-disabled="true"]:not([aria-current], [role="separator"]) { opacity: 0.4; }

/* ── Metrics (Pulse Deck) ──────────────────── */

.metrics-page {
  /* scoped mobile full-bleed for wide panels only */
}

.metrics-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
  margin-bottom: 1rem;
}

/* Inside a grid, gap owns spacing — avoid double margin */
.metrics-grid > .panel { margin-bottom: 0; }

@media (min-width: 900px) {
  .metrics-grid { grid-template-columns: 1fr 1fr; }
}

/* Mobile: full-bleed on the left; leave a thin right gutter for the scrollbar */
@media (max-width: 719px) {
  .metrics-page {
    --metrics-sb-gap: 10px; /* room so scrollbar doesn’t cover cards */
    margin-left: -1rem;  /* cancel .app-main left padding — flush left */
    margin-right: calc(-1rem + var(--metrics-sb-gap)); /* keep right gap */
  }

  .metrics-page .page-head,
  .metrics-page .stats-grid,
  .metrics-page > .empty-panel {
    padding-left: 1rem;
    padding-right: calc(1rem - var(--metrics-sb-gap));
  }

  .metrics-page > .panel,
  .metrics-page .metrics-grid > .panel {
    /* flush left; soft radius only on the right (matches rounded UI + scrollbar gap) */
    border-radius: 0 var(--radius-large) var(--radius-large) 0;
    border-left: 0;
    border-right: 1px solid var(--border);
  }

  .metrics-page > .panel {
    margin-bottom: 0.75rem;
  }

  .metrics-page .metrics-grid {
    gap: var(--space-3);
    margin-bottom: 0.75rem;
  }

  .metrics-page .panel-b {
    padding: 0.85rem;
  }

  .metrics-page .panel-h {
    padding-inline: 0.85rem;
  }

  /* KPI cards stay rounded + inset (not full-bleed slabs) */
  .metrics-page .stats-grid .stat-card {
    border-radius: var(--radius-large);
  }

  /* ── Fitting the tables on a phone ──────────────────────────────────────
     Sized for 360px, the narrowest common Android, which covers wider phones
     for free. Measured before: Bouncer requests and Scenario buckets already
     fit their column and scrolled only because of the 480px floor above. */
  .metrics-page .metrics-table {
    min-width: 0;
  }

  .metrics-page .metrics-table th,
  .metrics-page .metrics-table td {
    padding-inline: 0.25rem;
  }

  .metrics-page .metrics-th-full { display: none; }
  .metrics-page .metrics-th-short { display: inline; }

  /* Sources, routes and scenario names are paths and slugs with no spaces to
     break at, so they set the table's width instead of wrapping. Let them
     break anywhere and the numeric columns get the room they need. */
  .metrics-page .metrics-ident {
    overflow-wrap: anywhere;
    word-break: break-word;
  }

  /* Numbers never need more than their own width; give the rest to the name.
     A max rather than a fixed width, so auto layout can still hand space back
     when a column's numbers are short. */
  .metrics-page .metrics-table th.num,
  .metrics-page .metrics-table td.num {
    max-width: 4.5rem;
  }
}

.panel-b { padding: var(--space-4); }
.panel-hint { font-size: var(--text-small); color: var(--muted); }
.metrics-subh {
  font-size: var(--text-control);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.65rem;
}

.metrics-split {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}

@media (min-width: 720px) {
  .metrics-split { grid-template-columns: 1fr 1fr; }
}

.metrics-note {
  margin-top: 0.85rem;
  font-size: var(--text-caption);
  color: var(--muted);
  line-height: 1.45;
}

.metrics-note code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  color: var(--accent-text);
}

.chart-box {
  height: 220px;
  position: relative;
}

.chart-box canvas { display: block; }

.bar-list { display: grid; gap: 0.55rem; }
.bar-row { display: grid; gap: var(--space-1); }
.bar-top {
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  font-size: var(--text-compact);
}
.bar-top .name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bar-top .n {
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-weight: 600;
  flex-shrink: 0;
}
.bar-track {
  height: 8px;
  background: var(--panel-2);
  border-radius: var(--radius-pill);
  overflow: hidden;
}
.bar-fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--accent) 72%, var(--panel)),
    color-mix(in srgb, var(--info) 68%, var(--panel))
  );
}

.metrics-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-normal);
  /* Keeps columns from squashing where there is room to spare. Lifted on a
     phone, where it was the only reason two of these tables scrolled at all. */
  min-width: 480px;
}

/* Short header shows on a phone; the full word is always in the accessibility
   tree, so shortening costs nothing to a screen reader. */
.metrics-th-short { display: none; }
.metrics-table th {
  text-align: left;
  font-size: var(--text-x-small);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  padding: 0.5rem 0.4rem;
  border-bottom: 1px solid var(--border);
}
.metrics-table td {
  padding: 0.55rem 0.4rem;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.metrics-table tr:last-child td { border-bottom: 0; }
/* IBM Plex Mono runs visibly larger than Inter at the same nominal size, so
   mono values read as oversized beside the text next to them even though they
   are the smaller number (12.48px against 13.12px). An em keeps this an
   optical correction relative to whatever the container sets, rather than a
   fixed size to forget about. Scoped to the metrics page: .mono-soft is shared
   with 20 other views whose neighbours are sized differently. */
.metrics-table .mono-soft { font-size: 0.88em; }

/* Numeric columns took a quarter of the table each, and the identity column
   absorbed the rest — 726px of it — so a scenario's name and its first number
   sat half a screen apart. The table now takes the width it needs and the
   slack falls at the right, where it costs nothing to read. */
@media (min-width: 720px) {
  .metrics-table th.num,
  .metrics-table td.num { width: 8rem; }
}

/* Bouncer mode, using the Bouncers page's own vocabulary. */
.bouncer-mode {
  display: inline-block;
  font-size: var(--text-micro);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
}

.bouncer-mode.is-stream { color: var(--accent-text); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
.bouncer-mode.is-live { color: var(--info); border-color: color-mix(in srgb, var(--info) 40%, var(--border)); }
.bouncer-mode.is-mixed { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, var(--border)); }

.bouncer-match-of { color: var(--muted); font-size: 0.88em; margin-left: 0.3rem; }
.bouncer-match-na { color: var(--muted); }

.metrics-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--text) 88%, var(--muted));
}

.rate { font-weight: 700; font-variant-numeric: tabular-nums; }
.rate.good { color: var(--success); }
.rate.mid { color: var(--warning); }
.rate.bad { color: var(--danger); }

/* ── Settings ──────────────────────────────── */

.settings-page {
  display: grid;
  gap: var(--space-4);
}

.settings-page-title {
  display: flex;
  align-items: center;
  gap: 0.42rem;
}

.settings-page-title-root { color: var(--muted); }
.settings-page-title-current { color: var(--text); }

.settings-page-title svg {
  width: 0.88rem;
  height: 0.88rem;
  flex: 0 0 auto;
  color: color-mix(in srgb, var(--muted) 68%, transparent);
}

.settings-nav {
  display: grid;
  align-content: start;
  gap: 0.12rem;
}

.settings-nav--pane {
  width: var(--context-pane-w);
  min-width: var(--context-pane-w);
  /* Sits directly under .list-filters-head, which supplies the top rhythm. */
  padding: 0.15rem 0.65rem 0.85rem;
}

/* The head is emitted inside the pane's scroll wrapper here, so it needs the
   pane's fixed width for the same clip-not-reflow reason as everything else. */
.context-pane .list-filters-head {
  width: var(--context-pane-w);
  min-width: var(--context-pane-w);
}

.settings-mobile-menu {
  display: grid;
  gap: 0.65rem;
  width: min(100%, 34rem);
}

.settings-nav--mobile { gap: 0.16rem; }

.settings-nav--mobile .settings-nav-item {
  min-height: 2.8rem;
  padding: 0.62rem 0.7rem;
  font-size: 0.86rem;
}

.settings-nav--mobile .settings-nav-icon {
  width: 17px;
  height: 17px;
  flex-basis: 17px;
}

.settings-nav-chevron {
  width: 14px;
  height: 14px;
  margin-left: auto;
  opacity: 0.42;
}

/* Phone head: the way back first and small, the page name large. */
.settings-mobile-head {
  display: grid;
  gap: 0.15rem;
  margin: 0.15rem 0 0.4rem;
}

.settings-mobile-head h1 {
  font-size: 1.45rem;
  letter-spacing: -0.02em;
}

.settings-mobile-back {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  width: fit-content;
  min-height: var(--tap-target);
  margin-left: -0.3rem;
  padding: 0 0.3rem;
  color: var(--accent-text);
  font-size: var(--text-control);
  font-weight: 500;
  text-decoration: none;
}

.settings-mobile-back:hover { color: var(--text); }
.settings-mobile-back svg { width: 1rem; height: 1rem; }

.settings-feature-form { padding: var(--space-4); }

.settings-feature-form .form-input { max-width: 26rem; }

.settings-feature-form .form-input-num { max-width: 5rem; }

.settings-feature-fields {
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.settings-feature-fields:disabled .form-input {
  opacity: 0.55;
}

.form-note {
  font-size: var(--text-small);
  color: var(--muted);
}

.form-note a { color: var(--accent-text); }

.form-note-warning { color: var(--warning); }

.btn-secondary[aria-disabled="true"] { pointer-events: none; }

/* Toggle switch — stretch on press (left/right insets, not translateX). */
.switch-row {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  cursor: pointer;
  user-select: none;
}

.switch-row--compact {
  align-items: center;
  gap: 0;
  margin-top: 0;
}

.switch {
  --switch-w: 2.75rem;
  --switch-h: 1.5rem;
  --switch-pad: 0.1875rem;
  --switch-thumb: 1.125rem;
  --switch-stretch: 0.55rem;
  --switch-motion: 0.2s cubic-bezier(0.22, 1, 0.36, 1);
  position: relative;
  flex-shrink: 0;
  width: var(--switch-w);
  height: var(--switch-h);
  margin-top: 0.1rem;
}

.switch--compact {
  --switch-w: 1.75rem;
  --switch-h: 1.05rem;
  --switch-pad: 0.14rem;
  --switch-thumb: 0.77rem;
  --switch-stretch: 0.32rem;
  margin-top: 0;
}

.switch input {
  position: absolute;
  inset: 0;
  z-index: 1;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.switch-track {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--muted) 38%, var(--panel-2));
  transition: background var(--switch-motion);
  pointer-events: none;
}

.switch-track::after {
  content: "";
  position: absolute;
  top: var(--switch-pad);
  bottom: var(--switch-pad);
  left: var(--switch-pad);
  right: calc(100% - var(--switch-pad) - var(--switch-thumb));
  border-radius: var(--radius-pill);
  background: white;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--text) 22%, transparent);
  transition:
    left var(--switch-motion),
    right var(--switch-motion),
    background var(--switch-motion);
}

.switch input:checked + .switch-track { background: var(--accent); }

.switch input:checked + .switch-track::after {
  left: calc(100% - var(--switch-pad) - var(--switch-thumb));
  right: var(--switch-pad);
}

.switch-row:active:not(:has(input:disabled)) .switch input:not(:checked) + .switch-track::after,
.switch input:active:not(:disabled):not(:checked) + .switch-track::after {
  right: calc(100% - var(--switch-pad) - var(--switch-thumb) - var(--switch-stretch));
}

.switch-row:active:not(:has(input:disabled)) .switch input:checked + .switch-track::after,
.switch input:active:not(:disabled):checked + .switch-track::after {
  left: calc(100% - var(--switch-pad) - var(--switch-thumb) - var(--switch-stretch));
  right: var(--switch-pad);
}

.switch input:focus-visible + .switch-track {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

.switch input:disabled { cursor: not-allowed; }

.switch input:disabled + .switch-track { opacity: 0.4; }

.switch-row:has(.switch input:disabled) { cursor: not-allowed; }

.switch-row:has(.switch input:disabled) .switch-state { opacity: 0.55; }

.switch-label {
  display: grid;
  gap: 0.1rem;
  font-size: 0.85rem;
}

.switch-state { font-weight: 600; }

.switch-state-off { color: var(--muted); }

.switch-state-on { display: none; }

.switch-row:has(.switch input:checked) .switch-state-on { display: block; }

.switch-row:has(.switch input:checked) .switch-state-off { display: none; }

@media (prefers-reduced-motion: reduce) {
  .switch-track,
  .switch-track::after { transition: none; }
}

.settings-section { margin-bottom: 0; }

.settings-section,
.settings-section > .panel-b {
  min-width: 0;
}

.settings-section .panel-h { border-bottom: 1px solid var(--border); }

turbo-frame[data-controller~="inventory-refresh"] { display: block; min-width: 0; }
.suppressions-inventories { display: grid; gap: var(--space-4); min-width: 0; }
.suppressions-inventories .warning-admonition { margin-bottom: 0; }

.postoverflow-rule {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 1.25rem;
  align-items: start;
  gap: 1.25rem;
  padding: 1.25rem var(--space-4);
  border-bottom: 1px solid var(--border);
}
.postoverflow-rule:last-child { border-bottom: 0; }
.postoverflow-rule-content { min-width: 0; }
.postoverflow-rule-heading { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem; }
.postoverflow-rule-heading > strong,
.postoverflow-rule-link { color: var(--text); font-size: var(--text-normal); font-weight: 650; overflow-wrap: anywhere; text-decoration: none; }
/* A real destination link covers the row, including its chevron and blank space. */
.postoverflow-rule-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.postoverflow-rule-link:focus-visible { outline: 0; }
.postoverflow-rule-link:focus-visible::after { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.postoverflow-rule-state { color: var(--muted); font-size: var(--text-xx-small); }
.postoverflow-rule-chevron { width: 1.1rem; height: 1.1rem; color: var(--muted); margin-top: 0.15rem; }
@media (hover: hover) {
  .postoverflow-rule:has(.postoverflow-rule-link):hover { background: color-mix(in srgb, var(--text) 3%, transparent); }
  .postoverflow-rule:has(.postoverflow-rule-link):hover .postoverflow-rule-chevron { color: var(--accent-text); }
}
.postoverflow-rule:has(.postoverflow-rule-link:active) { background: color-mix(in srgb, var(--text) 5%, transparent); }
.postoverflow-rule-facts { display: grid; grid-template-columns: 3.6rem minmax(0, 1fr); gap: 0.5rem 0.75rem; margin: 0.75rem 0 0; font-size: var(--text-x-small); }
.postoverflow-rule-facts dt { color: var(--muted); }
.postoverflow-rule-facts dd { min-width: 0; margin: 0; overflow-wrap: anywhere; }
.postoverflow-rule-scenario { color: var(--accent-text); font-size: var(--text-xx-small); }
.postoverflow-rule-namespace { color: var(--muted); }
.postoverflow-rule-conditions { min-width: 0; padding-left: 0.7rem; border-left: 2px solid var(--border); }
.postoverflow-rule-match { margin: 0 0 0.35rem; color: var(--muted); font-size: var(--text-xx-small); }
.postoverflow-rule-condition { font-size: var(--text-x-small); line-height: 1.8; overflow-wrap: anywhere; }
.postoverflow-rule-condition > span:not(.postoverflow-rule-join) { color: var(--muted); }
.postoverflow-rule-condition code { color: var(--text); font: var(--text-x-small)/1.8 var(--font-mono); overflow-wrap: anywhere; }
.postoverflow-rule-asn::before { content: "· "; }
.postoverflow-rule-join { color: var(--accent-text); font: var(--text-micro) var(--font-mono); margin-right: 0.35rem; }
.postoverflow-rule-more { display: block; color: var(--muted); font-size: var(--text-xx-small); }
.postoverflow-rule-preview-note { color: var(--muted); }
@media (max-width: 640px) {
  .postoverflow-rule { gap: 0.5rem; padding: 1rem var(--space-3); }
  .postoverflow-rule-facts { grid-template-columns: 2.8rem minmax(0, 1fr); gap: 0.5rem; }
}

.postoverflow-whitelist-form .banner { margin-bottom: 1rem; }

#postoverflow-file-editor {
  display: grid;
  min-width: 0;
  gap: var(--space-4);
}

#postoverflow-file-editor .status-note {
  white-space: normal;
  line-height: 1.5;
}

#postoverflow-file-editor p.status-note { margin: 0.75rem 0; }
#postoverflow-file-editor textarea.form-input { max-width: none; width: 100%; }
#postoverflow-file-editor .panel-h h2 { overflow-wrap: anywhere; }

/* Shared creation and existing-file editor. */
.whitelist-editor [hidden] { display: none !important; }
.whitelist-editor { overflow: visible; }
.whitelist-editor-header { min-width: 0; overflow-wrap: anywhere; }
.whitelist-editor-header h2 { margin: 0.35rem 0; font-size: var(--text-medium); font-weight: 600; }
.whitelist-editor-form { min-width: 0; }
.whitelist-editor-form fieldset { min-width: 0; padding: 0; margin: 0; border: 0; }
.whitelist-editor-tabs { display: flex; align-items: center; gap: 1rem; padding: 0 1rem; border-bottom: 1px solid var(--border); }
.whitelist-editor-tabs [role="tablist"] { display: flex; align-self: stretch; gap: 1.5rem; }
.whitelist-editor-tabs [role="tab"] {
  -webkit-tap-highlight-color: transparent;
  padding: 0.85rem 0;
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--muted);
  font: 500 var(--text-caption) var(--font);
  cursor: pointer;
}
.whitelist-editor-tabs [aria-selected="true"] { border-bottom-color: var(--accent); color: var(--accent-text); }
.whitelist-editor-tabs [role="tab"]:disabled { opacity: 0.45; cursor: not-allowed; }
.whitelist-mode-note { padding: 0.7rem 1rem; margin: 0; color: var(--muted); font-size: var(--text-x-small); line-height: 1.6; border-bottom: 1px solid var(--border); }
.whitelist-advanced-panel { padding: 1rem; }
.whitelist-creation-options { padding: 0 1rem 1rem; }
.whitelist-code { min-width: 0; border: 1px solid var(--border); border-radius: var(--radius-surface); overflow: hidden; background: var(--bg); }
.whitelist-code-header,.whitelist-code-footer { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.5rem 0.75rem; color: var(--muted); font: var(--text-micro) var(--font-mono); }
.whitelist-code-header { background: var(--panel-2); border-bottom: 1px solid var(--border); }
.whitelist-code-header > span:first-child { overflow-wrap: anywhere; min-width: 0; }
.whitelist-code-header > span:last-child { flex: none; }
.whitelist-code-footer { border-top: 1px solid var(--border); }
.whitelist-code-editor { min-width: 0; }
.whitelist-code .cm-editor { height: auto; min-height: 12rem; max-height: 75svh; resize: vertical; overflow: hidden; outline: 0; background: var(--bg); color: var(--text); font-size: 0.72rem; }
.whitelist-code .cm-editor.cm-focused { outline: none; box-shadow: none; }
.whitelist-code .cm-scroller { overflow: auto; font-family: var(--font-mono); line-height: 1.5rem; }
.whitelist-code .cm-content { padding: 0.75rem 0; caret-color: var(--text); }
.whitelist-code .cm-line { padding: 0 0.75rem; }
.whitelist-code .cm-content ::selection { background: var(--accent-soft); }
.whitelist-code .cm-gutters { border: 0; background: color-mix(in srgb, var(--panel) 65%, var(--bg)); color: var(--muted); }
.whitelist-code .cm-lineNumbers .cm-gutterElement { min-width: 2.7rem; padding: 0 0.6rem 0 0.2rem; border-left: 2px solid transparent; }
.whitelist-code .cm-lineNumbers .is-error { color: var(--danger); border-left-color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent); }
.whitelist-code .yaml-error-line { background: color-mix(in srgb, var(--danger) 8%, transparent); box-shadow: inset 0 -1px color-mix(in srgb, var(--danger) 70%, transparent); }
.whitelist-code .yaml-key { color: var(--accent-text); }
.whitelist-code .yaml-string { color: color-mix(in srgb, var(--success) 75%, var(--text)); }
.whitelist-code .yaml-comment { color: color-mix(in srgb, var(--muted) 80%, var(--text)); }
.whitelist-code .yaml-punctuation { color: var(--muted); }
.whitelist-code-input {
  position: relative;
  display: block;
  width: 100%;
  height: 24rem;
  min-height: 12rem;
  margin: 0;
  padding: 0.75rem;
  resize: vertical;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font: 0.72rem/1.5rem var(--font-mono);
  white-space: pre;
  tab-size: 2;
}
.whitelist-code-input:focus { outline: 0; box-shadow: none; }
.whitelist-code-input[hidden] { display: none; }
.whitelist-diagnostic { padding: 0.75rem 0.9rem; margin: 0 1rem 1rem; border-left: 2px solid var(--danger); border-radius: 0 var(--radius-control) var(--radius-control) 0; background: color-mix(in srgb, var(--danger) 6%, var(--panel)); color: var(--text); font-size: var(--text-caption); }
.whitelist-diagnostic p { overflow-wrap: anywhere; white-space: pre-wrap; margin: 0; }
.whitelist-diagnostic[hidden],.whitelist-diagnostic [hidden] { display: none; }
.whitelist-diagnostic.is-success { border-left-color: var(--success); background: color-mix(in srgb, var(--success) 6%, var(--panel)); }
.whitelist-diagnostic.is-pending { border-left-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--panel)); }
.whitelist-error-location { display: inline-block; margin-top: 0.5rem; border: 0; padding: 0; background: transparent; color: var(--accent-text); text-decoration: underline; text-underline-offset: 3px; font: var(--text-x-small) var(--font-mono); cursor: pointer; }
.whitelist-editing-note { max-width: 52rem; margin: 0; padding: 0 1rem 1rem; color: var(--muted); font-size: var(--text-x-small); line-height: 1.7; }
.whitelist-editor-footer { display: flex; justify-content: flex-end; align-items: center; gap: 1rem; padding: 0.85rem 1rem; }
.whitelist-editor-footer .form-actions { margin: 0; flex: none; }
.whitelist-submit { display: inline-grid; place-items: center; min-height: 40px; line-height: 1; }
/* Keep the label's dimensions and accessible name while the spinner replaces it. */
.whitelist-submit > span { grid-area: 1 / 1; }
.whitelist-submit .pending-operation-spinner { visibility: hidden; border-color: currentColor; border-top-color: transparent; animation-play-state: paused; }
.whitelist-submit.is-loading .pending-operation-spinner { visibility: visible; animation-play-state: running; }
.whitelist-submit.is-loading .whitelist-submit-label { opacity: 0; }
.whitelist-editor-remove { margin-right: auto; background: transparent; border-color: transparent; }
/* Shown as Cancel, Check, Save; Save stays first in the form for Enter. */
.whitelist-editor-footer .whitelist-cancel { order: -2; }
.whitelist-editor-footer .whitelist-check { order: -1; }
@media (max-width: 640px) {
  .whitelist-editor-tabs [role="tab"],.whitelist-error-location { min-height: var(--tap-target); }
  .whitelist-code .cm-lineNumbers .cm-gutterElement { min-width: 2rem; }
  .whitelist-code .cm-line { padding-inline: 0.5rem; }
  .whitelist-code-input { padding-inline: 0.5rem; }
  .whitelist-editor-footer { flex-wrap: wrap; gap: 0.65rem; }
  .whitelist-editor-footer .form-actions { margin-left: auto; }
  .whitelist-editor-footer .btn-primary,.whitelist-editor-footer .btn-secondary { min-height: var(--tap-target); }
  .whitelist-editor-remove { min-height: var(--tap-target); }
}
@media (max-width: 480px) {
  .whitelist-editor-footer .form-actions { width: 100%; justify-content: flex-end; }
  .whitelist-editor-remove { order: 1; }
}

.postoverflow-whitelist-form-fields { max-width: 50rem; }

.postoverflow-whitelist-form-fields > .form-row { margin-bottom: 1.25rem; }

.postoverflow-whitelist-form-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: 0.85rem;
  margin-bottom: 0.5rem;
}

.postoverflow-condition-builder {
  margin-bottom: 1.25rem;
  padding: var(--space-3);
  border-radius: var(--radius-surface);
  background: color-mix(in srgb, var(--bg) 60%, var(--panel));
}

.postoverflow-condition-builder > .form-label {
  display: block;
  margin-bottom: 0.5rem;
  color: var(--muted);
  font-size: var(--text-x-small);
  font-weight: 600;
}

.postoverflow-condition-rows {
  display: grid;
  gap: 0.45rem;
}

.postoverflow-condition-row {
  display: grid;
  grid-template-columns: minmax(9rem, 0.9fr) minmax(7rem, 0.65fr) minmax(11rem, 1.45fr) 2rem;
  gap: var(--space-2);
  align-items: center;
}

.postoverflow-condition-row .custom-select-trigger,
.postoverflow-condition-row > .form-input { min-height: 2.2rem; font-size: var(--text-small); }

.postoverflow-condition-remove,
.postoverflow-condition-add {
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.postoverflow-condition-remove {
  width: 2rem;
  min-height: var(--control-height-small);
  border-radius: var(--radius-control);
  font-size: 1rem;
}

.postoverflow-condition-remove:hover:not(:disabled) { color: var(--danger); background: color-mix(in srgb, var(--danger) 8%, transparent); }
.postoverflow-condition-remove:disabled { opacity: 0.25; cursor: default; }
.postoverflow-condition-add { margin-top: 0.55rem; color: var(--info); font-size: var(--text-x-small); }

/* Conditions suggested by the source alert; pressed ones are in the form. */
.postoverflow-suggestions { margin-bottom: 0.85rem; }

.postoverflow-suggestions > .form-label {
  display: block;
  margin-bottom: 0.45rem;
  color: var(--muted);
  font-size: var(--text-x-small);
  font-weight: 600;
}

.postoverflow-suggestion-list { display: flex; flex-wrap: wrap; gap: 0.35rem; }

.postoverflow-suggestion {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35rem;
  max-width: 100%;
  min-width: 0;
  padding: 0.22rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--panel);
  color: var(--muted);
  font-size: var(--text-small);
  cursor: pointer;
  transition: border-color var(--transition-fast), color var(--transition-fast), background var(--transition-fast);
}

/* Drawn rather than typed, as font glyphs sit off centre at this size. The
   odd box centres the 1px strokes on whole pixels, keeping them sharp. */
.postoverflow-suggestion::before {
  content: "";
  flex: none;
  align-self: center;
  width: 9px;
  height: 9px;
  background: var(--info);
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'%3E%3Cpath d='M4.5 2v5M2 4.5h5' stroke='%23000' stroke-width='1'/%3E%3C/svg%3E") center / contain no-repeat;
}

.postoverflow-suggestion:hover:not(:disabled) { border-color: color-mix(in srgb, var(--info) 45%, var(--border)); color: var(--text); }

.postoverflow-suggestion[aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--info) 55%, var(--border));
  background: color-mix(in srgb, var(--info) 12%, var(--panel));
  color: var(--text);
}

.postoverflow-suggestion[aria-pressed="true"]::before {
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.6 6.2 5 8.6l4.4-5' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.postoverflow-suggestion:disabled { cursor: default; opacity: 0.5; }

.postoverflow-suggestion-label { flex: none; font-weight: 600; }

.postoverflow-suggestion-value {
  min-width: 0;
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: 0.92em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.postoverflow-suggestions > .form-note { margin-top: 0.45rem; }

.postoverflow-condition-builder > .form-note { margin: 0.55rem 0 0; }

/* The warning admonition's triangle and colour, at note size. */
.postoverflow-allowlist-note:not([hidden]) { display: flex; align-items: flex-start; gap: 0.4rem; }

.postoverflow-allowlist-note svg { flex: none; width: 1.1em; height: 1.1em; margin-top: 0.1em; color: #ff9100; }

.postoverflow-logic-preview {
  margin-top: 0;
  margin-bottom: 0;
  padding: 0.75rem 0.85rem;
  overflow-x: auto;
  border-radius: var(--radius-surface);
  background: #081017;
  box-shadow: inset 0 0 0 1px rgba(116, 203, 226, 0.1);
  color: #aebdca;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  line-height: 1.65;
}

.postoverflow-logic-expression {
  display: block;
  min-width: max-content;
  font: inherit;
}

.postoverflow-logic-line { display: block; }
.postoverflow-logic-opening,
.postoverflow-logic-closing { color: #8295a5; }
.postoverflow-logic-keyword { color: #c69bf4; }
.postoverflow-logic-subject { color: #73d2e6; }
.postoverflow-logic-value { color: #a9dc76; }

.postoverflow-logic-scope-item { padding-left: 1.1rem; }

.postoverflow-logic-scope-joiner {
  color: #f085a6;
  font-weight: 700;
}

.postoverflow-logic-condition {
  display: grid;
  grid-template-columns: minmax(7.5rem, auto) minmax(0, 1fr);
  gap: 1rem;
  padding-left: 1.1rem;
}

.postoverflow-logic-field { color: #8ecdf3; }
.postoverflow-logic-operator { color: #e8bd79; }

.postoverflow-logic-joiner {
  padding-left: 1.1rem;
  color: #f085a6;
  font-weight: 700;
}

/* Light theme keeps the same roles in darker inks; each is at least 4.5:1 on --panel-2. */
html[data-theme="light"] .postoverflow-logic-preview {
  background: var(--panel-2);
  box-shadow: inset 0 0 0 1px var(--border);
  color: #334155;
}

html[data-theme="light"] .postoverflow-logic-opening,
html[data-theme="light"] .postoverflow-logic-closing { color: var(--muted); }
html[data-theme="light"] .postoverflow-logic-keyword { color: #6d28d9; }
html[data-theme="light"] .postoverflow-logic-subject { color: #0e7490; }
html[data-theme="light"] .postoverflow-logic-value { color: #047857; }
html[data-theme="light"] .postoverflow-logic-field { color: #0369a1; }
html[data-theme="light"] .postoverflow-logic-operator { color: #a1460a; }
html[data-theme="light"] .postoverflow-logic-scope-joiner,
html[data-theme="light"] .postoverflow-logic-joiner { color: #be185d; }

.postoverflow-whitelist-unban-choice {
  margin: 1.25rem 0 1rem;
  padding: var(--space-3);
  border-radius: var(--radius-surface);
  background: var(--panel-2);
}

@media (max-width: 760px) {
  .postoverflow-whitelist-form-grid { grid-template-columns: 1fr; gap: 0; }
  .postoverflow-whitelist-form-grid > .form-row:first-child { margin-bottom: 1.25rem; }
  .postoverflow-condition-row { grid-template-columns: minmax(0, 1fr) 2rem; gap: 0.4rem; }
  .postoverflow-condition-row > .custom-select,
  .postoverflow-condition-row > .form-input { grid-column: 1; }
  .postoverflow-condition-row > .custom-select:nth-child(2) { grid-row: 2; }
  .postoverflow-condition-row > .form-input { grid-row: 3; }
  .postoverflow-condition-remove { grid-column: 2; grid-row: 1; }
  .postoverflow-logic-preview { font-size: 0.64rem; }
}

.connection-state-detail {
  min-width: 0;
  color: var(--muted);
  font-size: var(--text-control);
  overflow-wrap: anywhere;
}

/* The wrapper carries the reason as a tooltip; the button must not swallow the hover. */
.settings-allowlist-actions button:disabled { pointer-events: none; }

.text-danger { color: var(--danger); }

/* ── Settings · CrowdSec Hub ──────────────── */

.hub-page,
.hub-inventory {
  display: grid;
  gap: var(--space-4);
  min-width: 0;
}

/* The inventory frame is a grid item of .hub-page, so it has to be a block of
   its own rather than the inline box a turbo-frame defaults to. */
.hub-page > turbo-frame { display: block; }

/* Holds the inventory's place while cscli is read, so the page does not jump
   when the frame lands. */
.hub-loading {
  min-height: 10rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  color: var(--muted);
  font-size: 0.82rem;
}

.hub-freshness {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  color: var(--muted);
  font-size: 0.78rem;
}

.hub-freshness-warn { color: var(--warning); }

.hub-refresh {
  color: var(--accent);
  text-decoration: none;
  min-height: var(--tap-target);
  display: inline-flex;
  align-items: center;
}

.hub-refresh:hover { text-decoration: underline; }
.hub-update-check { display: contents; }
button.hub-refresh { padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
button.hub-refresh:disabled { color: var(--muted); cursor: progress; text-decoration: none; }

.hub-subnav {
  display: flex;
  gap: 1.15rem;
  min-width: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
}

.hub-subnav-link {
  position: relative;
  padding: 0.28rem 0 0.5rem;
  color: var(--muted);
  font-size: 0.76rem;
  font-weight: 600;
  transition: color var(--transition-fast);
}

.hub-subnav-link:hover { color: var(--text); }

.hub-subnav-link.is-active { color: var(--accent-text); }

.hub-subnav-link.is-active::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--accent);
}

.hub-operation {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: var(--radius-surface);
}

.hub-operation > div { display: grid; gap: 0.12rem; }
.hub-operation strong { font-size: var(--text-compact); }
.hub-operation span { font-size: 0.7rem; color: var(--muted); }

.hub-operation-indicator {
  width: 0.55rem;
  height: 0.55rem;
  flex: 0 0 auto;
  border-radius: var(--radius-round);
  background: var(--success);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--success) 12%, transparent);
}

.hub-operation--pending .hub-operation-indicator,
.hub-operation--running .hub-operation-indicator {
  background: var(--info);
  animation: hub-operation-pulse 1.2s ease-in-out infinite;
}

@keyframes hub-operation-pulse {
  0%, 100% { opacity: 0.45; transform: scale(0.9); }
  50% { opacity: 1; transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .hub-operation--pending .hub-operation-indicator,
  .hub-operation--running .hub-operation-indicator { animation: none; }
}

.hub-visibility-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.65rem;
  margin-bottom: 1rem;
}

.hub-filterbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem 1.1rem;
  align-items: flex-end;
  padding-inline: 0.1rem;
  margin-bottom: 0.75rem;
}

.hub-filter-choice,
.hub-filter-control {
  display: grid;
  gap: var(--space-1);
}

.hub-filter-label {
  color: var(--muted);
  font-size: var(--text-xx-small);
  font-weight: 650;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.hub-filter-options {
  display: flex;
  align-items: center;
  gap: 0.1rem;
}

.hub-filter-option {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: var(--control-height-compact);
  padding: 0.35rem 0.48rem;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-control);
  font: inherit;
  font-size: 0.69rem;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.hub-filter-option::before {
  content: "";
  width: 0.58rem;
  height: 0.58rem;
  flex: 0 0 auto;
  border: 1px solid color-mix(in srgb, var(--muted) 72%, transparent);
  border-radius: var(--radius-pill);
}

.hub-filter-option:hover:not(.is-selected) { color: var(--text); background: color-mix(in srgb, var(--text) 3%, transparent); }
.hub-filter-option:focus-visible { outline: 1px solid var(--primary); outline-offset: -1px; }
.hub-filter-option.is-selected { color: var(--text); }
.hub-filter-option.is-selected::before {
  background: var(--primary);
  border-color: var(--primary);
  box-shadow: inset 0 0 0 2px var(--bg);
}
.hub-filter-choice[data-hub-scenarios-target="modeFilter"] .hub-filter-option[data-filter-value="enforcing"].is-selected::before { background: var(--success); border-color: var(--success); }
.hub-filter-choice[data-hub-scenarios-target="modeFilter"] .hub-filter-option[data-filter-value="observe"].is-selected::before { background: var(--warning); border-color: var(--warning); }
.hub-filter-choice[data-hub-scenarios-target="modeFilter"] .hub-filter-option[data-filter-value="disabled"].is-selected::before { background: var(--danger); border-color: var(--danger); }

.hub-filter-collection { width: clamp(13rem, 19vw, 18rem); }

.hub-result-count {
  align-self: center;
  margin-left: auto;
  color: var(--muted);
  font-size: 0.7rem;
  white-space: nowrap;
  padding-inline: 0.25rem;
}

.hub-scenario-list {
  overflow-x: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
}

.hub-scenario-header,
.hub-scenario {
  display: grid;
  grid-template-columns: minmax(16rem, 2fr) minmax(11rem, 1.25fr) minmax(10rem, 1fr) 4.5rem 10rem;
  gap: var(--space-3);
  align-items: center;
  min-width: 58rem;
}

.hub-scenario-header {
  padding: 0.45rem 0.75rem;
  color: var(--muted);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 78%, transparent);
  font-size: var(--text-micro);
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.hub-scenario {
  padding: 0.42rem 0.75rem;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 78%, transparent);
  box-shadow: inset 3px 0 transparent;
  transition: background var(--transition-fast), box-shadow var(--transition-fast);
}

.hub-scenario:last-child { border-bottom: 0; }
.hub-scenario[hidden] { display: none; }
.hub-scenario.is-staged {
  background: color-mix(in srgb, var(--accent) 6%, var(--panel));
  box-shadow: inset 3px 0 var(--accent);
}

.hub-scenario-name-cell { display: grid; gap: 0.15rem; min-width: 0; }
.hub-scenario-identity { min-width: 0; display: flex; align-items: center; gap: 0.45rem; }

/* Every scenario a Hub item defines, joined to it by tree connectors. Items
   are padded rather than spaced by a gap, so the vertical line stays unbroken. */
.hub-scenario-members {
  display: grid;
  margin: 0 0 0.1rem;
  padding: 0;
  list-style: none;
}
/* Desktop: the mode follows its name, so it never reads as the next column. */
.hub-scenario-members li {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  min-width: 0;
  padding: 0.12rem 0 0.12rem 1.37rem;
  font-size: 0.66rem;
}
/* The list runs' tree: the trunk under the middle of the item name's first
   character, counted in the name's own `ch`. */
.hub-scenario-members li::before,
.hub-scenario-members li::after {
  position: absolute;
  left: calc(0.5ch - var(--tree-stroke) / 2);
  content: "";
  border: 0 solid var(--tree-line);
  font-family: var(--font-mono);
  font-size: 0.74rem;
}
/* The trunk reaches up to the name and stops at the last item's elbow. */
.hub-scenario-members li::before { top: 0; bottom: 0; border-left-width: var(--tree-stroke); }
.hub-scenario-members li:first-child::before { top: -0.3rem; }
.hub-scenario-members li:last-child::before { content: none; }
.hub-scenario-members li::after {
  top: 0;
  bottom: 50%;
  width: var(--tree-stub);
  border-width: 0 0 var(--tree-stroke) var(--tree-stroke);
  border-bottom-left-radius: var(--tree-r);
}
.hub-scenario-members li:first-child::after { top: -0.3rem; }
.hub-scenario-members li .mono-soft {
  min-width: 0;
  overflow: hidden;
  color: color-mix(in srgb, var(--text) 62%, var(--muted));
  font-size: 0.72rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.hub-scenario-member-namespace { color: var(--muted); }

/* A row with nested scenarios lines every cell up with the item's own line,
   which is as tall as the mode control, rather than centring it on the list. */
.hub-scenario.has-members { --hub-item-line: calc(1.75rem + 4px); align-items: start; }
.hub-scenario.has-members .hub-scenario-identity { min-height: var(--hub-item-line); }
/* The item's line is taller than its name; tuck the list into that space. */
.hub-scenario.has-members .hub-scenario-members { margin-top: -0.35rem; }
.hub-scenario.has-members > .hub-scenario-collection,
.hub-scenario.has-members > .hub-scenario-activity,
.hub-scenario.has-members > .hub-scenario-version { line-height: var(--hub-item-line); }
.hub-scenario-members .hub-scenario-member-mode::before { content: "·" / ""; margin-right: 0.4rem; color: var(--muted); font-weight: 400; }
/* The phone sheet is one column, so its modes align at the right edge. */
.hub-scenario-member-list {
  display: grid;
  gap: 0.15rem;
  margin: 0.3rem 0 0.15rem;
  padding: 0;
  list-style: none;
}
.hub-scenario-member-list li {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  min-width: 0;
  font-size: 0.66rem;
}
.hub-scenario-member-list li .mono-soft { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-scenario-member-mode { flex-shrink: 0; font-weight: 600; }
.hub-scenario-member-mode[data-mode="enforcing"] { color: var(--success); }
.hub-scenario-member-mode[data-mode="observe"] { color: var(--warning); }
.hub-scenario-mode-note { margin: 0.3rem 0 0; color: var(--muted); font-size: 0.64rem; line-height: 1.45; }
/* A wrapped badge keeps its unwrapped width, leaving a gap beside the text.
   The name truncates instead. */
.hub-scenario-identity .badge,
.hub-item-badges .badge { flex-shrink: 0; white-space: nowrap; }
.hub-item-name { color: var(--text); font-size: 0.74rem; font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hub-item-name:hover { color: var(--accent-text); }
.hub-collection p { margin: 0.22rem 0 0; color: var(--muted); font-size: var(--text-small); line-height: 1.45; }

.hub-scenario-collection,
.hub-scenario-activity,
.hub-scenario-version {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 0.69rem;
}
.hub-scenario-activity strong { color: var(--text); font-weight: 600; }

.hub-mode-control { min-width: 0; }
.hub-mode-options {
  display: inline-grid;
  grid-template-columns: repeat(3, auto);
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-control);
  background: var(--panel-2);
}
.hub-mode-option {
  min-height: 1.75rem;
  padding: 0.25rem 0.5rem;
  overflow: hidden;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-compact);
  font: inherit;
  font-size: 0.64rem;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--transition-fast), background var(--transition-fast), box-shadow var(--transition-fast);
}
.hub-mode-option:hover:not(:disabled):not(.is-selected) { color: var(--text); background: color-mix(in srgb, var(--text) 5%, transparent); }
.hub-mode-option:focus-visible { outline: 1px solid var(--primary); outline-offset: -1px; }
.hub-mode-option[data-mode-value="enforcing"].is-selected { color: var(--success); background: color-mix(in srgb, var(--success) 16%, var(--panel)); }
.hub-mode-option[data-mode-value="observe"].is-selected { color: var(--warning); background: color-mix(in srgb, var(--warning) 16%, var(--panel)); }
.hub-mode-option[data-mode-value="disabled"].is-selected { color: var(--danger); background: color-mix(in srgb, var(--danger) 15%, var(--panel)); }
.hub-mode-option:disabled { cursor: default; }
/* An unavailable mode, as opposed to the current mode of a locked row. */
.hub-mode-option:disabled:not(.is-selected) {
  color: color-mix(in srgb, var(--muted) 45%, transparent);
  cursor: not-allowed;
}

.hub-scenario-mobile-list {
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-surface);
}

.hub-scenario-mobile-item {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: minmax(0, 1fr);
  grid-auto-columns: auto;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  min-height: 2.8rem;
  padding: 0.55rem 0.7rem;
  color: var(--text);
  background: transparent;
  border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 78%, transparent);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.hub-scenario-mobile-item:last-child { border-bottom: 0; }
.hub-scenario-mobile-item[hidden] { display: none; }
.hub-scenario-mobile-item:not([data-press-feedback-active]):active { background: color-mix(in srgb, var(--text) 4%, transparent); }
.hub-scenario-mobile-name { overflow: hidden; font-size: var(--text-small); font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.hub-scenario-mobile-mode { font-size: 0.63rem; font-weight: 600; white-space: nowrap; }
.hub-scenario-mobile-mode[data-mode="enforcing"] { color: var(--success); }
.hub-scenario-mobile-mode[data-mode="observe"] { color: var(--warning); }
.hub-scenario-mobile-mode[data-mode="disabled"] { color: var(--danger); }
.hub-scenario-mobile-mode[data-mode="mixed"] { color: var(--muted); }
.hub-scenario-mobile-chevron { color: var(--muted); font-size: 1.05rem; line-height: 1; }

.hub-scenario-sheet-scroll {
  height: 100%;
  min-height: 0;
  padding: 1.4rem 1rem 2rem 1.75rem;
  overflow-y: auto;
}
.hub-scenario-detail[hidden] { display: none; }
.hub-scenario-detail { display: grid; gap: 1.25rem; }
.hub-scenario-detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.hub-scenario-detail-head h2 { margin: 0.25rem 0 0; color: var(--text); font-size: var(--text-medium); line-height: 1.35; overflow-wrap: anywhere; }
.hub-scenario-detail-link { width: fit-content; color: var(--info); font-size: var(--text-small); }
.hub-scenario-detail-list { display: grid; gap: 0; margin: 0; }
.hub-scenario-detail-list > div { display: grid; gap: var(--space-1); padding: 0.8rem 0; border-bottom: 1px solid color-mix(in srgb, var(--border) 78%, transparent); }
.hub-scenario-detail-list > div:first-child { border-top: 1px solid color-mix(in srgb, var(--border) 78%, transparent); }
.hub-scenario-detail-list dt { color: var(--muted); font-size: 0.6rem; font-weight: 650; letter-spacing: 0.05em; text-transform: uppercase; }
.hub-scenario-detail-list dd { margin: 0; color: var(--text); font-size: var(--text-caption); line-height: 1.55; overflow-wrap: anywhere; }
.hub-scenario-detail-list dd strong { font-weight: 650; }
.hub-scenario-detail-mode { display: grid; gap: 0.45rem; }
.hub-scenario-detail-mode .hub-mode-options { width: fit-content; }

.hub-change-bar {
  position: sticky;
  z-index: 20;
  bottom: 1rem;
  margin: 1rem auto 0;
  width: min(34rem, calc(100% - 1rem));
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 0.65rem 0.75rem 0.65rem 0.9rem;
  border-radius: var(--radius-large);
  background: color-mix(in srgb, var(--panel) 92%, var(--accent));
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border));
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
}

.hub-change-bar[hidden] { display: none; }
.hub-change-bar > div { display: flex; gap: 0.4rem; }
.hub-change-bar strong { font-size: var(--text-caption); }

.hub-review {
  position: fixed;
  inset: 0;
  width: min(34rem, calc(100vw - 2rem));
  max-height: min(38rem, calc(100dvh - 2rem));
  margin: auto;
  padding: 0;
  color: var(--text);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.5);
}
.hub-review::backdrop { background: rgba(0, 0, 0, 0.62); backdrop-filter: blur(5px); }
.hub-review-card { display: grid; max-height: inherit; }
.hub-review .panel-h { display: flex; justify-content: space-between; align-items: flex-start; }
.hub-review .panel-h h2 { margin: 0; }
.hub-review ol { margin: 0; padding: 0.75rem 1rem 0.75rem 2.4rem; overflow-y: auto; display: grid; gap: var(--space-2); }
.hub-review li { padding-left: 0.2rem; font-size: var(--text-caption); }
.hub-review li strong,
.hub-review li span { display: block; }
.hub-review li span { color: var(--muted); margin-top: 0.1rem; }
.hub-review .form-actions { padding: 0.8rem 1rem; border-top: 1px solid var(--border); }

.hub-collection-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}
.hub-collection {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: start;
  gap: 0.45rem;
  min-width: 0;
  padding: 0.9rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-surface);
}
.hub-collection-head,
.hub-collection-foot { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
.hub-collection-head { align-items: flex-start; }
.hub-item-badges { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.3rem; flex-shrink: 0; }
.hub-collection-foot { margin-top: auto; padding-top: 0.35rem; color: var(--muted); font-size: var(--text-x-small); justify-content: flex-start; }
.hub-collection-foot .badge { margin-left: auto; }
.hub-empty-filter { text-align: center; color: var(--muted); font-size: var(--text-control); padding: 2rem; }

@media (max-width: 1100px) and (min-width: 960px) {
  .hub-result-count { width: 100%; margin-left: 0; }
}

@media (max-width: 959px) {
  .hub-filterbar { align-items: flex-start; }
  .hub-filter-collection { width: min(100%, 18rem); }
  .hub-result-count { width: 100%; margin-left: 0; }
  .hub-collection-grid { grid-template-columns: 1fr; }
  .hub-change-bar { bottom: calc(var(--bottom-h) + 0.75rem); }
}

@media (max-width: 540px) {
  .hub-filterbar { display: grid; gap: 0.65rem; }
  .hub-filter-options { flex-wrap: wrap; }
  .hub-filter-collection { width: 100%; }
  .hub-change-bar { align-items: stretch; flex-direction: column; }
  .hub-change-bar > div { display: grid; grid-template-columns: 1fr 1fr; }
}

/* ── Desktop breakpoint ────────────────────── */

@media (min-width: 960px) {
  .app-shell {
    grid-template-columns: auto 1fr;
    padding-bottom: 0;
  }

  /* Sticky makes the rail a stacking context, so the fixed “Try me” tip
     inside it can only rise as high as the rail itself. Above page content,
     below the page's own overlays (refresh bar, modals, toasts). */
  .unified-chrome {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    z-index: 30;
  }

  .top-mobile { display: none; }
  .bottom-nav { display: none; }

  .app-main-wrap { min-height: 100dvh; }
  .app-main { padding: 1.5rem 1.75rem 2rem; max-width: 1200px; margin-inline: auto; }

  .mobile-only { display: none !important; }
  .desktop-only { display: block; min-width: 0; max-width: 100%; }

  /* Pane stays display:flex; open/closed is width-only (see .context-pane rules) */
  .context-pane.desktop-only {
    display: flex;
  }
  .chrome-handle.desktop-only {
    display: flex;
  }

  .chrome-handle-wrap.desktop-only {
    display: flex;
  }

  .chrome-handle--idle.desktop-only {
    display: flex;
  }

  .theme-control.desktop-only {
    display: grid;
  }
}

/* —— Auth (login / first-run) —— */
.auth-body {
  min-height: 100dvh;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: Inter, system-ui, sans-serif;
  display: grid;
  place-items: center;
  padding: var(--space-5);
}

.auth-shell { width: min(100%, 24rem); }

.auth-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-large);
  padding: 1.75rem 1.5rem 1.5rem;
  box-shadow: 0 12px 40px color-mix(in srgb, #000 28%, transparent);
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-bottom: 1.25rem;
}

.auth-brand-title {
  font-family: Outfit, Inter, sans-serif;
  font-weight: 600;
  font-size: 1.15rem;
  letter-spacing: -0.02em;
}

.auth-heading {
  font-family: Outfit, Inter, sans-serif;
  font-size: 1.35rem;
  font-weight: 600;
  margin: 0 0 0.35rem;
  letter-spacing: -0.02em;
}

.auth-lead {
  margin: 0 0 1.25rem;
  color: var(--muted);
  font-size: var(--text-medium);
  line-height: 1.45;
}

.auth-form .form-row:last-of-type { margin-bottom: 0.25rem; }

.auth-actions {
  margin-top: 1.1rem;
  justify-content: stretch;
}

.auth-actions .btn-primary {
  width: 100%;
  justify-content: center;
  padding: 0.65rem 1rem;
  font-size: var(--text-medium);
}

.auth-passkey { margin-top: 1.1rem; }
.auth-passkey[hidden] { display: none; }

.auth-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1.1rem;
  color: var(--muted);
  font-size: var(--text-normal);
}

.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--border);
}

/* —— Demo sign-in: the example compose file beside the card ——
   Pressed into the page rather than set on it: a shade off the background
   with a light edge below and a dark one above, fading out at its edges.
   Sized from the file itself (--lines, --cols) against the room the card
   leaves, down to a readable floor; below that it scrolls in its own column
   rather than shrinking or running under the card. Wide screens only —
   nobody installs a container from a phone. */
.compose-example {
  --line: 1.5;
  --etch: color-mix(in srgb, var(--text) 38%, var(--bg));
  --y-comment: color-mix(in srgb, var(--text) 32%, var(--bg));
  --y-key: color-mix(in srgb, var(--text) 56%, var(--bg));
  --y-value: color-mix(in srgb, var(--text) 44%, var(--bg));
  --y-fill: color-mix(in srgb, var(--accent) 75%, var(--bg));
  display: none;
}

html[data-theme="light"] .compose-example {
  --etch: color-mix(in srgb, var(--text) 56%, var(--bg));
  --y-comment: color-mix(in srgb, var(--text) 50%, var(--bg));
  --y-key: color-mix(in srgb, var(--text) 74%, var(--bg));
  --y-value: color-mix(in srgb, var(--text) 62%, var(--bg));
  --y-fill: color-mix(in srgb, var(--accent) 85%, var(--bg));
}

@media (min-width: 900px) {
  .auth-body.has-aside {
    --auth-card: 24rem;
    --auth-gap: 1.5rem;
    --auth-pad-x: clamp(1.5rem, 3vw, 3rem);
    --aside-w: calc(100vw - var(--auth-card) - var(--auth-gap) - 2 * var(--auth-pad-x));
    --aside-h: calc(100dvh - 4rem);
    grid-template-columns: var(--auth-card) auto;
    justify-content: center;
    column-gap: var(--auth-gap);
    padding: 2rem var(--auth-pad-x);
  }

  .has-aside .auth-shell { grid-row: 1; grid-column: 1; width: 100%; }

  .has-aside .compose-example {
    display: block;
    position: relative;
    grid-row: 1;
    grid-column: 2;
    max-width: var(--aside-w);
    font-size: max(var(--text-micro), min(0.82rem,
      calc(var(--aside-h) * 0.9 / (var(--lines) * var(--line))),
      calc(var(--aside-w) / (var(--cols) * 0.6))));
  }
}

.compose-example-text {
  margin: 0;
  overflow-x: auto;
  font-family: var(--font-mono);
  line-height: var(--line);
  white-space: pre;
  color: var(--etch);
  text-shadow:
    0 1px 0 color-mix(in srgb, #fff 5%, transparent),
    0 -1px 0 color-mix(in srgb, #000 55%, transparent);
  -webkit-mask-image: radial-gradient(ellipse 90% 95% at 50% 50%, #000 80%, transparent 100%);
          mask-image: radial-gradient(ellipse 90% 95% at 50% 50%, #000 80%, transparent 100%);
}

html[data-theme="light"] .compose-example-text {
  text-shadow:
    0 1px 0 color-mix(in srgb, #fff 90%, transparent),
    0 -1px 0 color-mix(in srgb, #000 12%, transparent);
}

.compose-example-text ::selection,
.compose-example-text::selection { background: var(--accent-soft); color: var(--text); }

.compose-example .y-comment { color: var(--y-comment); }
.compose-example .y-key { color: var(--y-key); }
.compose-example .y-value { color: var(--y-value); }
.compose-example .y-fill { color: var(--y-fill); }

/* In the file's top-right corner, clear of its first lines. */
.compose-example-copy {
  position: absolute;
  top: 0;
  right: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  background: color-mix(in srgb, var(--panel) 85%, transparent);
  color: var(--text);
  font: inherit;
  font-family: var(--font);
  font-size: var(--text-small);
  cursor: pointer;
}

.compose-example-copy:hover { border-color: var(--accent); }
.compose-example-copy svg { width: 0.9rem; height: 0.9rem; }
.compose-example.is-copied .compose-example-copy { border-color: var(--success); color: var(--success); }
.compose-example.is-copy-failed .compose-example-copy { border-color: var(--danger); color: var(--danger); }

.auth-passkey-button {
  width: 100%;
  justify-content: center;
  padding: 0.65rem 1rem;
  font-size: var(--text-medium);
}

.auth-passkey-button:disabled { cursor: progress; }

.auth-passkey-error {
  margin: 0.6rem 0 0;
  color: var(--danger);
  font-size: var(--text-normal);
}

.auth-alert,
.auth-notice {
  border-radius: var(--radius-control);
  padding: 0.6rem 0.75rem;
  font-size: var(--text-normal);
  margin-bottom: 1rem;
  line-height: 1.4;
}

.auth-alert {
  background: color-mix(in srgb, var(--danger) 14%, transparent);
  color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
}

.auth-notice {
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent-text);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
}

.rail-sign-out-form { margin: 0; }

.rail-sign-out {
  appearance: none;
  display: flex;
  align-items: center;
  gap: var(--rail-gap, 0.45rem);
  width: 100%;
  border: 0;
  background: transparent;
  color: var(--muted);
  border-radius: var(--radius-control);
  padding: 0.4rem var(--rail-pad-x, 0.45rem);
  font-family: inherit;
  font-size: 0.7rem;
  font-weight: 600;
  cursor: pointer;
  text-align: left;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.rail-sign-out:hover {
  color: var(--text);
  background: var(--panel-2);
}

.rail-sign-out-icon {
  width: var(--rail-lead, 17px);
  height: var(--rail-lead, 17px);
  box-sizing: border-box;
  padding: 3px;
  flex-shrink: 0;
  opacity: 0.9;
}

.form-input-sm {
  padding: 0.3rem 0.45rem;
  font-size: var(--text-caption);
  max-width: 11rem;
}

.access-link-copy label {
  color: var(--muted);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.access-link-dismiss {
  appearance: none;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
}

.access-link-dismiss:hover {
  border-color: var(--border);
  background: var(--panel-2);
  color: var(--text);
}

.access-link-content {
  display: grid;
  gap: var(--space-4);
  align-items: center;
  padding: var(--space-4);
}

.access-link-qr {
  position: relative;
  width: min(100%, 13rem);
  aspect-ratio: 1;
  justify-self: center;
  border-radius: var(--radius-panel);
  overflow: hidden;
  background: #fff;
}

.access-link-qr-svg {
  display: block;
  width: 100%;
  height: 100%;
}

.access-link-logo {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: 17%;
  aspect-ratio: 1;
  box-sizing: border-box;
  padding: 2.5%;
  border-radius: 22%;
  background: #fff;
  transform: translate(-50%, -50%);
}

.access-link-logo img {
  display: block;
  width: 100%;
  height: 100%;
}

.access-link-copy {
  min-width: 0;
  display: grid;
  gap: 0.55rem;
}

.access-link-copy p {
  margin: 0 0 0.2rem;
  color: var(--muted);
  font-size: var(--text-normal);
  line-height: 1.5;
}

.access-link-input-row {
  display: flex;
  align-items: stretch;
  gap: 0.45rem;
}

.access-link-input-row .form-input {
  min-width: 0;
  flex: 1;
  font-size: var(--text-small);
}

.access-link-export {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-top: 0.2rem;
}

.passkey-rename-form {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
}

.form-error {
  margin: 0.5rem 0 0;
  color: var(--danger);
  font-size: var(--text-normal);
}

@media (min-width: 700px) {
  .access-link-content {
    grid-template-columns: 13rem minmax(0, 1fr);
  }
}

.session-ua {
  display: inline;
  font-size: var(--text-control);
  overflow-wrap: anywhere;
  margin-right: 0.35rem;
}

.demo-banner {
  margin: 0 0 1rem;
  padding: 0.55rem 0.75rem;
  border-radius: var(--radius-control);
  font-size: var(--text-normal);
  line-height: 1.4;
  background: color-mix(in srgb, var(--warning) 12%, transparent);
  color: var(--warning);
  border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
}

/* Handle column wrapper (handle + optional Try me tip) */
.chrome-handle-wrap {
  position: relative;
  display: flex;
  flex-shrink: 0;
  align-self: stretch;
  height: 100%;
}

.chrome-handle-wrap .chrome-handle {
  display: flex;
  height: 100%;
}

/* Guest “Try me” tip — desktop only; position set fixed via list-chrome JS
   (absolute children are clipped by .unified-chrome overflow:hidden).
   No pill/chrome: bare text + arrow so ← clearly points at the handle. */
.filter-try-me {
  position: fixed;
  z-index: 60;
  pointer-events: auto;
}

.filter-try-me[hidden],
.filter-try-me:not(.is-visible) {
  display: none !important;
  pointer-events: none;
}

@media (max-width: 899px) {
  .filter-try-me {
    display: none !important;
  }
}

.filter-try-me-btn {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: var(--accent-text);
  font: inherit;
  cursor: pointer;
  white-space: nowrap;
  text-shadow: 0 1px 3px color-mix(in srgb, #000 50%, transparent);
  animation: filter-try-me-pulse 2.2s ease-in-out infinite;
}

.filter-try-me-btn:hover .filter-try-me-label,
.filter-try-me-btn:hover .filter-try-me-arrow {
  color: var(--accent);
}

.filter-try-me-arrow {
  flex-shrink: 0;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1;
  color: var(--accent-text);
}

.filter-try-me-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.05rem;
}

.filter-try-me-label {
  font-size: var(--text-small);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.filter-try-me-copy {
  font-size: var(--text-caption);
  font-weight: 500;
  color: var(--muted);
  text-shadow: 0 1px 3px color-mix(in srgb, #000 45%, transparent);
}

/* Nudge toward the handle (left) so the arrow feels aimed at it. */
@keyframes filter-try-me-pulse {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(-4px); }
}

.unified-chrome.filters-open .filter-try-me {
  display: none !important;
}

/* ── Settings skeleton ─────────────────────────
   Every settings page except Hub and the whitelist editor. Wide containers put
   each block's heading beside its grouped content; narrow ones put it above.
   Inputs, selects, switches and the compact action bar keep their own styles:
   rules here place them, never restyle them. */

.settings-page {
  --settings-pad: 1rem;
  --settings-head-w: 13.5rem;
  --settings-col-gap: 2.75rem;
  --settings-content-w: 46rem;
  --settings-hair: color-mix(in srgb, var(--border) 62%, transparent);
  --settings-inset: calc(var(--settings-pad) + 2rem + 0.85rem);
  /* Values, fields, selects and toggles all start at this column's edge. */
  --settings-value-w: 19rem;
  container: settings / inline-size;
}


.settings-block {
  display: grid;
  gap: 0.55rem;
  min-width: 0;
  margin-bottom: 0.5rem;
}
.settings-block-head {
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.55rem;
}
.settings-block-head h2 { font-family: var(--font-display); font-size: 1rem; font-weight: 600; letter-spacing: -0.005em; }
.settings-block-hint { color: var(--muted); font-size: var(--text-small); }
.settings-block-intro { flex-basis: 100%; margin-top: 0.2rem; color: var(--muted); font-size: var(--text-control); line-height: 1.5; max-width: 60ch; }
.settings-block-action { justify-self: start; margin: -0.25rem 0 0 -0.65rem; }
.settings-block-body { min-width: 0; display: grid; gap: 0.6rem; container: block / inline-size; }

@container settings (min-width: 760px) {
  .settings-block {
    grid-template-columns: var(--settings-head-w) minmax(0, var(--settings-content-w));
    grid-template-rows: auto 1fr;
    column-gap: var(--settings-col-gap);
    align-items: start;
    margin-bottom: 1.25rem;
  }
  .settings-block-head { grid-column: 1; grid-row: 1; display: grid; gap: 0.25rem; padding-top: 0.6rem; }
  .settings-block-intro { margin-top: 0.35rem; max-width: 34ch; }
  .settings-block-action { grid-column: 1; grid-row: 2; margin: 0.55rem 0 0 -0.65rem; }
  .settings-block-body { grid-column: 2; grid-row: 1 / span 2; }
  /* Page-level notes span the heading and content columns, ending where the groups end. */
  .settings-notice { max-width: calc(var(--settings-head-w) + var(--settings-col-gap) + var(--settings-content-w)); }
}

/* One spacing below a page-level note, whichever page it sits on. */
.settings-notice { margin-bottom: var(--space-4); }
.settings-notice > :is(.info-admonition, .warning-admonition) { margin-bottom: 0; }

.settings-group {
  position: relative;
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-dialog);
  box-shadow: var(--shadow-panel);
}

/* Read-only rows: label left, value right. */
.settings-block .settings-dl { display: grid; gap: 0; }
.settings-block .settings-dl-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--settings-value-w));
  column-gap: 1rem;
  align-items: center;
  min-height: 3rem;
  padding: 0.55rem var(--settings-pad);
}
.settings-block .settings-dl-row + .settings-dl-row { border-top: 1px solid var(--settings-hair); }
.settings-block .settings-dl dt {
  color: var(--text);
  font-size: var(--text-normal);
  font-weight: 500;
}
.settings-block .settings-dl dd {
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.55rem;
  color: color-mix(in srgb, var(--muted) 70%, var(--text));
  font-size: var(--text-normal);
  overflow-wrap: anywhere;
}
.settings-block .settings-dl dd.mono-soft { font-size: var(--text-control); }
.settings-block .connection-state { display: flex; align-items: center; gap: 0.3rem 0.6rem; }

/* Forms: label left, control right; one hairline between fields. */
.settings-form { min-width: 0; }
.settings-block .settings-form .form-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--settings-value-w));
  column-gap: 1rem;
  align-items: center;
  margin: 0;
  padding: 0.5rem var(--settings-pad);
  border-top: 1px solid var(--settings-hair);
}
.settings-block .settings-group > .settings-form:first-child > .form-row:first-of-type { border-top: 0; }
.settings-block .settings-form .form-row > label:not(.switch-row) { color: var(--text); font-size: var(--text-normal); font-weight: 500; }
/* A switch row reads like the others: its state on the left, the switch where
   every other control sits. Only the row's order changes, not the switch. */
.settings-block .settings-form .form-row:has(> .switch-row) { grid-template-columns: minmax(0, 1fr); padding-block: 0.7rem; }
.settings-block .settings-form .form-row > .switch-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--settings-value-w));
  column-gap: 1rem;
  align-items: center;
}
.settings-block .settings-form .form-row > .switch-row > .switch-label { grid-column: 1; grid-row: 1; }
.settings-block .settings-form .form-row > .switch-row > .switch { grid-column: 2; grid-row: 1; justify-self: start; }
/* Narrow fields start where the wide ones do. */
.settings-block .settings-form .form-row > .form-input-num { justify-self: start; }
.settings-block .settings-form .form-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.5rem;
  margin: 0;
  padding: 0.7rem var(--settings-pad);
  border-top: 1px solid var(--settings-hair);
}
.settings-actions-start { order: -1; margin-right: auto; }
.settings-block .settings-form .form-error { padding: 0 var(--settings-pad) 0.7rem; margin: 0; }

/* Empty, loading and unavailable states. */
.settings-block .settings-empty {
  display: grid;
  gap: 0.2rem;
  padding: 0.95rem var(--settings-pad);
  color: var(--muted);
  font-size: var(--text-normal);
}
.settings-block .settings-empty strong { color: var(--text); font-weight: 600; }

/* Lists: glyph, title + subtitle, trailing controls. Separators start at the
   text, as in grouped native lists. */
.settings-list { display: grid; min-width: 0; }
.settings-item {
  position: relative;
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr) auto;
  align-items: center;
  column-gap: 0.85rem;
  min-height: 3.5rem;
  padding: 0.6rem var(--settings-pad);
}
.settings-item + .settings-item::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--settings-inset);
  right: 0;
  border-top: 1px solid var(--settings-hair);
}
.settings-item-text { min-width: 0; display: grid; gap: 0.18rem; }
.settings-item-title { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; font-size: var(--text-normal); overflow-wrap: anywhere; }
.settings-item-title strong { font-weight: 600; }
.settings-item-meta { display: flex; flex-wrap: wrap; gap: 0.1rem 1rem; color: var(--text); font-size: var(--text-small); }
.settings-item-meta .status-note { white-space: normal; overflow-wrap: anywhere; }
.settings-item-trail { display: flex; align-items: center; justify-content: flex-end; gap: 0.5rem; }
.settings-k { color: var(--muted); }
.settings-kv { overflow-wrap: anywhere; }

.settings-glyph {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-surface);
  background: color-mix(in srgb, var(--text) 6%, transparent);
  color: var(--muted);
}
.settings-glyph svg { width: 1.05rem; height: 1.05rem; }
.settings-glyph--initial {
  border-radius: var(--radius-round);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-family: var(--font-display);
  font-size: 0.9rem;
  font-weight: 600;
}

/* Row menu: a disclosure of the row's actions. The controller picks the side
   with room and caps the height to it. */
.row-menu { position: relative; }
.row-menu > summary { list-style: none; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu-trigger {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-control);
  color: var(--muted);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.row-menu-trigger svg { width: 1.1rem; height: 1.1rem; }
.row-menu-trigger:hover,
.row-menu[open] > .row-menu-trigger { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }
.row-menu-trigger:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; }
.row-menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.3rem);
  z-index: 60;
  display: grid;
  gap: 0.1rem;
  min-width: 11.5rem;
  max-width: min(18rem, 100vw - 2rem);
  overflow: auto;
  padding: 0.3rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius-panel);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.04);
  animation: custom-select-in 120ms ease-out;
}
.row-menu.is-up > .row-menu-panel { top: auto; bottom: calc(100% + 0.3rem); }
html[data-theme="light"] .row-menu-panel { box-shadow: 0 18px 45px rgba(24, 32, 47, 0.16), 0 2px 8px rgba(24, 32, 47, 0.08); }
.row-menu-panel form { display: contents; }
.row-menu-item {
  display: flex;
  align-items: center;
  width: 100%;
  padding: 0.45rem 0.6rem;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: var(--text-caption);
  font-weight: 500;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
.row-menu-item:hover:not(:disabled) { background: var(--panel-2); }
.row-menu-item:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.row-menu-item:disabled { opacity: 0.48; cursor: not-allowed; }
.row-menu-item.is-danger { color: color-mix(in srgb, var(--danger) 88%, var(--text)); }
.row-menu-item.is-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 11%, transparent); color: var(--danger); }
.row-menu-separator { border: 0; border-top: 1px solid var(--border); margin: 0.2rem 0.15rem; }
@media (prefers-reduced-motion: reduce) { .row-menu-panel { animation: none; } }

/* General: the Appearance groups become rows; the bars themselves are untouched. */
.settings-block .settings-appearance { display: grid; gap: 0; padding: 0; }
.settings-block .settings-appearance-group {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--settings-value-w));
  align-items: center;
  column-gap: 1rem;
  min-height: 3rem;
  padding: 0.55rem var(--settings-pad);
}
.settings-block .settings-appearance-group + .settings-appearance-group { border-top: 1px solid var(--settings-hair); }
.settings-block .settings-appearance-heading {
  color: var(--text);
  font-size: var(--text-normal);
  font-weight: 500;
}

/* Users: captions once, the per-user form flattened into the row's columns. */
/* The two selects and the menu fill the shared value column exactly, so the
   first select starts where every other value and field does. Permission only
   ever reads View or Edit; Account keeps the room for Administrator. */
.settings-block .user-access-list .settings-item,
.user-access-captions {
  --user-access-permission-w: 6rem;
  --user-access-account-w: calc(var(--settings-value-w) - var(--user-access-permission-w) - 2rem - 2 * 0.85rem);
  grid-template-columns: 2rem minmax(0, 1fr) var(--user-access-account-w) var(--user-access-permission-w) 2rem;
}
.user-access-captions {
  display: grid;
  column-gap: 0.85rem;
  padding: 0.6rem var(--settings-pad) 0;
  color: var(--muted);
  font-size: var(--text-small);
}
.user-access-captions > :first-child { grid-column: 3; }
.settings-block .user-access-row { gap: 0 0.85rem; }
/* Only there to disable the whole form at once when it is read-only. */
.invite-fields { display: contents; }
.settings-block .user-access-row .user-access-form { display: contents; }
.settings-block .user-access-row .user-access-field { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.2rem; min-width: 0; }
.settings-block .user-access-row .user-access-field > label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Profile: the sign-out button sits on the heading's line. */
.settings-sign-out { display: flex; align-items: center; min-height: 2.6rem; }
@container settings (min-width: 760px) { .settings-sign-out { padding-top: 0.2rem; } }

/* The passkey-only form is an empty sibling that only ever shows its error. */
.settings-block .passkey-only-form .form-error { padding-top: 0.7rem; }

/* Devices: the user agent is long prose, so "this device" follows its last word
   instead of wrapping onto a line of its own. */
.settings-block .session-row .settings-item-title { display: block; line-height: 1.6; }
.settings-block .session-row .settings-item-title .badge { vertical-align: 0.05em; }
.settings-block .session-row .settings-item-text { gap: 0.6rem; }

/* Passkey rename opens under its own row. */
.settings-item > .passkey-rename-form { grid-column: 2 / -1; margin-top: 0.5rem; }
.settings-item > .passkey-rename-form[hidden] { display: none; }

/* Suppressions: rows without glyphs, so separators start at the padding. */
.settings-block.postoverflow-whitelists,
.settings-block .settings-allowlist { --settings-inset: var(--settings-pad); }
.settings-block .postoverflow-rule-list { display: grid; }
.settings-block .postoverflow-rule {
  grid-template-columns: minmax(0, 1fr) 1.25rem;
  column-gap: 0.85rem;
  padding: 0.75rem var(--settings-pad);
  border-bottom: 0;
}
.settings-block .postoverflow-rule + .postoverflow-rule::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--settings-inset);
  right: 0;
  border-top: 1px solid var(--settings-hair);
}
.settings-block .postoverflow-rule:first-child { border-radius: var(--radius-dialog) var(--radius-dialog) 0 0; }
.settings-block .postoverflow-rule:last-child { border-radius: 0 0 var(--radius-dialog) var(--radius-dialog); }
.settings-block .postoverflow-rule:only-child { border-radius: var(--radius-dialog); }
.settings-block .postoverflow-rule-chevron { align-self: center; margin-top: 0; }
.settings-block .postoverflow-rule-facts { margin-top: 0.5rem; gap: 0.3rem 0.75rem; }
.settings-block .postoverflow-rule-scenario { font-size: var(--text-x-small); }

.settings-allowlist-stack { display: grid; gap: 0.65rem; }
.settings-block .settings-allowlist-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; min-height: 3.4rem; }
.settings-block .settings-allowlist-head .cell-primary { font: 600 var(--text-normal) / 1.35 var(--font); letter-spacing: normal; color: var(--text); overflow-wrap: anywhere; }
.settings-block .settings-allowlist-head .cell-secondary { font-size: var(--text-small); }
.settings-block .settings-allowlist-meta { margin: 0; color: var(--muted); font-size: var(--text-small); white-space: nowrap; }
.settings-block .settings-allowlist-items {
  list-style: none;
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0.2rem 0;
  border-top: 1px solid var(--settings-hair);
}
.settings-block .settings-allowlist-items li {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.9rem;
  padding: 0.5rem var(--settings-pad) 0.5rem var(--settings-inset);
  font-size: var(--text-control);
}
.settings-block .settings-allowlist-items li + li::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--settings-inset);
  right: 0;
  border-top: 1px solid var(--settings-hair);
}
.settings-block .settings-allowlist-items .cell-secondary { display: inline; font-size: var(--text-small); }
.settings-block .settings-allowlist-items .status-note { margin-left: auto; font-size: var(--text-small); }
.settings-block .settings-allowlist-empty {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-compact);
  padding: 0.6rem var(--settings-pad) 0.7rem var(--settings-inset);
  border-top: 1px solid var(--settings-hair);
}

/* Issued access link */
.settings-block .access-link-content { padding: 1rem var(--settings-pad); }
.settings-block .access-link-dismiss { position: absolute; top: 0.6rem; right: 0.6rem; }
.settings-block.access-link-panel .settings-group { border-color: color-mix(in srgb, var(--success) 45%, var(--border)); }
.settings-block .access-link-copy > p { padding-right: 1.75rem; }

/* Narrow blocks */
@container block (max-width: 559px) {
  .settings-block .settings-dl-row { grid-template-columns: max-content minmax(0, 1fr); min-height: 2.9rem; }
  .settings-block .settings-dl dd { justify-content: flex-end; text-align: right; }
  .settings-block .settings-form .form-row > .switch-row { display: flex; flex-direction: row-reverse; justify-content: space-between; }
  .settings-block .settings-form .form-row { grid-template-columns: minmax(0, 1fr); row-gap: 0.35rem; padding-block: 0.6rem; }
  .settings-block .settings-form .form-actions > * { flex: 1 1 auto; }
  .settings-actions-start { margin-right: 0; order: 2; }
  .settings-block .settings-appearance-group { grid-template-columns: minmax(0, 1fr); row-gap: 0.45rem; padding-block: 0.7rem; }
  .user-access-captions { display: none; }
  .settings-block .user-access-list .settings-item { grid-template-columns: 2rem minmax(0, 1fr) minmax(0, 1fr) 2rem; row-gap: 0.55rem; }
  .settings-block .user-access-row .settings-item-text { grid-column: 2 / 4; }
  .settings-block .user-access-row .row-menu { grid-column: 4; grid-row: 1; }
  .settings-block .user-access-row .user-access-field { grid-row: 2; }
  .settings-block .user-access-row .user-access-field:nth-of-type(1) { grid-column: 2; }
  .settings-block .user-access-row .user-access-field:nth-of-type(2) { grid-column: 3; }
  .settings-block .user-access-row .user-access-field > label {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
    color: var(--muted);
    font-size: var(--text-small);
    font-weight: 500;
  }
  .settings-block .settings-allowlist-head .settings-item-trail { grid-column: 1 / -1; justify-content: space-between; margin-top: 0.3rem; }
  .settings-block .settings-allowlist-items .status-note { margin-left: 0; flex-basis: 100%; }
  .settings-block .postoverflow-rule-facts { grid-template-columns: 2.8rem minmax(0, 1fr); }
}
