:root {
  /* Tell the browser this is a dark app so native UI — the date-picker calendar
     popup, scrollbars, form-control internals — renders dark, and the date input's
     calendar icon is drawn light (visible) instead of dark-on-dark. */
  color-scheme: dark;
  --bg: #0f1117;
  --panel: #171a23;
  --panel-2: #1d212c;
  --border: #2a2f3c;
  --text: #e2e4e9;
  --muted: #8b93a7;
  --accent: #38bdac;
  --accent-2: #5eead4;
  --danger: #f87171;
  --warn: #fbbf24;
  --info: #60a5fa;

  /* Text/background pairs the rules below used to spell as literal hex. Tokens so
     the light palette can restate them — a literal is a colour the theme cannot
     reach, which is how a pale-pink error line ends up on a white page. */
  --on-accent: #06231f;
  --danger-fg: #fca5a5;
  --warn-fg: #fcd34d;
  --info-fg: #93c5fd;
  --accent-soft: rgba(56, 189, 172, 0.18);
  --danger-soft: rgba(248, 113, 113, 0.18);
  --overlay: rgba(0, 0, 0, 0.55);
  --shadow: rgba(0, 0, 0, 0.4);

  /* Severity palette — ONE definition per band, referenced by all three rule
     families below (`.sev-*` badges, `.chart .seg-*` bar fills, `.chart-swatch.seg-*`
     legend squares). The three families used to carry their own copies of these
     hex values, which is how the legend swatches for Security and Recommended went
     missing entirely (their bar fills existed, but `.chart .seg-*` sets `fill` and
     is scoped to `.chart`, so it does nothing for a legend `<span>`).

     `-fg` is the badge's text tint; the badge background is derived from the solid
     color at 16-18% so a new band needs two values, not six.

     Adding a band means: a `--sev-x` / `--sev-x-fg` pair here, plus one line in
     each of the three families. `severity_css_defines_every_band` (util.rs) reads
     this file and fails if any of the four is missing. */
  --sev-critical: #f87171;
  --sev-critical-fg: #fca5a5;
  --sev-important: #fb923c;
  --sev-important-fg: #fdba74;
  --sev-security: #e879f9;
  --sev-security-fg: #f0abfc;
  --sev-moderate: #fbbf24;
  --sev-moderate-fg: #fcd34d;
  --sev-recommended: #22d3ee;
  --sev-recommended-fg: #67e8f9;
  --sev-low: #60a5fa;
  --sev-low-fg: #93c5fd;
  --sev-optional: #94a3b8;
  --sev-optional-fg: #cbd5e1;
  --sev-unknown: #6b7280;
  --sev-unknown-fg: #9ca3af;
}

/* Light palette. The dark `:root` above stays the fallback (and what a System
   choice shows on a dark or unspecified OS); this restates EVERY token, so no
   dark-tuned value leaks onto a white page. It appears twice because CSS has no
   way to share a declaration block between a media query and an attribute
   selector: once for System on a light OS, once for an explicit Light choice.
   `the_light_palette_overrides_every_root_token` (util/theme.rs) fails if either
   copy misses a token.

   Severity bands are darker here, not the dark palette's pastels: the solid colour
   fills chart bars on white, and `-fg` is badge text on a 16-20% tint of it, so both
   need contrast against a light background. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --bg: #f4f6f9;
    --panel: #ffffff;
    --panel-2: #eef1f5;
    --border: #d3d9e2;
    --text: #1b1f2a;
    --muted: #535c6e;
    --accent: #0b7a6f;
    --accent-2: #0a6960;
    --danger: #dc2626;
    --warn: #b45309;
    --info: #2563eb;
    --on-accent: #ffffff;
    --danger-fg: #b91c1c;
    --warn-fg: #92400e;
    --info-fg: #1d4ed8;
    --accent-soft: rgba(11, 122, 111, 0.12);
    --danger-soft: rgba(220, 38, 38, 0.1);
    --overlay: rgba(15, 23, 42, 0.45);
    --shadow: rgba(15, 23, 42, 0.16);
    --sev-critical: #dc2626;
    --sev-critical-fg: #991b1b;
    --sev-important: #ea580c;
    --sev-important-fg: #9a3412;
    --sev-security: #c026d3;
    --sev-security-fg: #86198f;
    --sev-moderate: #a16207;
    --sev-moderate-fg: #854d0e;
    --sev-recommended: #0891b2;
    --sev-recommended-fg: #155e75;
    --sev-low: #2563eb;
    --sev-low-fg: #1e40af;
    --sev-optional: #64748b;
    --sev-optional-fg: #334155;
    --sev-unknown: #6b7280;
    --sev-unknown-fg: #4b5563;
  }
}

:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f4f6f9;
  --panel: #ffffff;
  --panel-2: #eef1f5;
  --border: #d3d9e2;
  --text: #1b1f2a;
  --muted: #535c6e;
  --accent: #0b7a6f;
  --accent-2: #0a6960;
  --danger: #dc2626;
  --warn: #b45309;
  --info: #2563eb;
  --on-accent: #ffffff;
  --danger-fg: #b91c1c;
  --warn-fg: #92400e;
  --info-fg: #1d4ed8;
  --accent-soft: rgba(11, 122, 111, 0.12);
  --danger-soft: rgba(220, 38, 38, 0.1);
  --overlay: rgba(15, 23, 42, 0.45);
  --shadow: rgba(15, 23, 42, 0.16);
  --sev-critical: #dc2626;
  --sev-critical-fg: #991b1b;
  --sev-important: #ea580c;
  --sev-important-fg: #9a3412;
  --sev-security: #c026d3;
  --sev-security-fg: #86198f;
  --sev-moderate: #a16207;
  --sev-moderate-fg: #854d0e;
  --sev-recommended: #0891b2;
  --sev-recommended-fg: #155e75;
  --sev-low: #2563eb;
  --sev-low-fg: #1e40af;
  --sev-optional: #64748b;
  --sev-optional-fg: #334155;
  --sev-unknown: #6b7280;
  --sev-unknown-fg: #4b5563;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 14px;
}

main {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 14px;
  min-height: 100vh;
}

h1 {
  font-size: 18px;
  margin: 0;
}

h2 {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin: 0 0 10px;
}

.topbar {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 8px 14px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
}

.brand h1 {
  font-size: 16px;
  white-space: nowrap;
}

.logo {
  color: var(--accent);
  font-size: 22px;
}

.subtitle {
  margin: 1px 0 0;
  color: var(--muted);
  font-size: 12px;
}

.subtitle:empty {
  display: none;
}

/* Run query, the data's age, Refresh and the auto-refresh cadence: the controls
   used on every visit, in the bar rather than a panel of their own. */
.run-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 10px;
}

.run-status {
  color: var(--muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.run-status:empty {
  display: none;
}

/* A one-glyph button (↻), square so it does not read as a text label. */
.btn-icon {
  padding: 5px 10px;
  font-size: 16px;
  line-height: 1;
}

/* The running query's progress along the bar's bottom edge. */
.topbar-progress {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 0;
  height: 3px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--panel-2);
}

.actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.account {
  color: var(--accent-2);
}

.pill {
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
}

.pill-on {
  color: var(--accent-2);
  border-color: var(--accent);
}

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

.pill-demo {
  color: var(--warn);
  border-color: var(--warn);
}

/* Sample-data notice shown under the header in demo / web mode. */
.demo-banner {
  margin: 0;
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--warn);
  border-radius: 10px;
  color: var(--warn);
  font-size: 13px;
}

.panel {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}

label {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 12px;
  color: var(--muted);
}

label.inline {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

/* Inline validation beside a control (e.g. the custom install range). */
.field-hint {
  font-size: 12px;
  color: var(--warn);
}

input,
select {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 8px 10px;
  font-size: 13px;
}

/* Text fields show focus through their border, which is why the default ring is
   dropped for them only. The blanket `outline: none` this replaces also hid focus
   on every checkbox — the row selectors, the facet chips, the group headers — so a
   keyboard user could not see which one Space would tick. */
input:not([type="checkbox"]):not([type="radio"]):focus,
select:focus,
textarea:focus {
  border-color: var(--accent);
  outline: none;
}

/* One visible ring for everything reached by keyboard. `:focus-visible` keeps it
   off for mouse clicks, so the ring is never noise. */
button:focus-visible,
a:focus-visible,
summary:focus-visible,
select:focus-visible,
input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible,
[role="tab"]:focus-visible,
[role="tabpanel"]:focus-visible {
  outline: 2px solid var(--accent-2);
  outline-offset: 2px;
}

input.narrow {
  width: 80px;
}

/* Date inputs: keep the (now light, via color-scheme) calendar icon clearly
   visible and clickable. */
input[type="date"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.9;
}

input[type="date"]::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}

select:disabled {
  opacity: 0.5;
}

.chips,
.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.chips,
.row {
  margin-top: 12px;
}



.chips-label {
  font-size: 12px;
  color: var(--muted);
  margin-right: 2px;
}

.chip {
  flex-direction: row;
  align-items: center;
  gap: 6px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 5px 10px;
  color: var(--text);
  cursor: pointer;
}

.chip input {
  margin: 0;
}

.btn {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  padding: 8px 14px;
  font-size: 13px;
  cursor: pointer;
}

.btn:hover {
  border-color: var(--accent);
}

.btn:disabled {
  opacity: 0.5;
  cursor: default;
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}

.btn-ghost {
  background: transparent;
}

.link {
  background: none;
  border: none;
  color: var(--accent-2);
  cursor: pointer;
  padding: 4px 6px;
  font-size: 13px;
}

.x {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  padding: 2px 6px;
}

/* Sortable Patches-table column headers — a button styled as the header text. */
.th-sort {
  background: none;
  border: none;
  padding: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}

.th-sort:hover {
  color: var(--text);
}

/* Two-click confirm: the first click "arms" a destructive control, the second
   fires it (mouseleave/blur disarm). Reuses the danger palette as a warning. */
.x-armed {
  background: var(--danger-soft);
  border-radius: 6px;
  color: var(--danger-fg);
  font-size: 12px;
  font-weight: 600;
}

.btn-armed {
  border-color: var(--danger);
  color: var(--danger-fg);
}

.seg {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--muted);
  padding: 6px 14px;
  cursor: pointer;
}

.seg-on {
  background: var(--accent);
  color: var(--on-accent);
  border-color: var(--accent);
  font-weight: 600;
}

.tabs {
  display: flex;
  /* The row's min content width (two labelled tab groups + summary) exceeds a
     phone viewport; without wrapping it overflows the panel's right edge. */
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 8px;
  padding-bottom: 6px;
}

.tab {
  background: none;
  border: none;
  color: var(--muted);
  padding: 5px 10px;
  cursor: pointer;
  border-radius: 8px;
}

.tab-on {
  background: var(--panel-2);
  color: var(--text);
}

.result-summary {
  margin-left: auto;
  color: var(--muted);
  font-size: 12px;
  cursor: help;
}

/* The results panel's own padding, tighter than a settings-style panel's. */
.panel.results {
  padding: 10px 14px;
}

/* Tab bar grouped by scope tier (Filtered results | Fleet health). */
.tab-group {
  display: flex;
  align-items: center;
  gap: 6px;
}

.tab-group-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-right: 2px;
}

.tab-list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.tab-divider {
  width: 1px;
  align-self: stretch;
  background: var(--border);
  margin: 0 6px;
}

.table-wrap {
  overflow: auto;
  max-height: 56vh;
  border: 1px solid var(--border);
  border-radius: 10px;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}

thead th {
  position: sticky;
  top: 0;
  background: var(--panel-2);
  text-align: left;
  padding: 9px 10px;
  color: var(--muted);
  font-weight: 600;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

tbody td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}

tbody tr:hover {
  background: var(--panel-2);
}

.patch-name {
  white-space: normal;
  min-width: 220px;
  max-width: 420px;
}

/* At most two lines, the rest behind an ellipsis (the full text is the title).
   On an inner span: `-webkit-box` on the cell itself would drop its table-cell
   layout. */
.clamp-2 {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.empty,
.note {
  color: var(--muted);
  padding: 14px 4px;
}

.note {
  color: var(--warn);
}

.sev,
.stat {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 11.5px;
  font-weight: 600;
}

.sev-critical {
  background: color-mix(in srgb, var(--sev-critical) 18%, transparent);
  color: var(--sev-critical-fg);
}

.sev-important {
  background: color-mix(in srgb, var(--sev-important) 18%, transparent);
  color: var(--sev-important-fg);
}

.sev-security {
  background: color-mix(in srgb, var(--sev-security) 16%, transparent);
  color: var(--sev-security-fg);
}

.sev-moderate {
  background: color-mix(in srgb, var(--sev-moderate) 16%, transparent);
  color: var(--sev-moderate-fg);
}

.sev-recommended {
  background: color-mix(in srgb, var(--sev-recommended) 16%, transparent);
  color: var(--sev-recommended-fg);
}

.sev-low {
  background: color-mix(in srgb, var(--sev-low) 16%, transparent);
  color: var(--sev-low-fg);
}

/* Optional is a real NinjaOne severity and Unknown is one it sent that we couldn't
   map — both used to fall through to `.sev-none`, rendering "low priority" and
   "unidentified" identically in the Patches table. */
.sev-optional {
  background: color-mix(in srgb, var(--sev-optional) 16%, transparent);
  color: var(--sev-optional-fg);
}

.sev-unknown {
  background: color-mix(in srgb, var(--sev-unknown) 20%, transparent);
  color: var(--sev-unknown-fg);
  font-style: italic;
}

.sev-none {
  background: var(--panel-2);
  color: var(--muted);
}

.stat-installed {
  background: var(--accent-soft);
  color: var(--accent-2);
}

.stat-approved {
  background: color-mix(in srgb, var(--info) 16%, transparent);
  color: var(--info-fg);
}

.stat-pending {
  background: color-mix(in srgb, var(--warn) 16%, transparent);
  color: var(--warn-fg);
}

.stat-rejected {
  background: var(--panel-2);
  color: var(--muted);
}

.stat-failed {
  background: var(--danger-soft);
  color: var(--danger-fg);
}

/* The two live regions hold only fixed-position toasts. Fixed themselves, they
   leave the page's flex column, whose gap they used to widen while empty. */
.toaster {
  position: fixed;
}

.toast {
  position: fixed;
  bottom: 18px;
  right: 18px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--panel);
  box-shadow: 0 8px 24px var(--shadow);
  max-width: 480px;
}

.toast-ok {
  border-color: var(--accent);
}

.toast-err {
  border-color: var(--danger);
  color: var(--danger-fg);
}

/* Persistent record of the last failed query in the results area — same danger
   palette as .toast-err, but it stays until the next success or a dismiss. */
.error-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  padding: 8px 12px;
  border: 1px solid var(--danger);
  border-radius: 8px;
  background: color-mix(in srgb, var(--danger) 10%, transparent);
  color: var(--danger-fg);
  font-size: 13px;
}

.error-banner .x {
  margin-left: auto;
}

/* --- Running-query progress --- */
.progress-bar {
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.3s ease;
}

.progress-indeterminate {
  width: 35%;
  animation: progress-slide 1.1s ease-in-out infinite;
}

@keyframes progress-slide {
  0% {
    margin-left: -35%;
  }
  100% {
    margin-left: 100%;
  }
}

/* --- Patches table pagination --- */
.pager {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.pager-info {
  color: var(--muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

/* --- Update splash modal --- */
.modal-overlay {
  position: fixed;
  inset: 0;
  background: var(--overlay);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 20px;
}

.modal {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 20px 22px;
  width: min(560px, 100%);
  max-height: 80vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px var(--shadow);
}

/* The container is focused programmatically on open (see app/modal.rs) so the
   first Tab starts inside the dialog; the ring belongs on the controls, not on
   the panel. */
.modal:focus {
  outline: none;
}

.modal h2 {
  margin: 0 0 4px;
  font-size: 18px;
  /* A dialog's title is a sentence or a name ("SEA-DC01", "Reboot on 3
     devices"), not a section label: not the small-caps style h2 has elsewhere. */
  text-transform: none;
  letter-spacing: 0;
  color: var(--text);
}

.modal-sub {
  margin: 0 0 14px;
  color: var(--muted);
  font-size: 13px;
}

.changelog {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
  padding: 12px 14px;
  margin-bottom: 16px;
}

.changelog h3 {
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.changelog-body {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
  max-height: 40vh;
  overflow-y: auto;
}

.changelog-body h4 {
  margin: 12px 0 4px;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.changelog-body ul {
  margin: 0;
  padding-left: 18px;
}

.changelog-body li {
  margin: 0 0 4px;
}

.changelog-body p {
  margin: 0 0 8px;
}

.changelog-body strong {
  font-weight: 600;
  color: var(--text);
}

.changelog-body > :first-child {
  margin-top: 0;
}

.changelog-body > :last-child {
  margin-bottom: 0;
}

.app-version {
  margin-top: 16px;
  font-size: 11px;
  color: var(--muted);
}

/* Failures: the full affected-device list can be long — keep the cell readable. */
.device-list {
  max-width: 380px;
  font-size: 0.85rem;
  color: var(--muted);
}

/* --- Dashboard charts (inline SVG) --- */
.charts {
  display: grid;
  /* Severity and age side by side on a wide window, each its own height. */
  grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
  align-items: start;
  gap: 16px;
  margin-bottom: 16px;
}

.chart-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
  padding: 14px 16px;
}

.chart-title {
  margin: 0 0 12px;
  font-size: 13px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* "Compliance by OS" section — divided from the per-org compliance above it. */
.compliance-os {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.compliance-os .chart-card {
  margin-bottom: 12px;
}

.chart {
  max-width: 100%;
  height: auto;
}

.chart-lbl {
  fill: var(--muted);
  font-size: 12px;
}

.chart-val {
  fill: var(--text);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.chart-track {
  fill: var(--border);
}

/* The Within SLA % cell's bar, by health band: the bar chart of the same
   percentages that sat above each compliance table, drawn in the cell instead. */
/* The age histogram's bars: one colour, the accent. Age is a distribution, not a
   health band, so it does not borrow the Within SLA band colours. */
.chart .age-bar {
  fill: var(--accent);
}

.pct-cell {
  white-space: nowrap;
}

.pct-bar {
  display: inline-block;
  width: 64px;
  height: 8px;
  margin-right: 8px;
  vertical-align: middle;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}

.pct-bar__fill {
  display: block;
  height: 100%;
}

.pct-bar__fill.bar-good {
  background: var(--accent);
}

.pct-bar__fill.bar-warn {
  background: var(--warn);
}

.pct-bar__fill.bar-bad {
  background: var(--danger);
}

/* The Compliance tab's section links. */
.section-jumps {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 4px 2px 14px;
  font-size: 12.5px;
}

.compliance-section,
.compliance-os,
.compliance-approvals {
  scroll-margin-top: 8px;
}

/* The same bands as legend squares and as the Within SLA headline figure. */
.chart-swatch.bar-good {
  background: var(--accent);
}

.chart-swatch.bar-warn {
  background: var(--warn);
}

.chart-swatch.bar-bad {
  background: var(--danger);
}

.kpi-value.bar-good {
  color: var(--accent);
}

.kpi-value.bar-warn {
  color: var(--warn);
}

.kpi-value.bar-bad,
.kpi-value.kpi-alert {
  color: var(--danger);
}

/* Severity segment fills (stacked bar) — solid variants of the .sev-* badges,
   from the same custom properties so the two can no longer disagree. */
.chart .seg-critical {
  fill: var(--sev-critical);
}

.chart .seg-important {
  fill: var(--sev-important);
}

.chart .seg-security {
  fill: var(--sev-security);
}

.chart .seg-moderate {
  fill: var(--sev-moderate);
}

.chart .seg-recommended {
  fill: var(--sev-recommended);
}

.chart .seg-low {
  fill: var(--sev-low);
}

.chart .seg-optional {
  fill: var(--sev-optional);
}

.chart .seg-unknown {
  fill: var(--sev-unknown);
}

.chart-legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: 10px 0 0;
  margin: 0;
  font-size: 12px;
  color: var(--muted);
}

.chart-legend li {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* A device's pending backlog inside one table cell. */
.chart-legend.breakdown {
  padding: 0;
  gap: 4px 10px;
  color: inherit;
}

/* Drill-down affordance on a rollup value: reads as the data it replaces until
   hovered/focused, so the tables stay scannable rather than turning into a wall of
   links. A real <button> keeps it keyboard-reachable and announced. */
.drill {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  border-bottom: 1px dotted var(--muted);
}

.drill:hover,
.drill:focus-visible {
  color: var(--accent-2);
  border-bottom-color: var(--accent-2);
}

.drill-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  border-bottom: none;
}

.drill-legend:hover,
.drill-legend:focus-visible {
  border-bottom: none;
  text-decoration: underline;
}

.chart-swatch {
  width: 12px;
  height: 12px;
  border-radius: 2px;
  display: inline-block;
}

/* Legend squares. A separate family from `.chart .seg-*` because those set `fill`
   and are scoped to `.chart`, which does nothing to a legend `<span>` — Security and
   Recommended once had bar fills but no swatch, painting a transparent hole next to
   their counts. On third-party patches those are the *common* bands. */
.chart-swatch.seg-critical {
  background: var(--sev-critical);
}

.chart-swatch.seg-important {
  background: var(--sev-important);
}

.chart-swatch.seg-security {
  background: var(--sev-security);
}

.chart-swatch.seg-moderate {
  background: var(--sev-moderate);
}

.chart-swatch.seg-recommended {
  background: var(--sev-recommended);
}

.chart-swatch.seg-low {
  background: var(--sev-low);
}

.chart-swatch.seg-optional {
  background: var(--sev-optional);
}

.chart-swatch.seg-unknown {
  background: var(--sev-unknown);
}

/* --- Mobile / narrow viewports --- */
@media (max-width: 640px) {
  main {
    padding: 12px;
    gap: 12px;
  }

  .panel {
    padding: 12px 13px;
  }

  /* The results summary takes its own full line under the wrapped tab groups
     instead of squeezing beside them (margin-left:auto only suits one row). */
  .result-summary {
    flex-basis: 100%;
    margin-left: 0;
  }
}

/* --- Filters (filters.rs): the scope bar and the patch filter bar --------- */

/* One row of compact pickers under the top bar. Never `overflow-x: auto`: a
   scroll container would clip the pickers' drop-down panels. */
.scope-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
}

.scope-bar__os-name {
  width: 170px;
  padding: 6px 10px;
}

/* At the top of the Patches and Failures tabs, the only ones its filters reach. */
.patch-filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.patch-filter-bar__search {
  width: 200px;
  padding: 6px 10px;
}

.patch-filter-bar select,
.patch-filter-bar input[type="date"] {
  padding: 5px 8px;
}

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

.seg-group__label {
  font-size: 12px;
  color: var(--muted);
  margin-right: 2px;
}

.seg-group .seg {
  padding: 5px 10px;
}

/* The controls no longer match the results on screen; a click runs them. */
.filters-changed {
  margin-left: auto;
  padding: 5px 12px;
  background: var(--panel-2);
  border: 1px solid var(--warn);
  border-radius: 999px;
  color: var(--warn);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

.filters-changed:hover {
  background: var(--accent-soft);
}

/* A multi-select facet: one compact button naming the facet and its value. */
.picker {
  position: relative;
}

.picker__button {
  display: flex;
  align-items: center;
  gap: 6px;
  max-width: 260px;
  padding: 6px 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
  text-align: left;
}

.picker__button:hover:not(:disabled) {
  border-color: var(--accent);
}

/* A narrowed facet stands out from the "All" ones beside it. */
.picker__button--set {
  border-color: var(--accent-2);
}

.picker__button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.picker__label {
  color: var(--muted);
  white-space: nowrap;
}

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

.picker__caret {
  color: var(--muted);
  flex: none;
  font-size: 11px;
}

/* Above the sticky action bar (5) and table headers. */
.picker__panel {
  position: absolute;
  z-index: 30;
  top: 100%;
  left: 0;
  width: max-content;
  min-width: 220px;
  max-width: 360px;
  margin-top: 4px;
  padding: 8px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px var(--shadow);
}

.picker__tools {
  display: flex;
  gap: 6px;
  margin-bottom: 8px;
}

.picker__search {
  flex: 1;
  min-width: 0;
}

/* Bounded so a tenant with hundreds of organizations scrolls the list rather than
   the page. */
.picker__list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 260px;
  overflow-y: auto;
}

.picker__option {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  padding: 5px 6px;
  border-radius: 6px;
  color: var(--text);
  font-size: 13px;
  cursor: pointer;
}

.picker__option:hover {
  background: var(--panel-2);
}

.picker__option input {
  margin: 0;
}

.picker__empty {
  margin: 4px 2px;
  font-size: 12px;
  color: var(--muted);
}

/* The presets menu: a list of saved filters over a Save row. */
.presets {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.preset {
  display: flex;
  align-items: center;
}

.preset .menu__item {
  flex: 1;
}

.presets-save {
  display: flex;
  gap: 6px;
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

.preset-name {
  flex: 1;
  min-width: 0;
}

/* Read by assistive tech, not drawn. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Menus (app/menu.rs) ------------------------------------------------- */

.menu {
  position: relative;
}

/* Above the sticky action bar (5) and table headers, which it drops over. */
.menu__panel {
  position: absolute;
  z-index: 30;
  top: 100%;
  left: 0;
  min-width: 200px;
  margin-top: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px var(--shadow);
}

.menu__panel--right {
  left: auto;
  right: 0;
}

/* A popover's panel stays mounted while closed; `hidden` must beat its flex. */
.menu__panel[hidden] {
  display: none;
}

.menu__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 7px 10px;
  background: none;
  border: none;
  border-radius: 6px;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.menu__item:hover:not(:disabled) {
  background: var(--panel-2);
}

.menu__item:disabled {
  opacity: 0.5;
  cursor: default;
}

.menu__note {
  margin: 2px 10px 4px;
  font-size: 12px;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.menu__group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px 10px 8px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 2px;
}

.menu__heading {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.menu__segs {
  display: flex;
  gap: 4px;
}

/* --- Notices under the top bar (a copied view link, a pending view) --------- */

.notice-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
}

/* --- Dialog chrome shared by Settings and the drill-down -------------------- */

.modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}

.modal.settings {
  max-height: 88vh;
  padding-bottom: 0;
}

.settings-section {
  margin: 8px 0 10px;
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Save stays in reach however far down the form the operator scrolled. */
.settings-footer {
  position: sticky;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 16px -22px 0;
  padding: 12px 22px;
  background: var(--panel);
  border-top: 1px solid var(--border);
}

.settings-footer .app-version {
  margin: 0 0 0 auto;
}

/* --- First run: what to do before there is anything to show ----------------- */

.onboarding {
  margin-bottom: 12px;
  padding: 14px 16px;
  border: 1px solid var(--accent);
  border-radius: 10px;
  background: var(--panel-2);
}

.onboarding h2 {
  margin: 0 0 6px;
  color: var(--text);
  text-transform: none;
  letter-spacing: 0;
  font-size: 15px;
}

.onboarding p {
  margin: 0 0 12px;
  color: var(--muted);
}

/* --- App shell: the results fill the window ------------------------------- */

/* The bars keep their height; the results panel takes the rest of the window and
   its table scrolls inside it, under a sticky header. The page itself scrolls
   only when the window is too short for the bars plus a usable results floor.
   Phones keep the plain document flow. */
@media (min-width: 641px) {
  main.shell {
    height: 100vh;
  }

  .results {
    flex: 1 1 auto;
    min-height: 320px;
    display: flex;
    flex-direction: column;
  }

  .results > * {
    flex: none;
  }

  /* Never `overflow: hidden` here: it would clip the popovers inside the tab. */
  .results > #results-tabpanel {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    display: flex;
    flex-direction: column;
  }

  #results-tabpanel > * {
    flex: none;
  }

  /* Natural height up to the space left, then it scrolls inside; the floor keeps
     a few rows visible when the banners above it are tall. */
  #results-tabpanel > .table-wrap--fill,
  #results-tabpanel > .groups {
    flex: 0 1 auto;
    min-height: 160px;
    max-height: none;
  }

  #results-tabpanel > .groups {
    overflow: auto;
  }
}

/* --- Device actions ------------------------------------------------------- */

/* One row whatever is selected. Sticky so the running selection total and the
   action buttons stay reachable while a grouped view scrolls the tab. */
.action-bar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 8px;
  padding: 6px 10px;
  margin-bottom: 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.action-bar-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 200px;
  font-size: 13px;
}

.action-bar-hint {
  color: var(--muted);
}

/* Each group is one mechanism, labelled. "Apply all approved" and "Apply
   selected" are different endpoints with different blast radii, and the label
   before the pair is what distinguishes them — the buttons themselves ("All OS",
   "Selected OS", …) are too terse to carry that alone. */
.action-group {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 4px 3px 8px;
  border: 1px solid var(--border);
  border-radius: 6px;
}

.action-group-label {
  margin-right: 2px;
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

/* Ticked OS rows "Selected OS" cannot send; the note is the tooltip. */
.action-group-warn {
  color: var(--warn);
  font-size: 12px;
  cursor: help;
}

/* The Options button while a script would run for real. */
.options-live {
  border-color: var(--warn);
  color: var(--warn);
}

/* The run options and the reboot's mode and reason, behind their buttons. */
.popover__panel {
  min-width: 320px;
  max-width: min(560px, 90vw);
  max-height: 60vh;
  overflow-y: auto;
  gap: 10px;
  padding: 10px 12px;
}

.reboot-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 12px;
  color: var(--muted);
}

.reboot-options label {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.reboot-options .btn-primary {
  align-self: flex-start;
}

/* `.action-bar-reason`'s flex basis is a width in the bar's row; in this column
   it would be a 240px-tall gap. */
.reboot-options .action-bar-reason {
  flex: none;
}

.popover__panel .action-bar-options {
  min-width: 400px;
}

.script-dialog .script-picker {
  margin: 0;
}

/* One row per scope. Each carries a label saying which actions it reaches, because
   "Dry run" next to a native Apply reads as protection that endpoint cannot give. */
.action-bar-options {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  flex: 1 1 100%;
  font-size: 12px;
  color: var(--muted);
}

.action-bar-options label {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.action-options-label {
  flex: 1 1 100%;
  font-size: 11px;
  opacity: 0.85;
}

.action-bar-reason {
  flex: 1 1 240px;
}

/* The caveat beside a run option: the window an override bypasses, or which
   scripts cannot honor Dry run. */
.action-options-note {
  font-size: 11px;
  color: var(--warn);
}

.action-bar-runas {
  flex: 0 1 260px;
}

.action-bar-runas select {
  max-width: 100%;
}

.action-bar-blocked {
  flex: 1 1 100%;
  margin: 0;
  font-size: 12px;
  color: var(--warn);
  display: flex;
  align-items: center;
  gap: 8px;
}

.link-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent-2);
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
}

.btn-sm {
  padding: 4px 9px;
  font-size: 12px;
}

/* Row-selection column: narrow, unsortable, and outside PATCH_COLUMNS. */
.col-select {
  width: 32px;
  text-align: center;
}

/* A dispatch that will restart machines gets a visible accent, not just prose. */
.modal-danger {
  border-color: var(--danger);
}

.modal-blockers,
.modal-warnings {
  margin: 10px 0;
  padding-left: 18px;
  font-size: 13px;
}

.modal-blockers {
  color: var(--danger);
}

/* A dispatch that failed from the open dialog: said where the operator is looking,
   in the same danger palette as the blockers. */
.modal-error {
  margin: 10px 0;
  padding: 8px 12px;
  border: 1px solid var(--danger);
  border-radius: 8px;
  color: var(--danger-fg);
  font-size: 13px;
}

.modal-error p {
  margin: 0 0 6px;
}

.update-wait {
  color: var(--warn);
}

.modal-warnings {
  color: var(--warn);
}

.modal-label {
  margin: 12px 0 4px;
  font-size: 12px;
  color: var(--muted);
}

/* The exact string sent to the script — shown verbatim, wrapped rather than
   truncated so nothing is hidden from the operator approving it. */
.modal-params {
  margin: 0 0 12px;
  padding: 8px 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  /* One line per device for a targeted install, so a batch at the 25-device cap
     must not push the Confirm button off-screen. */
  max-height: 220px;
  overflow-y: auto;
}

/* Why a settled job has no Retry; the full reason is the tooltip. */
.retry-note {
  font-size: 12px;
  color: var(--muted);
  text-decoration: underline dotted;
  cursor: help;
}

/* The patches a Jobs row was sent, under its action. */
.job-targets {
  display: block;
  font-size: 11px;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* The same targets as the parameter block, in words — one device per line, capped
   like it so a full batch keeps the Confirm button on screen. */
.modal-target-lines {
  margin: 0 0 8px;
  padding-left: 18px;
  font-size: 13px;
  overflow-wrap: anywhere;
  max-height: 180px;
  overflow-y: auto;
}

.modal-targets,
.modal-skipped {
  margin: 8px 0;
  font-size: 12px;
  color: var(--muted);
}

.modal-targets ul,
.modal-skipped ul {
  margin: 6px 0 0;
  padding-left: 18px;
  max-height: 180px;
  overflow-y: auto;
}

/* What a native "Apply all" will install. The summary line carries the totals, so
   it reads without expanding; the per-device list is one click away. */
.modal-apply-preview {
  margin: 8px 0;
  font-size: 12px;
}

.modal-apply-preview ul {
  margin: 6px 0 0;
  padding-left: 18px;
  max-height: 180px;
  overflow-y: auto;
  color: var(--muted);
}

.modal-apply-preview .apply-preview-empty {
  color: var(--warn);
}

.modal-typed {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 12px 0;
  font-size: 13px;
  color: var(--danger);
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}

.script-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 10px;
  margin: 8px 0 4px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 13px;
}

.script-picker-targets {
  flex: 1 1 100%;
  margin: 0;
  font-size: 12px;
  color: var(--muted);
}

.script-picker label {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.script-picker-params {
  flex: 1 1 100%;
}

.script-picker-meta {
  flex: 1 1 100%;
  margin: 0;
  font-size: 12px;
  color: var(--muted);
}

.script-picker-tags {
  margin-left: 8px;
  opacity: 0.8;
}

.checkbox {
  flex-direction: row !important;
  align-items: center;
  gap: 6px;
}

.jobs-toolbar {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
}

.job-state {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 11px;
  border: 1px solid transparent;
}

.job-state-ok {
  color: var(--accent-2);
  border-color: var(--accent);
}

.job-state-bad {
  color: var(--danger);
  border-color: var(--danger);
}

.job-state-warn {
  color: var(--warn);
  border-color: var(--warn);
}

.job-state-running {
  color: var(--muted);
  border-color: var(--border);
}

.job-state-muted {
  color: var(--muted);
  opacity: 0.75;
}

/* The displayed results predate a dispatched action. */
.stale-banner {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 8px 0;
  padding: 8px 12px;
  border: 1px solid var(--warn);
  border-radius: 8px;
  background: var(--panel-2);
  font-size: 13px;
  color: var(--warn);
}

.settings-actions,
.settings-sla {
  margin-top: 14px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.settings-actions legend,
.settings-sla legend {
  padding: 0 6px;
  font-size: 12px;
  color: var(--muted);
}

.settings-hint {
  margin: 4px 0 10px;
  font-size: 12px;
  color: var(--muted);
}

/* One SLA band: its days input with the No SLA switch beneath it. */
.sla-band {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.sla-none {
  font-size: 12px;
  color: var(--muted);
}

/* The Compliance tab's headline figures. */
.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px;
  margin: 12px 0 8px;
}

.kpi {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
}

.kpi dt {
  font-size: 12px;
  color: var(--muted);
}

.kpi dd {
  margin: 0;
}

.kpi-value {
  font-size: 24px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.kpi-detail {
  font-size: 13px;
}

.kpi-def {
  margin-top: 4px !important;
  font-size: 12px;
  color: var(--muted);
}

/* "How these numbers are calculated". */
.calc-notes {
  margin: 4px 0 12px;
  font-size: 13px;
}

.calc-notes summary {
  cursor: pointer;
  color: var(--muted);
}

.calc-notes dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 14px;
  margin: 8px 0 0;
}

.calc-notes dt {
  color: var(--muted);
}

.calc-notes dd {
  margin: 0;
}

/* A header or label whose definition is in its tooltip. */
.col-help {
  text-decoration: underline dotted;
  text-decoration-color: var(--muted);
  text-underline-offset: 3px;
  cursor: help;
}

/* The fleet total under the organization table: body-cell spacing, set apart by a
   heavier rule. */
.total-row th,
.total-row td {
  padding: 7px 10px;
  font-weight: 600;
  white-space: nowrap;
  border-top: 2px solid var(--border);
}

.total-row th {
  text-align: left;
}

/* The approvals card follows the organization table directly. */
.compliance-approvals {
  margin-top: 16px;
}

.settings-disabled {
  opacity: 0.5;
}

.settings-window {
  margin: 4px 0 10px 24px;
}

.settings-window-days {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  margin-bottom: 6px;
  font-size: 13px;
}

.settings-window-label {
  color: var(--muted);
  font-size: 12px;
}

.settings-problem {
  color: var(--warn);
}

/* --- Patches view modes + grouped view ---------------------------------- */

.view-modes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0;
}

/* The active view mode. `.chip` is also used for multi-select facets, so this
   only ever rides on the mode buttons, which are single-select. */
.chip-on {
  background: var(--accent-soft);
  border-color: var(--accent-2);
  color: var(--accent-2);
}

.groups {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.group {
  /* Never shrunk: the list is a height-capped flex column that scrolls inside the
     tab, and a shrinkable group (its `overflow: hidden` lets it go below its
     content) was squeezed to a sliver once the list outgrew the window, cutting
     an expanded group's rows in half instead of scrolling. */
  flex: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
  overflow: hidden;
}

.group-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
}

.group-toggle {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  background: none;
  border: 0;
  padding: 0;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.group-caret {
  color: var(--muted);
  width: 1em;
  flex: none;
}

.group-label {
  font-weight: 600;
}

.group-sub,
.group-count {
  font-size: 12px;
  color: var(--muted);
}

/* Pushes the member count to the right on wide viewports, but lets it wrap
   under the label on narrow ones rather than overflowing the panel. */
.group-count {
  margin-left: auto;
}

.chip-note {
  font-size: 11.5px;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1px 6px;
}

/* A row's flags beside the device or patch name: "reboot pending", "reboot
   likely", "job running". */
td .chip-note {
  display: inline-block;
  margin-left: 6px;
  white-space: nowrap;
}

td.patch-name .chip-note {
  margin: 2px 0 0;
}

/* NinjaOne reports a job running on the device (`RunningJobChip`). */
.chip-live {
  color: var(--info-fg);
  border-color: var(--info);
}

/* The Jobs tab's "Running in NinjaOne" section, above the dispatched-jobs list. */
.live-jobs {
  margin-bottom: 18px;
}

.live-jobs .jobs-toolbar {
  align-items: baseline;
}

.live-jobs-asof {
  font-size: 12px;
  color: var(--muted);
}

.group-members {
  border-top: 1px solid var(--border);
}

.group-members td {
  padding: 6px 10px;
}

/* The sentence stating which devices and which patch families the compliance
   numbers describe. Muted and small — it qualifies the figures below it rather
   than competing with them. */
.scope-note {
  margin: 8px 2px 12px;
  font-size: 12px;
  color: var(--muted);
}

/* Jobs tab section headings — the live session list and the durable audit trail
   are two different things and were previously one undifferentiated table. */
.jobs-heading {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 22px 0 4px;
  font-size: 0.95rem;
  color: var(--text);
}
.jobs-heading:first-of-type { margin-top: 8px; }
/* The two native applies install a device's whole approved backlog regardless of
   the selection. That reach used to be carried only by the 11px group heading
   above them, so the buttons themselves now read as the wider action. */
.btn-wide-radius {
  border-color: var(--warn);
  color: var(--warn);
}
.btn-wide-radius:disabled {
  border-color: var(--border);
  color: var(--muted);
}

/* Blast radius as the confirm dialog's first line, above the device list. */
.confirm-radius {
  margin: 0 0 0.75rem;
  color: var(--muted);
}
.confirm-radius-wide {
  color: var(--warn);
  font-weight: 600;
}

/* --- Trend tab: fleet health over the run history ------------------------- */

/* Side by side on a wide window: the cards are read together, as a row. */
.trend-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 10px;
  margin-bottom: 10px;
}

.trend-card {
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  background: var(--panel-2);
  color: var(--accent);
}
.trend-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}
.trend-title {
  font-weight: 600;
  color: var(--text);
}
/* Direction, not magnitude: more compliance is better, more of everything else
   here is worse, so the sign alone cannot carry the meaning. */
.trend-delta { font-variant-numeric: tabular-nums; color: var(--muted); }
.trend-better { color: var(--accent-2); }
.trend-worse { color: var(--danger); }
.trend-spark {
  display: block;
  width: 100%;
  height: 60px;
  margin: 6px 0 2px;
}
.trend-foot {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.trend-now { color: var(--text); font-weight: 600; }
/* Per-organization deltas under the trend cards. */
.trend-subhead {
  margin: 18px 0 6px;
  font-size: 14px;
  color: var(--text);
}

/* --- Patches tab: changes since the previous comparable run ---------------- */
/* One line: the baseline and three counts, each opening its list below. */
.changes {
  margin: 0 0 8px;
  padding: 6px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
}
.changes-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
}
.changes-title {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
}
.changes-toggle {
  background: none;
  border: none;
  border-radius: 6px;
  padding: 2px 6px;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.changes-toggle:hover {
  background: var(--panel);
}
.changes-count {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* Direction by meaning, as on the trend cards: new and failed are worse. */
.changes-new .changes-count { color: var(--warn); }
.changes-resolved .changes-count { color: var(--accent-2); }
.changes-failed .changes-count { color: var(--danger); }
.changes-list { margin-top: 6px; }
.changes-table { margin-top: 0; }
.changes-note {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--muted);
}
/* Desktop build with no reachable Tauri backend. Replaces the whole UI rather than
   sitting above it: the point is that no fleet numbers are on screen at all, so
   there is nothing for this to annotate. See app.rs's `backend_missing` branch. */
.backend-missing {
  max-width: 60ch;
  margin: 15vh auto 0;
  border-color: var(--danger);
}
.backend-missing h2 {
  color: var(--danger);
  margin-top: 0;
}

/* Motion. Honour the OS setting: no sliding, fading or animated width changes.
   The indeterminate progress bar becomes a static half-strength bar — it still
   says "working", it just stops moving. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .progress-indeterminate {
    animation: none;
    width: 100%;
    opacity: 0.45;
  }
}

/* --- Operator UX: auto-refresh countdown, view links, column chooser, shortcuts --- */

.refresh-countdown {
  color: var(--muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.view-code {
  flex: 1 1 260px;
  min-width: 0;
  max-width: 520px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
}

.view-link-warning {
  margin: 0;
}

.patches-toolbar {
  justify-content: space-between;
}

.patches-toolbar .view-modes {
  margin: 0;
}

.patches-toolbar {
  margin: 0 0 8px;
}

.patches-toolbar .pager {
  margin: 0;
}

.patches-toolbar .pager .btn {
  padding: 5px 10px;
}

/* The count beside a tab's name: what is waiting there. */
.tab-badge {
  display: inline-block;
  min-width: 1.6em;
  margin-left: 6px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 11px;
  line-height: 1.6;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.tab-on .tab-badge {
  color: var(--text);
}

.column-menu {
  position: relative;
}

.column-menu > summary {
  list-style: none;
  cursor: pointer;
}

.column-menu > summary::-webkit-details-marker {
  display: none;
}

.column-menu__panel {
  position: absolute;
  right: 0;
  z-index: 20;
  margin-top: 4px;
  min-width: 220px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  box-shadow: 0 8px 24px var(--shadow);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.column-menu__item {
  display: flex;
  flex-direction: row;
  color: var(--text);
  align-items: center;
  gap: 6px;
  font-size: 13px;
}

.column-menu__note {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 12px;
}

.shortcuts-table {
  width: 100%;
  border-collapse: collapse;
  margin: 8px 0 4px;
}

.shortcuts-table th,
.shortcuts-table td {
  text-align: left;
  padding: 6px 4px;
  border-bottom: 1px solid var(--border);
  font-weight: normal;
  white-space: normal;
}

.shortcuts-table th {
  white-space: nowrap;
  width: 1%;
  padding-right: 16px;
}

kbd {
  display: inline-block;
  min-width: 1.6em;
  padding: 1px 6px;
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: 5px;
  background: var(--panel-2);
  color: var(--text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  text-align: center;
}

/* --- Device drill-down (tables/device.rs) --- */
/* Wider than the confirm/update dialogs: it carries a patch table. */
.modal-wide {
  width: min(920px, 100%);
}

.device-drill-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}

.device-facts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 8px 16px;
  margin: 0 0 12px;
}

.device-fact dt {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.device-fact dd {
  margin: 2px 0 0;
  font-size: 13px;
}

.device-bands {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0 0 12px;
}

/* A KB that fixes a vulnerability exploited in the wild (`exploited_chip`):
   the danger palette, so it reads above the neutral reboot notes beside it. */
.chip-exploited {
  color: var(--danger-fg);
  border-color: var(--danger);
  background: var(--danger-soft);
}

/* The CVE search's id field and button share a line. */
.cve-search__form {
  gap: 8px;
  margin-bottom: 12px;
}
