/* workhorse-web, in Unfold's look without its chrome (docs/superpowers/specs/2026-10-19-unfold-design.md).
   Colours come from Unfold's palette (unfold-colors.css: --color-base-*, --color-primary-*, --color-font-*),
   the type is Unfold's Inter, icons are its Material Symbols, corners its --border-radius. Everything else
   is this file: a 4px spacing scale, a small type scale, and semantic colours that always travel with a
   symbol or words. Light and dark follow prefers-color-scheme; no script is involved. */

:root {
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-6: 24px; --space-8: 32px; --space-12: 48px;
  --text-xs: 12px; --text-sm: 13px; --text-md: 14px; --text-lg: 16px; --text-xl: 20px;
  --radius: var(--border-radius, 6px);
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sidebar-width: 288px;

  --bg: #fff;
  --surface: #fff;
  --surface-2: var(--color-base-50);
  --surface-3: var(--color-base-100);
  --sidebar-bg: var(--color-base-50);
  --nav-current-bg: var(--color-base-100);
  --nav-accent: var(--color-primary-600);
  --hover: var(--color-base-100); /* rows, menus and default buttons on hover: base-50 on white was invisible */
  --chip-border: var(--color-base-200);
  --border: var(--color-base-200);
  /* Form-field edges need 3:1 against the page (WCAG 1.4.11): base-500 reaches it in both themes (4.8:1 on white,
     4.6:1 on the sidebar, 3.7:1 on base-900). --border stays for cards, tables, dividers and buttons. */
  --control-border: var(--color-base-500);
  --text: var(--color-font-default-light);
  --text-strong: var(--color-font-important-light);
  --text-muted: var(--color-font-subtle-light);
  --accent: var(--color-primary-600);
  --accent-strong: var(--color-primary-700);
  --accent-text: #fff;
  --link: var(--color-primary-700);
  --ok: #166534;    --ok-bg: #dcfce7;
  --warn: #854d0e;  --warn-bg: #fef9c3;
  --error: #b91c1c; --error-bg: #fee2e2;
  --info: var(--color-primary-700); --info-bg: var(--color-primary-50);
  --focus: var(--color-primary-600);
  --menu-bg: var(--surface);
  --menu-border: var(--border);
  --menu-hover: var(--hover);
  --menu-shadow: 0 8px 24px rgb(0 0 0 / 0.12);
  --button-border: var(--color-base-200);
  --row-stripe: var(--color-base-50);
  color-scheme: light;
}

/* Dark: chosen explicitly (data-theme="dark"), or following the system unless Light was chosen. The theme
   menu stores the choice; the server renders data-theme, so there is no flash and no script. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: var(--color-base-900);
    --surface: var(--color-base-900);
    --surface-2: var(--color-base-800);
    --surface-3: var(--color-base-700);
    --sidebar-bg: color-mix(in srgb, var(--color-base-950) 20%, var(--color-base-900));
    --nav-current-bg: rgb(255 255 255 / 0.06);
    --nav-accent: var(--color-primary-400);
    --hover: var(--color-base-800);
    --chip-border: var(--color-base-700);
    --border: var(--color-base-800);
    --text: var(--color-font-default-dark);
    --text-strong: var(--color-font-important-dark);
    --text-muted: var(--color-font-subtle-dark);
    /* White text needs the darker accent (≥4.5:1); the current nav item reads in a light tint. */
    --accent: var(--color-primary-600);
    --accent-strong: var(--color-primary-300);
    --accent-text: #fff;
    --link: var(--color-primary-300);
    --ok: #86efac;    --ok-bg: #14532d;
    --warn: #fde68a;  --warn-bg: #422006;
    --error: #fca5a5; --error-bg: #450a0a;
    --info: var(--color-primary-200); --info-bg: var(--color-primary-950);
    --focus: var(--color-primary-400);
    /* A shadow doesn't show on dark: menus are raised a step instead, as Unfold's dropdowns are. */
    --menu-bg: var(--color-base-800);
    --menu-border: var(--color-base-700);
    --menu-hover: var(--color-base-700);
    --menu-shadow: 0 8px 24px rgb(0 0 0 / 0.5);
    --button-border: var(--color-base-700); /* above the base-800 hover fill, so a hovered button keeps its outline */
    --row-stripe: rgb(255 255 255 / 0.02);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: var(--color-base-900);
  --surface: var(--color-base-900);
  --surface-2: var(--color-base-800);
  --surface-3: var(--color-base-700);
  --sidebar-bg: color-mix(in srgb, var(--color-base-950) 20%, var(--color-base-900));
  --nav-current-bg: rgb(255 255 255 / 0.06);
  --nav-accent: var(--color-primary-400);
  --hover: var(--color-base-800);
  --chip-border: var(--color-base-700);
  --border: var(--color-base-800);
  --text: var(--color-font-default-dark);
  --text-strong: var(--color-font-important-dark);
  --text-muted: var(--color-font-subtle-dark);
  /* White text needs the darker accent (≥4.5:1); the current nav item reads in a light tint. */
  --accent: var(--color-primary-600);
  --accent-strong: var(--color-primary-300);
  --accent-text: #fff;
  --link: var(--color-primary-300);
  --ok: #86efac;    --ok-bg: #14532d;
  --warn: #fde68a;  --warn-bg: #422006;
  --error: #fca5a5; --error-bg: #450a0a;
  --info: var(--color-primary-200); --info-bg: var(--color-primary-950);
  --focus: var(--color-primary-400);
  --menu-bg: var(--color-base-800);
  --menu-border: var(--color-base-700);
  --menu-hover: var(--color-base-700);
  --menu-shadow: 0 8px 24px rgb(0 0 0 / 0.5);
  --button-border: var(--color-base-700);
  --row-stripe: rgb(255 255 255 / 0.02);
  color-scheme: dark;
}
:root[data-theme="light"] { color-scheme: light; }

/* Base */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: var(--text-md)/calc(20 / 14) var(--font); /* Unfold's text-sm leading, as a ratio for 12-16px text */
  -webkit-font-smoothing: antialiased;
}
a { color: var(--link); text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
/* Slightly rounded rings on elements without corners of their own (links, summaries); zero specificity, so a
   control's own border-radius always wins and focus never changes its shape. */
:where(:focus-visible) { border-radius: 2px; }
h1, h2, h3, h4 { color: var(--text-strong); line-height: 1.25; margin: 0 0 var(--space-3); font-weight: 600; }
h1 { font-size: var(--text-xl); letter-spacing: -0.01em; }
h2 { font-size: var(--text-lg); margin-top: var(--space-8); }
h3, h4 { font-size: var(--text-md); }
p { margin: 0 0 var(--space-3); }
strong { color: var(--text-strong); }
.mono, code, pre { font-family: var(--mono); font-size: 0.92em; }
.muted { color: var(--text-muted); }
.wrap { overflow-wrap: anywhere; }
.keep-lines { white-space: pre-wrap; overflow-wrap: anywhere; } /* collected text shown whole, its line breaks kept */
.lede { max-width: 70ch; color: var(--text-muted); }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.notes { max-width: 70ch; }
ul.plain { list-style: none; padding: 0; margin: 0; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: var(--space-4); top: var(--space-2); z-index: 20; background: var(--surface); color: var(--link); padding: var(--space-2) var(--space-3); border-radius: var(--radius); }
/* Unfold's icon font: its fonts CSS declares only the @font-face; the class that applies it lives in Unfold's
   main stylesheet, which tenant pages don't load. Ligature names (e.g. "search") render as glyphs. */
.material-symbols-outlined {
  font-family: "Material Symbols Outlined"; font-weight: 400; font-style: normal; font-size: 20px; line-height: 1;
  letter-spacing: normal; text-transform: none; white-space: nowrap; word-wrap: normal; direction: ltr;
  display: inline-block; font-feature-settings: "liga"; -webkit-font-smoothing: antialiased; user-select: none;
}

/* Shell: Unfold's layout — a sidebar of categories, a slim header, the page. */
.shell { min-height: 100vh; }
.with-sidebar .shell { display: grid; grid-template-columns: var(--sidebar-width) minmax(0, 1fr); }
.page { min-width: 0; display: flex; flex-direction: column; }
.page-header {
  display: flex; align-items: center; gap: var(--space-4); min-height: 64px;
  padding: var(--space-2) var(--space-6); border-bottom: 1px solid var(--border); background: var(--surface);
}
.page-header-end { margin-left: auto; display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.header-link { color: var(--text-muted); text-decoration: none; font-weight: 500; padding: var(--space-2); border-radius: var(--radius); }
.header-link:hover { color: var(--text-strong); background: var(--hover); }
main { width: 100%; max-width: 1440px; padding: var(--space-6) var(--space-6) var(--space-12); overflow-wrap: break-word; } /* a long word (an API name) breaks rather than push the page sideways */

.sidebar {
  position: sticky; top: 0; align-self: start; height: 100vh; overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--space-4);
  padding: var(--space-4); background: var(--sidebar-bg); border-right: 1px solid var(--border);
}
.brand { display: flex; align-items: center; gap: var(--space-3); color: var(--text-strong); text-decoration: none; }
.brand-symbol {
  display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; flex: none;
  border-radius: var(--radius); background: var(--accent); color: var(--accent-text);
}
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.brand-name { font-weight: 600; color: var(--text-strong); }
.brand-tenant { font-size: var(--text-xs); color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A tenant's brand (docs/superpowers/specs/2026-10-23-tenant-branding-design.md, "Pages"). Every logo variant is in the
   page and CSS picks one (theme, collapsed rail), so the theme menu needs no request and no script. Logo over tenant name. */
.brand-custom { flex-direction: column; align-items: flex-start; gap: var(--space-1); min-width: 0; }
.brand-custom img { display: none; height: 32px; width: auto; max-width: 100%; object-fit: contain; }
.brand-custom .brand-logo.brand-logo-light { display: block; }
.brand-custom .brand-tenant { max-width: 100%; }
/* The accent rule: --brand-accent comes from the brand's own stylesheet (/brand/<version>.css on the tenant's host, linked in
   base.html), never an inline or nonce'd style, so style-src stays 'self'; without it the app's own accent shows. */
.sidebar-accent { border-top: 3px solid var(--brand-accent, var(--accent)); }
/* Dark theme: the dark logo when the brand has one; otherwise the light logo on a light plate so a dark logo stays visible. */
:root[data-theme="dark"] .brand-has-dark .brand-logo-light { display: none !important; }
:root[data-theme="dark"] .brand-has-dark .brand-logo.brand-logo-dark { display: block; }
:root[data-theme="dark"] .brand-custom:not(.brand-has-dark) img { background: #fff; padding: 4px; border-radius: var(--radius); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-has-dark .brand-logo-light { display: none !important; }
  :root:not([data-theme="light"]) .brand-has-dark .brand-logo.brand-logo-dark { display: block; }
  :root:not([data-theme="light"]) .brand-custom:not(.brand-has-dark) img { background: #fff; padding: 4px; border-radius: var(--radius); }
}
/* Muted footer line; "Built with workhorse" is a small credit at the sidebar's foot. */
.brand-footer { padding: var(--space-4) var(--space-6); font-size: var(--text-xs); color: var(--text-muted); border-top: 1px solid var(--border); }
.brand-footer p { margin: 0; }
.brand-footer a { color: inherit; text-decoration: underline; }
.brand-credit { margin: var(--space-4) var(--space-3) 0; font-size: var(--text-xs); color: var(--text-muted); }
.print-brand { display: none; }
/* The input is the box (border, background and radius from the shared input rule), so its focus ring surrounds the
   whole field; the magnifier sits in its left padding and lets clicks through. */
.sidebar-search { position: relative; display: flex; color: var(--text-muted); }
.sidebar-search .material-symbols-outlined { position: absolute; left: calc(1px + var(--space-3)); top: 50%; transform: translateY(-50%); pointer-events: none; }
.sidebar-search input[type=search] { flex: 1; min-width: 0; padding-left: calc(var(--space-3) + 20px + var(--space-2)); box-shadow: none; }
.sidebar-search input[type=search]:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.sidebar-disclosure { flex: 1; }
.sidebar-disclosure > :not(summary) + :not(summary) { margin-top: var(--space-4); }
/* The account's controls in the Menu: only below 1024px (the header holds them on wider screens). */
.menu-account { display: none; }
.sidebar-version { margin: var(--space-4) var(--space-3) 0; font-size: var(--text-xs); color: var(--text-muted); }
.sidebar-toggle { display: none; }
.nav-list { list-style: none; margin: 0 0 var(--space-2); padding: 0; display: flex; flex-direction: column; gap: 2px; }
.nav-list a {
  display: flex; align-items: center; gap: var(--space-3); min-height: 38px; padding: var(--space-2) var(--space-3);
  border-radius: var(--radius); color: var(--text); text-decoration: none; font-weight: 500;
}
.nav-list a .material-symbols-outlined { color: var(--text-muted); }
/* Hover tints the text; only the current page gets the pill, so two items never both look selected. */
.nav-list a:hover { color: var(--nav-accent); }
.nav-list a[aria-current] { background: var(--nav-current-bg); color: var(--nav-accent); font-weight: 600; }
.nav-list a:hover .material-symbols-outlined, .nav-list a[aria-current] .material-symbols-outlined { color: inherit; }
/* Items paint in order, so the next item's pill would cover the bottom of this one's focus ring. */
.nav-list a:focus-visible { position: relative; z-index: 1; }
/* A section is a disclosure and its heading the summary: the whole row opens and closes the list below it, with no
   script; app.js only remembers the choice. The caret points down while open and right while closed. */
.nav-section { margin-top: var(--space-3); }
.nav-heading {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  min-height: 32px; padding: var(--space-1) var(--space-3); border-radius: var(--radius); list-style: none; cursor: pointer;
  font-size: var(--text-sm); font-weight: 600; color: var(--text-strong);
}
.nav-heading::-webkit-details-marker { display: none; }
.nav-heading:hover { background: var(--hover); }
.nav-caret { flex: none; font-size: 18px; color: var(--text-muted); transition: transform 120ms ease; }
.nav-section:not([open]) .nav-caret { transform: rotate(-90deg); }

/* Collapsing the sidebar (wide screens): the button at the start of the header narrows it to a rail of icons.
   The server draws the page already collapsed (a cookie), so nothing jumps on load. Labels stay in the
   accessibility tree and show as tips on hover and keyboard focus; Escape hides a tip (app.js). */
:root { --tip-bg: var(--text-strong); --tip-text: var(--bg); }
.icon-button {
  position: relative; display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 36px; height: 36px; min-height: 36px; padding: 0; border: 0; border-radius: var(--radius);
  background: transparent; color: var(--text-muted); box-shadow: none; cursor: pointer;
}
.icon-button:hover { background: var(--surface-2); color: var(--text-strong); }
.tip { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.icon-button:is(:hover, :focus-visible) .tip {
  width: auto; height: auto; margin: 0; overflow: visible; clip: auto; z-index: 40; top: calc(100% + 6px); left: 0;
  padding: var(--space-1) var(--space-2); border-radius: var(--radius); background: var(--tip-bg); color: var(--tip-text);
  font-size: var(--text-sm); font-weight: 500; line-height: 1.4;
}
/* A tip can be hovered without vanishing: an invisible bridge spans the gap to its owner. */
.icon-button .tip::before { content: ""; position: absolute; left: 0; right: 0; top: -6px; height: 6px; }
body[data-tips="off"] .tip { opacity: 0 !important; pointer-events: none; }
.sidebar-search-link {
  display: none; align-items: center; justify-content: center; min-height: 36px; padding: var(--space-2);
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--text-muted); text-decoration: none;
}
.sidebar-search-link:hover { color: var(--text-strong); }

@media (min-width: 1024px) {
  /* Only while the button moves it (app.js), so resizing the window never animates the layout. */
  .sidebar-moving .shell { transition: grid-template-columns 160ms ease; }
  .sidebar-collapsed { --sidebar-width: 73px; }
  .sidebar-collapsed .sidebar { padding: var(--space-4) var(--space-3); overflow: visible; z-index: 30; }
  .sidebar-collapsed .sidebar-version { display: none; }
  .sidebar-collapsed .sidebar-search { display: none; }
  .sidebar-collapsed .sidebar-search-link { display: flex; }
  .sidebar-collapsed :is(.brand, .nav-list a, .sidebar-search-link) { position: relative; justify-content: center; }
  .sidebar-collapsed .nav-list a { padding: var(--space-2); }
  .sidebar-collapsed :is(.nav-label, .brand-text, .nav-heading) {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  /* The rail shows every item, closed section or not. Its headings are out of sight, so they leave the Tab order too
     (the lists they name keep their names: aria-labelledby reads a hidden label). */
  .sidebar-collapsed .nav-heading { visibility: hidden; }
  .sidebar-collapsed .nav-section:not([open])::details-content { content-visibility: visible; }
  .sidebar-collapsed .nav-section { border-top: 1px solid var(--border); padding-top: var(--space-2); margin-top: var(--space-2); }
  .sidebar-collapsed :is(.nav-list a, .sidebar-search-link):is(:hover, :focus-visible) .nav-label,
  .sidebar-collapsed .brand:focus-visible .brand-text {
    width: auto; height: auto; margin: 0; overflow: visible; clip: auto; z-index: 40;
    left: calc(100% + 8px); top: 50%; transform: translateY(-50%);
    padding: var(--space-1) var(--space-2); border-radius: var(--radius); background: var(--tip-bg); color: var(--tip-text);
    font-size: var(--text-sm); font-weight: 500; line-height: 1.4;
  }
  .sidebar-collapsed .brand-text * { color: inherit; font-size: inherit; }
  /* The rail shows the square rendition, fitted in its 36px square (dark one under the dark rules below). */
  .sidebar-collapsed .brand-custom img.brand-logo { display: none !important; }
  .sidebar-collapsed .brand-custom img.brand-rail { width: 36px; height: 36px; object-fit: contain; }
  .sidebar-collapsed .brand-custom img.brand-rail.brand-logo-light { display: block; }
  :root[data-theme="dark"] .sidebar-collapsed .brand-has-dark img.brand-rail.brand-logo-light { display: none; }
  :root[data-theme="dark"] .sidebar-collapsed .brand-has-dark img.brand-rail.brand-logo-dark { display: block; }
  .sidebar-collapsed .brand-credit { display: none; }
}
@media (min-width:1024px) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sidebar-collapsed .brand-has-dark img.brand-rail.brand-logo-light { display: none; }
  :root:not([data-theme="light"]) .sidebar-collapsed .brand-has-dark img.brand-rail.brand-logo-dark { display: block; }
}
@media (min-width:1024px) {
  .sidebar-collapsed :is(.nav-label, .brand-text)::before { content: ""; position: absolute; top: 0; bottom: 0; left: -8px; width: 8px; }
  body[data-tips="off"].sidebar-collapsed :is(.nav-label, .brand-text) { opacity: 0 !important; pointer-events: none; }
}
/* The rail lets its tips spill past it, so it can't scroll; on a short window, reaching every link matters more. */
@media (min-width: 1024px) and (max-height: 640px) {
  .sidebar-collapsed .sidebar { overflow-y: auto; }
}
@media (max-width: 1023px) {
  .sidebar-collapse { display: none; }
}

.tag-columns { font-size: var(--text-sm); color: var(--text-muted); margin: 0 0 var(--space-2); }
.tag-columns .chip { display: inline-flex; align-items: center; font-size: var(--text-sm); }

/* Defaults (inventory/defaults.py): the header's switch and the notes that say what a page leaves out. The switch is
   as quiet as the menus beside it (no fill, no border): it states the setting, "Defaults: hidden", and the page's own
   primary action stays the loudest thing on screen. */
.header-toggle {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: 36px; padding: var(--space-2) var(--space-3);
  border: 0; border-radius: var(--radius); background: transparent; color: var(--text-strong);
  font-weight: 500; box-shadow: none; cursor: pointer; white-space: nowrap;
}
.header-toggle .material-symbols-outlined { font-size: 20px; color: var(--text-muted); }
.header-toggle-label { color: var(--text-muted); }
.header-toggle:hover { background: var(--hover); }
.header-toggle:hover .header-toggle-label { color: var(--text); }
.defaults-note {
  display: flex; align-items: flex-start; gap: var(--space-2); margin: 0 0 var(--space-4); padding: var(--space-2) var(--space-3);
  border-radius: var(--radius); background: var(--surface-2); color: var(--text); font-size: var(--text-sm); max-width: 80ch;
}
.defaults-note .material-symbols-outlined { font-size: 18px; color: var(--text-muted); }
/* A hint: an explanation written on many pages, as one line that expands (a native <details>). The line says what
   matters; a chevron after it says there is more; opened, the rest reads under the line, aligned with its words. */
.hint > summary { display: flex; align-items: flex-start; gap: var(--space-2); min-height: 24px; list-style: none; cursor: pointer; }
.hint > summary::-webkit-details-marker { display: none; }
.hint > summary::after {
  content: ""; flex: none; align-self: center; width: 6px; height: 6px; margin: 0 var(--space-1);
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg); opacity: 0.7;
}
.hint[open] > summary::after { transform: rotate(-135deg); }
.hint > summary:hover .hint-line { text-decoration: underline; text-decoration-color: var(--text-muted); text-underline-offset: 2px; }
.hint > p { margin: var(--space-1) 0 0; }
details.defaults-note { display: block; width: fit-content; }
details.defaults-note > p { padding-left: calc(18px + var(--space-2)); }
.table-filter-hint { flex: 1 1 24rem; font-size: var(--text-sm); color: var(--text-muted); }
.table-filter-hint > summary { min-height: 38px; align-items: center; } /* centred on the Apply filters button beside it */
.table-filter-hint .mono { white-space: nowrap; } /* an example like <2026-01-01 stays whole */
.page-head .defaults-note { margin-top: var(--space-2); }
/* Four kinds: one row of four, two of two on narrower screens, one column on a phone. */
.cards.kind-cards { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1279px) { .cards.kind-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .cards.kind-cards { grid-template-columns: 1fr; } }
.kind-cards .card { display: flex; flex-direction: column; }
.kind-cards .card p { margin: 0 0 var(--space-2); }
.kind-cards .card p.kind-link { margin: auto 0 0; } /* the link sits at the foot; a card without one keeps its note up */
.kind-total { font-size: var(--text-xl); font-weight: 600; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.kind-total .muted { font-size: var(--text-sm); font-weight: 500; }

/* Tenant menu (a native disclosure; Escape/outside-click handled in app.js) */
.menu { position: relative; }
.menu summary {
  list-style: none; display: inline-flex; align-items: center; gap: var(--space-1); min-height: 36px;
  padding: var(--space-2) var(--space-3); border-radius: var(--radius); cursor: pointer; font-weight: 500; color: var(--text-strong);
}
.menu summary::-webkit-details-marker { display: none; }
.menu summary:hover { background: var(--hover); }
.menu .caret { font-size: 18px; color: var(--text-muted); }
.menu-label { max-width: min(24ch, 30vw); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu li a > span:first-child { overflow-wrap: anywhere; }
.menu ul {
  position: absolute; right: 0; z-index: 10; min-width: 240px; margin: var(--space-1) 0 0; padding: var(--space-2);
  list-style: none; background: var(--menu-bg); border: 1px solid var(--menu-border); border-radius: var(--radius);
  box-shadow: var(--menu-shadow);
}
.menu li a { display: flex; justify-content: space-between; gap: var(--space-4); padding: var(--space-2) var(--space-3); border-radius: var(--radius); text-decoration: none; color: var(--text); }
.menu li a:hover { background: var(--menu-hover); }
.menu li a:hover .muted { color: var(--text); } /* the role on a hovered row keeps its contrast in dark */
.menu li a[aria-current="true"] { font-weight: 600; color: var(--text-strong); }

/* Breadcrumbs in the header, as in Unfold. Separators are drawn chevrons, not characters, so screen readers
   read only the trail. */
/* One line that gives way before the header's controls do: the current page (the h1 repeats it) truncates first,
   parents only when they alone overflow. Separators are chevrons drawn after each parent, not characters. */
.breadcrumbs { flex: 1 1 0; min-width: 0; container-type: inline-size; }
.breadcrumbs ol { display: flex; flex-wrap: nowrap; align-items: center; list-style: none; margin: 0; padding: 0; font-weight: 500; color: var(--text-muted); }
.breadcrumbs li { display: inline-flex; align-items: center; min-width: 0; white-space: nowrap; }
.breadcrumbs li:not(:last-child)::after {
  content: ""; display: inline-block; flex: none; width: 6px; height: 6px; margin: 0 10px 0 8px;
  border-top: 1.5px solid currentColor; border-right: 1.5px solid currentColor; transform: rotate(45deg); opacity: 0.7;
}
.breadcrumbs a { min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--text-muted); text-decoration: none; }
.breadcrumbs a:hover { color: var(--text-strong); text-decoration: underline; }
.breadcrumbs [aria-current="page"] { display: block; flex: 1 1 0; overflow: hidden; text-overflow: ellipsis; color: var(--text-strong); font-weight: 600; }
/* No room for a word beside the controls: no trail rather than a sliver. */
@container (max-width: 4em) { .breadcrumbs ol { display: none; } }

/* Theme menu: one form of three buttons inside a disclosure. */
.menu .menu-panel {
  position: absolute; right: 0; z-index: 10; min-width: 220px; margin-top: var(--space-1); padding: var(--space-2);
  background: var(--menu-bg); border: 1px solid var(--menu-border); border-radius: var(--radius); box-shadow: var(--menu-shadow);
}
.menu .menu-panel ul { position: static; min-width: 0; margin: 0; padding: 0; border: 0; box-shadow: none; list-style: none; }
.menu-heading { margin: 0 0 var(--space-1); padding: var(--space-1) var(--space-3); font-size: var(--text-sm); font-weight: 600; color: var(--text-muted); }
.menu-option {
  width: 100%; justify-content: flex-start; gap: var(--space-3); min-height: 36px; padding: var(--space-2) var(--space-3);
  border: 0; box-shadow: none; background: transparent; color: var(--text); font-weight: 500;
}
.menu-option:hover { background: var(--menu-hover); }
.menu-option[aria-pressed="true"] { color: var(--text-strong); font-weight: 600; }
.menu-option .material-symbols-outlined { color: var(--text-muted); }
.menu-check { margin-left: auto; color: var(--accent-strong) !important; }
.theme-menu > summary .material-symbols-outlined { color: var(--text-muted); }

/* Page heads */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-6); }
.page-head h1, .page-head p { margin-bottom: var(--space-1); }
.crumbs { font-size: var(--text-sm); margin-bottom: var(--space-2); color: var(--text-muted); }

/* Buttons */
.button, button {
  font: inherit; font-size: var(--text-md); font-weight: 500;
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 38px; padding: var(--space-2) var(--space-3);
  border: 1px solid var(--button-border); border-radius: var(--radius);
  background: var(--surface); color: var(--text-strong); text-decoration: none; cursor: pointer;
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.05);
}
.button:hover, button:hover { background: var(--hover); }
.button:active, button:active { transform: translateY(1px); }
.button:disabled, button:disabled { opacity: 0.55; cursor: not-allowed; transform: none; }
.button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.button.primary:hover { background: var(--color-primary-700); border-color: var(--color-primary-700); }
/* Unfold's danger button: solid red-600 in both themes (white text 4.8:1); hover darkens to red-700 like primary. */
.button.danger { background: oklch(57.7% .245 27.325); border-color: transparent; color: #fff; }
.button.danger:hover { background: oklch(50.5% .213 27.518); }
button.link { border: 0; background: none; box-shadow: none; color: var(--text-muted); padding: var(--space-2); font-weight: 500; }
button.link:hover { color: var(--text-strong); background: var(--hover); }
.actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-4); }
.actions form { margin: 0; }

/* Forms */
.form.narrow { max-width: 560px; }
.field { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-4); border: 0; padding: 0; min-width: 0; }
.field label, .field legend { font-size: var(--text-md); font-weight: 500; color: var(--text-strong); padding: 0; }
.field label.inline { flex-direction: row; font-weight: 400; color: var(--text); }
fieldset.field { align-items: flex-start; }
label.inline { display: inline-flex; align-items: center; gap: var(--space-2); font-weight: 400; margin: 0 var(--space-3) var(--space-2) 0; }
input[type=text], input[type=search], input[type=password], input[type=email], input:not([type]), select, textarea, input[type=file] {
  font: inherit; font-size: var(--text-md); color: var(--text-strong);
  min-height: 38px; padding: var(--space-2) var(--space-3);
  background: var(--surface); border: 1px solid var(--control-border); border-radius: var(--radius);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); max-width: 100%;
}
input::placeholder, textarea::placeholder { color: var(--text-muted); opacity: 1; }
input[type=radio], input[type=checkbox] { width: 16px; height: 16px; accent-color: var(--accent); }
.help { font-size: var(--text-sm); color: var(--text-muted); margin: 0; }
div.error { font-size: var(--text-sm); color: var(--error); margin: 0; font-weight: 600; } /* not the flash li.error */
div.error p { margin: 0; }
.has-error input, .has-error select, .has-error textarea { border-color: var(--error); }

.error-summary {
  border: 2px solid var(--error); border-radius: var(--radius); background: var(--error-bg);
  padding: var(--space-4); margin-bottom: var(--space-6); max-width: 70ch;
}
.error-summary h2 { font-size: var(--text-md); margin: 0 0 var(--space-2); color: var(--error); }
.error-summary ul { margin: 0; padding-left: var(--space-4); }
.error-summary a { color: var(--error); font-weight: 600; }
.error-summary p { margin: 0; }
.error-summary:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }

/* Badges and alerts: always a symbol or words as well as colour */
.badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 2px var(--space-2); border-radius: var(--radius);
  font-size: var(--text-xs); font-weight: 600; white-space: nowrap;
  background: var(--surface-3); color: var(--text);
}
.badge-ok { background: var(--ok-bg); color: var(--ok); }
.badge-warn { background: var(--warn-bg); color: var(--warn); }
.badge-error { background: var(--error-bg); color: var(--error); }
.badge-info { background: var(--info-bg); color: var(--info); }
.alert { padding: var(--space-3) var(--space-4); border-radius: var(--radius); border-left: 4px solid; max-width: 80ch; color: var(--text-strong); }
.alert-error { background: var(--error-bg); border-color: var(--error); }
.alert-warn { background: var(--warn-bg); border-color: var(--warn); }
.alert-info { background: var(--info-bg); border-color: var(--info); }
.messages { list-style: none; padding: 0; margin: 0 0 var(--space-6); }
.message { padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--info-bg); color: var(--text-strong); margin-bottom: var(--space-2); }
.message.success { background: var(--ok-bg); }
.message.error { background: var(--error-bg); }

/* Tables (Unfold: bordered card, quiet header, hover rows) */
.table-wrap { position: relative; overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); }
/* A table wider than its region says so: its right edge fades while there is more to the right (app.js marks
   data-more="right" as it scrolls), so a clipped tag or column reads as "more this way", not as cut off. The region's
   edges (and its focus ring, drawn inside it here) stay solid; only the content fades. */
.table-wrap[data-more~="right"] {
  --edge: 2px;
  mask-image: linear-gradient(to left, rgb(0 0 0 / 0.1), #000 64px), linear-gradient(#000 0 0), linear-gradient(#000 0 0),
              linear-gradient(#000 0 0);
  mask-size: 100% 100%, 100% var(--edge), 100% var(--edge), var(--edge) 100%;
  mask-position: 0 0, 0 0, 0 100%, 100% 0;
  mask-repeat: no-repeat;
}
.table-wrap[data-more~="right"]:focus-visible { outline-offset: -2px; } /* inside the region, where the mask keeps it solid */
/* Its scrollbar stays in view (macOS and phones hide an idle one), a thin bar in the theme's greys. */
.table-wrap::-webkit-scrollbar { height: 10px; }
.table-wrap::-webkit-scrollbar-track { background: var(--surface-2); border-top: 1px solid var(--border); }
.table-wrap::-webkit-scrollbar-thumb { background: var(--control-border); border: 2px solid var(--surface-2); border-radius: 999px; }
.table-wrap::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }
@media print { .table-wrap[data-more] { mask-image: none; } }
.table-wrap:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.table-wrap a { scroll-margin: var(--space-2); } /* scrolled into view with room for its focus ring */
table { width: 100%; border-collapse: collapse; font-size: var(--text-md); }
th, td { padding: var(--space-3); text-align: left; vertical-align: baseline; border-bottom: 1px solid var(--border); }
tbody tr:last-child :is(td, th) { border-bottom: 0; }
/* Column headers. A row's own header (th scope=row, its identifying cell) looks like the other cells. */
thead th { font-weight: 600; color: var(--text-strong); white-space: nowrap; }
thead th a { color: inherit; text-decoration: none; }
thead th a:hover { text-decoration: underline; }
tbody th { font-weight: inherit; }
tbody tr:nth-child(even) { background: var(--row-stripe); }
tbody tr:hover { background: var(--hover); }
/* On a phone a wide table scrolls sideways in its region. Its first column, the row's name, stays in place so every
   row keeps its name in view, and gives up width: a long name wraps instead of pushing the other columns off screen.
   The stuck cells paint the row's own background (stripe or hover) over the surface, so nothing shows through. */
@media (max-width: 640px) {
  /* Scrolling to a focused field keeps it clear of the pinned column, so focus is never hidden under it. */
  .table-wrap { scroll-padding-left: calc(40vw + 8px); }
  /* Only a table whose first cell is the row's name pins its first column, heading and filter included. */
  .table-wrap tbody th[scope="row"]:first-child,
  .table-wrap:has(tbody th[scope="row"]:first-child) :is(thead tr:first-child th:first-child, thead tr.filter-row td:first-child) {
    position: sticky; left: 0; z-index: 1; min-width: min(40vw, 10rem); max-width: 40vw; overflow-wrap: anywhere; white-space: normal;
    background: var(--surface); box-shadow: inset -1px 0 0 var(--border);
  }
  .table-wrap tbody tr:nth-child(even) th[scope="row"]:first-child { background: linear-gradient(var(--row-stripe), var(--row-stripe)), var(--surface); }
  .table-wrap tbody tr:hover th[scope="row"]:first-child { background: var(--hover); }
  .badge { white-space: normal; align-items: first baseline; }
}
tbody tr:hover .muted { color: var(--text); } /* muted on the hover tint was 4.4:1 */
thead th { padding-top: var(--space-2); padding-bottom: var(--space-2); }
tr.removed :is(td, th) { color: var(--text-muted); }
tbody tr.removed:hover :is(td, th) { color: var(--text); } /* muted on the hover tint fell under 4.5:1 */
table.compact td, table.compact th { padding: var(--space-2) var(--space-3); }
.name:is(td, th) { max-width: 40ch; overflow-wrap: anywhere; }
table.resources :is(td, th) { white-space: nowrap; }
/* The column the nowrap columns squeeze: 24ch keeps long ids (hashes, ARNs) to about 3 lines. */
table.resources .name:is(td, th) { white-space: normal; min-width: 24ch; }
/* The tags wrap (a row of chips); the type keeps its line ("iam virtual mfa device"), so no row doubles in height. */
table.resources td.tags { white-space: normal; min-width: 14ch; }
/* A resource with no name of its own shows the start of the id the collector derived for it: as an id (monospace,
   muted), so it doesn't read as a broken name; the full id is its link's title, and a screen reader hears "Unnamed". */
a.unnamed { font-family: var(--mono); font-size: 0.92em; color: var(--text-muted); text-decoration-color: currentColor; }
a.unnamed:hover { color: var(--link); }
tbody tr:hover a.unnamed { color: var(--text); }
th.tag-col { white-space: nowrap; }
/* Tag columns hold data of any length (128-character keys, 256-character values): cap each one. */
.clip { display: inline-block; max-width: 32ch; overflow: clip; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.chip {
  display: inline-block; margin: 0 var(--space-1) var(--space-1) 0; padding: 0 var(--space-2);
  border: 1px solid var(--chip-border); border-radius: var(--radius); font-size: var(--text-xs);
  color: var(--text); text-decoration: none; white-space: nowrap; background: var(--surface-2);
}
.chip:hover { color: var(--text-strong); border-color: var(--text-muted); }
.remove-col {
  display: inline-flex; align-items: center; justify-content: center; min-width: 24px; min-height: 24px;
  margin-left: var(--space-1); border-radius: var(--radius); text-decoration: none; color: var(--text-muted);
  border: 1px solid var(--border); /* a small button, not colour alone, inside the heading text */
}
.remove-col:hover { background: var(--surface-3); color: var(--text-strong); }

/* Definition lists */
.meta { display: grid; grid-template-columns: max-content 1fr; align-items: baseline; gap: var(--space-2) var(--space-6); margin: 0 0 var(--space-6); }
.meta dt { color: var(--text-muted); }
.meta dd { margin: 0; color: var(--text-strong); }
.card-stats dt { font-size: var(--text-sm); color: var(--text-muted); }

/* Empty states */
.empty { text-align: center; padding: var(--space-12) var(--space-6); border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface); }
.empty h2 { margin-top: 0; }
.empty p { max-width: 55ch; margin-left: auto; margin-right: auto; color: var(--text-muted); }

/* Overview */
.cards { list-style: none; padding: 0; margin: 0 0 var(--space-8); display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-4); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); }
.card h3, .card h4 { margin-bottom: var(--space-1); overflow-wrap: anywhere; }
.card-stats { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); margin: var(--space-3) 0 0; }
.card-stats dd { margin: 0; font-weight: 600; color: var(--text-strong); }
.group-heading { font-size: var(--text-md); margin: var(--space-6) 0 var(--space-3); }
.group-heading:first-of-type { margin-top: 0; }
.group-heading .muted, .account-group h2 .muted { font-weight: 400; font-size: var(--text-sm); }
.account-group + .account-group { margin-top: var(--space-6); }
.account-group h2 { font-size: var(--text-md); margin-top: 0; }
/* One table per organization: the short columns get the same widths in each, so they line up. */
.account-group thead th:nth-child(2) { width: 84px; }
.account-group thead th:nth-child(3) { width: 120px; }
.account-group thead th:nth-child(4) { width: 240px; }
.account-group thead th:nth-child(5) { width: 120px; }
.two-col { display: grid; gap: var(--space-8); grid-template-columns: repeat(auto-fit, minmax(min(440px, 100%), 1fr)); }
.two-col h2 { margin-top: 0; }
.bars { list-style: none; padding: 0; margin: 0; }
/* The label column is as wide in every row (each row is its own grid), wide enough for most service names; a name
   longer than it breaks only where it must. On a phone the name sits above its bar. */
.bars a { display: grid; grid-template-columns: minmax(12ch, 26ch) 1fr 7ch; align-items: center; gap: var(--space-3); padding: var(--space-1) 0; color: var(--text); text-decoration: none; }
.bars .bar-label { color: var(--link); }
.bars a:hover .bar-label { text-decoration: underline; }
.bar-label { overflow-wrap: break-word; min-width: 0; }
@media (max-width: 480px) {
  .bars a { grid-template-columns: 1fr 7ch; row-gap: 2px; }
  .bars .bar-label { grid-column: 1 / -1; }
}
.bar-value { text-align: right; font-variant-numeric: tabular-nums; color: var(--text-strong); }
meter.bar { width: 100%; height: 8px; }
meter.bar::-webkit-meter-bar { background: var(--surface-3); border: 0; border-radius: 999px; }
meter.bar::-webkit-meter-optimum-value { background: var(--accent); border-radius: 999px; }
meter.bar::-moz-meter-bar { background: var(--accent); }

/* Inventory */
.inventory { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-2); align-items: start; }
.filters { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-4); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); }
.filters .field select, .filters .field input:not([type=radio]):not([type=checkbox]) { width: 100%; }
.add-column { margin-top: var(--space-4); }
#type-field:not(:has(select)) { margin: 0; }
.filters-panel { min-width: 0; margin: 0; }
/* Opened, the inventory's filters lay out in columns rather than one tall column. */
.filters-panel form.filters:not(.add-column) { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); column-gap: var(--space-4); }
.filters-panel form.filters:not(.add-column) > :is(.actions, fieldset) { grid-column: 1 / -1; }
.filters-panel fieldset.field { flex-direction: row; flex-wrap: wrap; align-items: center; column-gap: var(--space-4); }
.filters-panel fieldset.field > :is(legend, .help) { flex-basis: 100%; }
.filters-panel fieldset.field > label.inline { margin: 0; }
.filters-panel .add-column { max-width: 30rem; padding-top: var(--space-4); border-top: 1px solid var(--border); }
.results { min-width: 0; }
.results-summary { font-size: var(--text-sm); color: var(--text-muted); margin-bottom: var(--space-2); }
.results-summary .error-text, .field .error-text { color: var(--error); }
.field .error-text { margin: var(--space-1) 0 0; }
#seen-fields { display: contents; } /* a wrapper only for its out-of-band refresh: its fields lay out as the form's own */
.filters input[aria-invalid="true"] { border-color: var(--error); box-shadow: inset 0 0 0 1px var(--error); }
/* Folded filters ({% filterfold %}, templates/_filter_fold.html; the inventory's panel too): one line, "Filters", that
   says how many apply and names each, so the data comes before a wall of controls. Closed until a filter applies. The
   names are chips of words (label: value), never colour alone; the line wraps rather than clip them. */
.filter-fold { margin: 0 0 var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); }
.filter-fold > summary {
  display: flex; align-items: center; gap: var(--space-2) var(--space-3); min-height: 44px; padding: var(--space-2) var(--space-4);
  list-style: none; cursor: pointer; border-radius: var(--radius); color: var(--text-strong);
}
.filter-fold > summary:hover { background: var(--hover); }
.filter-fold[open] > summary { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.filter-fold-line { display: contents; }
.filter-fold-title { font-weight: 600; }
.filter-fold-count { font-weight: 500; color: var(--text); margin-left: calc(-1 * var(--space-2)); }
.filter-fold-none { font-size: var(--text-sm); color: var(--text-muted); }
.filter-fold-applied { display: flex; flex-wrap: wrap; gap: var(--space-1); min-width: 0; font-size: var(--text-sm); }
.filter-fold-item { padding: 0 var(--space-2); border: 1px solid var(--chip-border); border-radius: var(--radius); background: var(--surface-2); color: var(--text); overflow-wrap: anywhere; }
.filter-fold-item strong { font-weight: 600; }
.filter-fold-body { padding: var(--space-4); border-top: 1px solid var(--border); }
.filter-fold-body > form, .filter-fold-body .inline-filters { margin-bottom: 0; }
.filter-fold-body .filters { border: 0; border-radius: 0; padding: 0; background: transparent; box-shadow: none; }
@media (forced-colors: active) { .filter-fold-item { border-color: CanvasText; } }

/* Sortable, filterable tables (workhorse_web/tables.py): a row of compact filters under the headings. */
.table-filters { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-2); }
.table-filter-errors { flex-basis: 100%; color: var(--error); font-size: var(--text-sm); }
.table-filter-errors ul { margin: 0; padding-left: var(--space-4); }
thead tr.filter-row [aria-invalid="true"] { border-color: var(--error); box-shadow: inset 0 0 0 1px var(--error); }
thead tr.filter-row td { padding: var(--space-1) var(--space-2) var(--space-2); background: transparent; border-bottom: 1px solid var(--border); }
thead tr.filter-row :is(input, select) { width: 100%; min-width: 4.5rem; min-height: 30px; padding: 2px var(--space-2); font-size: var(--text-sm); }
thead tr.filter-row input.filter-date { min-width: 7.5rem; }
thead tr.filter-row input.filter-text[placeholder] { min-width: 5.5rem; } /* a hint, like us-east-1, shows whole */
details.section > .table-filters { margin: 0 var(--space-4) var(--space-2); }
/* A badge in a cell wraps, so one long status doesn't set its column's width. */
td .badge { white-space: normal; align-items: first baseline; }
.table-wrap td.mono.wrap { min-width: 24ch; } /* an ARN keeps a readable line length when the table scrolls */
.table-wrap + p { margin-top: var(--space-3); }
.inline-filters { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); align-items: flex-end; margin: 0 0 var(--space-4); }
.inline-filters .field { margin: 0; }
.inline-filters .actions { margin: 0; }
/* A group of checkboxes among a page's filters is a row that wraps, under its legend, not a tall column beside them. */
.inline-filters > fieldset.field { flex: 1 1 100%; display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4); min-width: 0; }
.inline-filters > fieldset.field > label.inline { margin: 0; }
.nowrap { white-space: nowrap; }
/* A fact stated with its reason (Entry points): the state reads first, the reason below it in smaller type. */
td.fact { min-width: 18ch; }
.fact-why { display: block; font-size: var(--text-sm); color: var(--text-muted); }
tbody tr:hover .fact-why { color: var(--text); }
ul.columns { columns: 16rem; column-gap: var(--space-6); }
.export-links { font-size: var(--text-sm); color: var(--text-muted); margin: calc(-1 * var(--space-1)) 0 var(--space-2); }
.export-links:empty { display: none; }
#results[aria-busy="true"] { opacity: 0.6; transition: opacity 150ms ease-out; cursor: progress; }
/* Load more says it's loading while its request is out (htmx sets htmx-request, and removes it however it ends). */
#more-row .button.htmx-request { opacity: 0.6; cursor: progress; }
.more-busy { display: none; }
#more-row .htmx-request > .more-idle { display: none; }
#more-row .htmx-request > .more-busy { display: inline; }
.tag-filters { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0 0 var(--space-2); padding: 0; }
.tag-filters .chip { display: inline-flex; align-items: center; gap: var(--space-1); }
/* The button keeps to the visible part of a table that scrolls sideways (on a phone it was off to the right). */
#more-row .button { position: sticky; left: var(--space-3); }

/* Network: how completely each account was read (templates/network/). The banner is closed by default and its
   summary keeps the caveat visible; the symbol and words carry the state, the tint only repeats it. */
.read-banner { margin: 0 0 var(--space-6); border: 1px solid var(--border); border-left: 4px solid var(--warn); border-radius: var(--radius); background: var(--warn-bg); color: var(--text-strong); }
.read-banner > summary { display: flex; align-items: baseline; gap: var(--space-2); padding: var(--space-3) var(--space-4); cursor: pointer; list-style: none; }
.read-banner > summary::-webkit-details-marker { display: none; }
.read-banner-mark { font-weight: 700; }
.read-banner-open { margin-left: var(--space-1); text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; }
.read-banner[open] .read-banner-open { text-decoration: none; }
.read-banner-body { display: grid; gap: var(--space-3); padding: 0 var(--space-4) var(--space-4); }
.read-banner-body caption { caption-side: top; text-align: left; padding: var(--space-2) var(--space-3); font-weight: 600; }
.read-reasons { font-size: var(--text-sm); }
.figure-note { display: block; font-size: var(--text-sm); font-weight: 400; color: var(--text-muted); }
.error-fold > summary { cursor: pointer; }
.error-fold[open] > summary { margin-bottom: var(--space-1); }
.verdict { max-width: 80ch; margin: 0 0 var(--space-6); padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.verdict p { margin: 0; color: var(--text-strong); }
.caveats { margin: var(--space-2) 0 0; padding-left: var(--space-4); font-size: var(--text-sm); color: var(--text-muted); }
/* Network rule pages (Security groups, Firewall rules): views as tabs, chips that each show one slice of a table with
   its count, and the lines that qualify the counts. The current tab and chip carry weight and a border, not colour
   alone. */
.view-tabs ul { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0 0 var(--space-4); padding: 0; border-bottom: 1px solid var(--border); }
.view-tabs a { display: inline-block; padding: var(--space-2) var(--space-3); color: var(--text); text-decoration: none; border-bottom: 3px solid transparent; margin-bottom: -1px; }
.view-tabs a:hover { color: var(--text-strong); text-decoration: underline; }
.view-tabs a[aria-current="page"] { color: var(--text-strong); font-weight: 600; border-bottom-color: var(--text-strong); }
.chip-row ul { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0 0 var(--space-3); padding: 0; }
.chip-row .chip { margin: 0; padding: 2px var(--space-2); font-size: var(--text-sm); }
.chip-row .chip[aria-current="true"] { border: 2px solid var(--text-strong); color: var(--text-strong); font-weight: 600; background: var(--surface-3); }
.chip-count { font-variant-numeric: tabular-nums; font-weight: 400; }
.warn-lines { list-style: none; margin: 0 0 var(--space-6); padding: 0; display: grid; gap: var(--space-1); max-width: 80ch; }
.coverage, .facts { max-width: 80ch; }
.basis { margin: 0 0 var(--space-6); }
.basis p { margin: 0 0 var(--space-1); }
.basis p:last-child { margin-bottom: 0; }
.read-statement { margin: 0 0 var(--space-6); max-width: 80ch; }
.read-statement h2 { font-size: var(--text-md); margin: 0 0 var(--space-2); }
.read-statement p { margin: 0 0 var(--space-1); }
.read-reasons-list { margin: var(--space-2) 0; padding-left: var(--space-4); }
.container-head { margin: 0 0 var(--space-4); max-width: 80ch; }
.container-head p { margin: 0 0 var(--space-1); }
.viz-twin { font-size: var(--text-sm); color: var(--text-muted); margin: var(--space-3) 0 0; }
/* A Network page's views, as tabs: links that keep the page's filters; the current one says so (aria-current). */
.views { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; padding: 0; margin: 0 0 var(--space-4); }
.views a { display: inline-block; padding: var(--space-1) var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); text-decoration: none; }
.views a[aria-current="page"] { font-weight: 600; color: var(--text-strong); border-color: var(--text-muted); background: var(--surface-2); }
/* Networks (templates/network/networks.html): its page filters' checkbox group, the account form's read
   statement, and the links from network detail to its other pages. */
.page-filters fieldset.field { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 0; }
.page-filters fieldset.field legend { flex-basis: 100%; margin-bottom: var(--space-1); }
.account-read { max-width: 80ch; margin: 0 0 var(--space-6); }
.related-links { margin-top: var(--space-3); display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
/* IP overlap (templates/network/overlap/): the lookup beside the enterprise ranges link, a cell's notes, the tree of
   networks using a range, and the address-space map: one shared axis per colliding range, one track per network,
   each range solid and the span another network also holds lined (45°, tone-on-tone with the range's own blue,
   step 700: 2.7:1 against the fill in light, 3.3:1 in dark), never colour alone. Marks take colour; text doesn't. */
.overlap-controls { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6); align-items: flex-end; margin: 0 0 var(--space-6); }
.overlap-controls .inline-filters { margin: 0; }
.note-line { display: block; }
.note-line + .note-line { margin-top: var(--space-1); }
.tree-depth { display: inline-block; }
.tree-depth-1 { margin-left: 1.25rem; } .tree-depth-2 { margin-left: 2.5rem; } .tree-depth-3 { margin-left: 3.75rem; }
.tree-depth-4 { margin-left: 5rem; } .tree-depth-5 { margin-left: 6.25rem; } .tree-depth-6 { margin-left: 7.5rem; }
.range-facts { max-width: 80ch; }
.space-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.space-lines-fill { fill: var(--viz-s1); }
.space-lines-ink { fill: #0d366b; }
rect.space-held { fill: var(--viz-s1); }
.space-key { display: inline-block; vertical-align: middle; }
.space-map + .space-map { margin-top: var(--space-6); padding-top: var(--space-4); border-top: 1px solid var(--border); }
.space-map-title { margin: 0 0 var(--space-2); font-size: var(--text-sm); color: var(--text); }
.space-map-title .mono { color: var(--text-strong); font-weight: 600; }
.space-axis-labels { display: flex; justify-content: space-between; gap: var(--space-2); font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.space-axis-labels > span { min-width: 0; overflow-wrap: anywhere; }
.space-axis-labels > span:last-child { text-align: right; }
.range-title { font-family: var(--mono); }
.range-title, .space-spans, .space-map-title { overflow-wrap: anywhere; } /* an IPv6 range is one long word */
.viz.space-maps { margin-bottom: var(--space-6); }
.space-rows .viz-row-value { max-width: 16rem; white-space: normal; overflow-wrap: anywhere; text-align: left; font-weight: 500; }
.space-place { display: block; font-size: 12px; font-weight: 400; color: var(--text-muted); }
.space-spans { margin: var(--space-3) 0 0; padding-left: var(--space-4); font-size: var(--text-sm); color: var(--text); }
.space-spans li + li { margin-top: var(--space-1); }
@media (max-width: 600px) {
  .space-rows .viz-row-value { max-width: 9rem; }
  /* The track labels take a row of their own here, so the axis row's empty label cell goes too: its addresses
     then sit over the tracks, not beside them. */
  .space-axis-pad { display: none; }
}
@media (forced-colors: active) {
  .space-defs rect, .space-key rect, .space-rows rect { forced-color-adjust: none; }
}

/* Upload */
.dropzone { border: 2px dashed var(--control-border); border-radius: var(--radius); padding: var(--space-6); background: var(--surface); }
.dropzone.is-over { border-color: var(--accent); background: var(--info-bg); }
.dropzone-hint { margin: 0; color: var(--text-muted); }
/* Drawn like the meters: an accent fill on a pill, not the browser's default blue. */
.upload-progress { width: 100%; height: 8px; margin-top: var(--space-3); appearance: none; border: 0; border-radius: 999px; background: var(--surface-3); }
.upload-progress::-webkit-progress-bar { background: var(--surface-3); border-radius: 999px; }
.upload-progress::-webkit-progress-value { background: var(--accent); border-radius: 999px; }
.upload-progress::-moz-progress-bar { background: var(--accent); border-radius: 999px; }
input[type=file]::file-selector-button {
  font: inherit; font-weight: 500; color: var(--text-strong); cursor: pointer; margin-right: var(--space-3);
  padding: 2px var(--space-3); border: 1px solid var(--button-border); border-radius: var(--radius); background: var(--surface-2);
}
input[type=file]::file-selector-button:hover { background: var(--surface-3); }
.package-status { padding: var(--space-4); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: var(--space-6); }

/* Resource configuration */
details.section { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: var(--space-3); }
details.section > summary { display: flex; align-items: baseline; gap: var(--space-2); padding: var(--space-3) var(--space-4); cursor: pointer; }
/* A flex summary loses the native triangle, so draw the state: a chevron pointing right when closed, down when open
   (screen readers already hear expanded or collapsed). */
details.section > summary::before, .filter-fold > summary::before {
  content: ""; flex: none; align-self: center; width: 7px; height: 7px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg);
}
details.section[open] > summary::before, .filter-fold[open] > summary::before { transform: rotate(45deg); }
details.section > summary::-webkit-details-marker { display: none; }
.filter-fold > summary::-webkit-details-marker { display: none; }
.menu[open] .caret { transform: rotate(180deg); }
details.section > summary h3 { display: inline; margin: 0; }
details.section > summary h2 { display: inline; margin: 0; font-size: var(--text-lg); }
details.section > .table-wrap { margin: 0 var(--space-4) var(--space-4); }
/* A badge that leads somewhere (a partial scan's) reads as a link. */
a.badge { text-decoration: underline; text-underline-offset: 2px; }
a.badge:hover { text-decoration-thickness: 2px; }
.pager { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; margin-top: var(--space-4); }
.error-text { font-size: var(--text-sm); }
details.section > .json, details.section > pre, details.section > .actions { padding: 0 var(--space-4) var(--space-4); margin: 0; }
.raw-json { overflow-x: auto; white-space: pre-wrap; overflow-wrap: anywhere; max-height: 70vh; }
.json { font-family: var(--mono); font-size: var(--text-sm); overflow-x: auto; }
.json-tree { list-style: none; margin: 0; padding-left: var(--space-4); border-left: 1px solid var(--border); }
.json > .json-tree { padding-left: 0; border-left: 0; }
.json-tree li { margin: 2px 0; }
.json-tree summary { cursor: pointer; }
.json-key { color: var(--text-strong); font-weight: 600; }
.json-str { color: var(--ok); overflow-wrap: anywhere; }
.json-num, .json-bool { color: var(--info); }
.json-null, .json-empty, .json-count { color: var(--text-muted); }
.json-leaf { overflow-wrap: anywhere; }
.read-errors .alert { margin-bottom: var(--space-2); }
/* Copy tools: float at the right of a node's line; shown on hover or focus; hidden without the script. */
.jt { display: inline-flex; gap: var(--space-1); opacity: 0; transition: opacity 150ms ease-out; }
.jt:focus-within { opacity: 1; }
.jt button { min-height: 24px; padding: 0 var(--space-2); font-size: var(--text-xs); font-weight: 500; box-shadow: none; }
.json-tree li > .jt { float: right; }
.json-tree li:has(> details > summary:hover) > .jt,
.json-tree li:has(> .json-leaf:hover) .jt,
.jt:hover { opacity: 1; }
/* With a mouse, a node's tools take no room in the text: they appear over the top right of its row. (On touch they
   stay in the flow, always shown.) */
@media (hover: hover) {
  .json-tree li { position: relative; }
  .json-tree .jt { position: absolute; top: -2px; right: 0; padding-left: var(--space-1); background: var(--surface); }
}
.section-tools { opacity: 1; display: flex; margin: 0 0 var(--space-2); }
html:not(.js) :is(.jt, button.copy) { display: none; } /* copying needs the script; without it the buttons did nothing */
button.copy { min-height: 24px; padding: 0 var(--space-2); font-size: var(--text-xs); font-weight: 500; box-shadow: none; }

/* Sign-in: a card with the brand, as in Unfold's login; no header above it. */
body.auth { background: var(--surface-2); }
body.auth .page-header { display: none; }
body.auth main { max-width: 440px; margin: var(--space-12) auto 0; }
.auth-card { background: var(--surface); border: 1px solid var(--border); border-radius: calc(var(--radius) * 2); padding: var(--space-8) var(--space-6); box-shadow: 0 1px 3px rgb(0 0 0 / 0.06); }
.auth-brand { display: flex; align-items: center; gap: var(--space-3); margin-bottom: var(--space-6); }
.auth-card .actions .button.primary { width: 100%; }
.card-title { font-size: var(--text-lg); margin: 0 0 var(--space-2); overflow-wrap: anywhere; }

/* Other pages without a tenant */
body:not(.with-sidebar) main { margin: 0 auto; }


/* Below 1024px the sidebar folds into a "Menu" disclosure above the page, its toggle on the brand row. The Menu holds
   everything but the brand: search, the account's controls (tenant, history, Defaults, theme, sign out; the header's
   copy is hidden) and the sections, so the page starts under one short bar. */
@media (max-width: 1023px) {
  .with-sidebar .shell { display: block; }
  .sidebar { position: relative; height: auto; overflow: visible; padding: var(--space-3) var(--space-4); border-right: 0; border-bottom: 1px solid var(--border); gap: var(--space-3); }
  .sidebar-version { display: none; }
  .sidebar .brand { margin-right: 112px; min-height: 44px; } /* clear of the toggle; a margin, so the link's focus ring stops short of it */
  .sidebar-toggle {
    position: absolute; top: var(--space-3); right: var(--space-4);
    display: flex; align-items: center; gap: var(--space-2); min-height: 44px; padding: var(--space-2) var(--space-3);
    list-style: none; cursor: pointer; font-weight: 600; color: var(--text-strong);
    border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface);
  }
  .sidebar-toggle::-webkit-details-marker { display: none; }
  /* Its icon says what pressing it does: open (the three lines), or close (a cross) while open. */
  .sidebar-disclosure[open] > .sidebar-toggle .sidebar-toggle-closed, .sidebar-disclosure:not([open]) > .sidebar-toggle .sidebar-toggle-open { display: none; }
  .sidebar-disclosure > :not(summary) + :not(summary) { margin-top: var(--space-3); }
  .nav-heading { min-height: 44px; }
  /* Closed, the Menu holds nothing in flow (its toggle sits on the brand row): drop its gap so the bar ends there. */
  .sidebar-disclosure:not([open]) { margin-top: calc(-1 * var(--space-3)); }
  .with-sidebar .page-header-end { display: none; }
  .menu-account {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2);
    padding: 0 0 var(--space-3); border-bottom: 1px solid var(--border);
  }
  .menu-account > form { margin: 0; }
  /* A menu opened inside the Menu unfolds in place, under its summary, the width of the Menu. */
  .menu-account .menu[open] { flex-basis: 100%; }
  .menu-account .menu > :is(ul, .menu-panel) { position: static; min-width: 0; margin-top: var(--space-1); box-shadow: none; }
  .menu-account .menu:not([open]) > :is(ul, .menu-panel) { display: none; } /* a closed one takes no room, laid out or not */
  .menu-account .as-of-pill { margin: 0; }
  /* With the account's controls in the Menu, a header that holds only a trail of one (the h1 repeats it) goes. */
  .with-sidebar .page-header:not(:has(.breadcrumbs li + li)) { display: none; }
  .page-header { min-height: 52px; }
}

@media (max-width: 800px) {
  main { padding: var(--space-4) var(--space-4) var(--space-12); }
  /* The header's tools wrap below the trail rather than squeeze it into broken words. */
  .page-header { padding: var(--space-2) var(--space-4); flex-wrap: wrap; row-gap: var(--space-1); }
  /* The wrapped header puts the menus too far left for their lists to hang to the left of their summaries; they hang
     from the header's right edge instead, still just below their summary. */
  .page-header-end { position: relative; }
  .page-header-end .menu { position: static; }
  .page-header-end .menu > :is(ul, .menu-panel) { left: 0; right: 0; }
  /* The h1 repeats the current page: on a phone the trail keeps just its parent link, and a trail of one goes. Under
     the Menu's bar that link is a slim "‹ Network" line just above the h1, not a bar of its own. */
  .breadcrumbs:not(:has(li + li)), .breadcrumbs li:not(:nth-last-child(2)), .breadcrumbs li:nth-last-child(2)::after { display: none; }
  .with-sidebar .page-header { min-height: 0; padding: var(--space-2) var(--space-4) 0; border-bottom: 0; }
  .with-sidebar .page-header:has(.breadcrumbs li + li) + main { padding-top: var(--space-2); }
  .with-sidebar .breadcrumbs a { display: inline-flex; align-items: center; min-height: 24px; }
  .with-sidebar .breadcrumbs li:nth-last-child(2)::before {
    content: ""; display: inline-block; flex: none; width: 6px; height: 6px; margin: 0 8px 0 2px;
    border-bottom: 1.5px solid currentColor; border-left: 1.5px solid currentColor; transform: rotate(45deg); opacity: 0.7;
  }
  .meta { grid-template-columns: 1fr; gap: 0; }
  .meta dd { margin-bottom: var(--space-3); }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

@media (hover: none) {
  .jt { opacity: 1; }
}

/* Windows High Contrast / forced colours: backgrounds are dropped, so give shapes a border and mark the
   current page by more than a background. */
@media (forced-colors: active) {
  .badge, .alert, .message, .error-summary, .card, .button.primary, .brand-symbol, .read-banner { border: 1px solid CanvasText; }
  .nav-list a[aria-current] { text-decoration: underline; text-decoration-thickness: 2px; }
  .tip { outline: 1px solid CanvasText; }
  .upload-progress { forced-color-adjust: none; border: 1px solid CanvasText; background: Canvas; }
  .upload-progress::-webkit-progress-bar { background: Canvas; }
  .upload-progress::-webkit-progress-value { background: Highlight; }
}
@media (forced-colors: active) {
  .upload-progress::-moz-progress-bar { background: Highlight; }
}
@media (forced-colors: active) and (min-width: 1024px) {
  .sidebar-collapsed :is(.nav-label, .brand-text) { outline: 1px solid CanvasText; } /* the rail's labels are tips */
}


/* Charts. Series slots 1-3 validated (all pairs, CVD and normal vision) against this app's own surfaces:
   white in light, Unfold base-900 in dark; slot 3's sub-3:1 contrast on white is relieved by direct labels
   and the table twin. Status colours are fixed across themes and always ship with a symbol and a label.
   Marks take colour; text always wears the text tokens. */
:root {
  --viz-s1: #2a78d6; --viz-s2: #eb6834; --viz-s3: #1baf7a;
  /* Amber at 3.4:1 on white (WCAG 1.4.11); the brighter #fab219 is kept for dark, 9.7:1 on base-900. */
  --viz-good: #0ca30c; --viz-warning: #c47a00; --viz-critical: #d03b3b;
  --viz-grid: var(--color-base-200); --viz-other: var(--color-base-500);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --viz-s1: #3987e5; --viz-s2: #d95926; --viz-s3: #199e70; --viz-grid: var(--color-base-800); --viz-other: var(--color-base-400); --viz-warning: #fab219; }
}
:root[data-theme="dark"] { --viz-s1: #3987e5; --viz-s2: #d95926; --viz-s3: #199e70; --viz-grid: var(--color-base-800); --viz-other: var(--color-base-400); --viz-warning: #fab219; }

.kpis { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); }
.kpi { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-4); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); }
.kpi p { margin: 0; }
.kpi-label { font-size: var(--text-sm); color: var(--text-muted); font-weight: 500; }
.kpi-value { font-size: 28px; line-height: 1.2; font-weight: 600; color: var(--text-strong); margin: var(--space-1) 0 !important; }
.kpi-hero .kpi-value { font-size: clamp(32px, 11vw, 48px); line-height: 1.05; letter-spacing: -0.02em; overflow-wrap: anywhere; }
.kpi-note { font-size: var(--text-sm); color: var(--text-muted); }

.viz-grid { display: grid; gap: var(--space-6); grid-template-columns: repeat(auto-fit, minmax(min(480px, 100%), 1fr)); margin-top: var(--space-6); align-items: start; }
.viz-wide { grid-column: 1 / -1; }
.dash-note { margin-top: var(--space-6); } /* a note about the page, not a caption of the chart above it */
.viz-grid > .viz:has(> details.viz-table[open]) { grid-column: 1 / -1; } /* an opened table gets the full width */
.viz { container-type: inline-size; margin: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-4) var(--space-4) var(--space-3); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); min-width: 0; }
.viz figcaption h2 { margin: 0 0 var(--space-1); font-size: var(--text-lg); }
.viz-desc { color: var(--text-muted); font-size: var(--text-sm); margin: 0 0 var(--space-4); max-width: 70ch; }
.viz svg { display: block; overflow: visible; font-family: var(--font); }

/* Rows of bars: label, track, value. A subgrid lines every row's columns up, so tracks share one length. */
.viz-rows { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content; gap: var(--space-2) var(--space-3); align-items: center; }
.viz-rows > li { display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; align-items: center; }
.viz-row-label { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; font-size: var(--text-sm); color: var(--link); text-decoration: none; }
.viz-row-label:hover { text-decoration: underline; }
.viz-row-value { text-align: right; font-size: var(--text-sm); font-weight: 600; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.viz-track { width: 100%; }

/* A line chart: y-axis labels, the plot, end labels; three columns at one height. */
.viz-line-chart { display: grid; grid-template-columns: 44px minmax(0, 1fr) 136px; column-gap: var(--space-3); }
.viz-y, .viz-ends, .viz-plot { width: 100%; }
.viz-axis { fill: var(--text-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.viz-value { fill: var(--text-strong); font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
.viz-end-name { fill: var(--text-muted); font-weight: 500; }
.viz-grid-line { stroke: var(--viz-grid); stroke-width: 1; }

/* Marks take colour; text never does. */
.viz-inside { font-size: 12px; font-weight: 600; pointer-events: none; }
.viz-ink-dark { fill: #0b0b0b; }
.viz-ink-light { fill: #fff; }
.viz-gap { stroke: var(--surface); stroke-width: 2; }
rect.viz-s1, circle.viz-s1 { fill: var(--viz-s1); }
rect.viz-s2, circle.viz-s2 { fill: var(--viz-s2); }
rect.viz-s3, circle.viz-s3 { fill: var(--viz-s3); }
rect.viz-other { fill: var(--viz-other); }
rect.viz-good { fill: var(--viz-good); } rect.viz-warning { fill: var(--viz-warning); }
rect.viz-critical { fill: var(--viz-critical); }
.viz-line { stroke-width: 2; stroke-linecap: round; }
.viz-line.viz-s1 { stroke: var(--viz-s1); } .viz-line.viz-s2 { stroke: var(--viz-s2); } .viz-line.viz-s3 { stroke: var(--viz-s3); }
.viz-dot { stroke: var(--surface); stroke-width: 2; }
.viz-dot:hover { stroke: var(--text-strong); }
.viz-legend { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); margin: 0 0 var(--space-3); padding: 0; font-size: var(--text-sm); color: var(--text); }
.viz-legend li { display: inline-flex; align-items: center; gap: var(--space-1); }
.viz-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; }
.viz-swatch.viz-good { background: var(--viz-good); } .viz-swatch.viz-warning { background: var(--viz-warning); }
.viz-swatch.viz-critical { background: var(--viz-critical); }
.viz-key { display: inline-block; width: 16px; height: 2px; border-radius: 1px; }
.viz-key.viz-s1 { background: var(--viz-s1); } .viz-key.viz-s2 { background: var(--viz-s2); } .viz-key.viz-s3 { background: var(--viz-s3); }
.viz-table > summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); margin-top: var(--space-3); width: fit-content; }
.viz-table table { margin-top: var(--space-2); }
.viz-table thead th { white-space: normal; }
.viz-table table.compact :is(th, td) { padding-left: var(--space-2); padding-right: var(--space-2); }
details.regions > summary { cursor: pointer; color: var(--link); width: fit-content; }
/* Labels inside bar segments need room: hide them on narrow figures (the value column and the table remain). */
@container (max-width: 479px) {
  .viz-inside { display: none; }
}
@media (max-width: 600px) {
  .viz-rows { grid-template-columns: minmax(0, 1fr) max-content; }
  .viz-row-label { grid-column: 1 / -1; max-width: none; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .viz-line-chart { grid-template-columns: 40px minmax(0, 1fr) 52px; column-gap: var(--space-2); }
  .viz-end-name { display: none; }
}
@media (forced-colors: active) {
  /* Keep the marks' colours (they carry identity and state, always with a label too); text follows the system. */
  .viz rect, .viz circle, .viz-line, .viz-gap, .viz-swatch, .viz-key { forced-color-adjust: none; }
}

/* Network overview (templates/network/overview.html). Flow-log coverage is an ordered scale (logged, in part, none), so
   its parts are steps of one hue, validated as an ordinal ramp against white and base-900: monotone, gaps visible,
   the faintest step 2.1:1 on white and 2.7:1 on base-900, and every value is in the table twin. "Unknown" is never a
   colour that could read as one more category: it is the same hatch in every chart, a pattern defined once on the
   page (.viz-defs), with its word in the legend or the bar's label. */
:root { --viz-o1: #1c5cab; --viz-o2: #3987e5; --viz-o3: #86b6ef; --viz-texture-ground: var(--color-base-100); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --viz-o1: #9ec5f4; --viz-o2: #3987e5; --viz-o3: #1c5cab; --viz-texture-ground: var(--color-base-800); }
}
:root[data-theme="dark"] { --viz-o1: #9ec5f4; --viz-o2: #3987e5; --viz-o3: #1c5cab; --viz-texture-ground: var(--color-base-800); }
.viz-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.viz-texture-ground { fill: var(--viz-texture-ground); }
.viz-texture-ink { stroke: var(--viz-other); stroke-width: 1.5; }
rect.viz-o1 { fill: var(--viz-o1); } rect.viz-o2 { fill: var(--viz-o2); } rect.viz-o3 { fill: var(--viz-o3); }
rect.viz-unknown { fill: url(#viz-texture); }
.viz-swatch.viz-o1 { background: var(--viz-o1); } .viz-swatch.viz-o2 { background: var(--viz-o2); }
.viz-swatch.viz-o3 { background: var(--viz-o3); }
.viz-swatch.viz-unknown { background: repeating-linear-gradient(135deg, var(--viz-other) 0 1.5px, var(--viz-texture-ground) 1.5px 4px); }
.viz-row-empty { font-size: var(--text-sm); color: var(--text-muted); }
.viz-note { font-size: var(--text-sm); color: var(--text-muted); margin: var(--space-3) 0 0; }
.overview-account { margin: var(--space-3) 0 0; }
/* An account picker shrinks to the screen: a long account name (display name and id) mustn't push the page sideways
   at 320px (WCAG 1.4.10). The Network overview's and the Discovery report's share the class. */
.page-head > div:has(> .overview-account) { min-width: 0; max-width: 100%; }
.overview-account .field { min-width: 0; max-width: 100%; }
.overview-account select { max-width: 100%; }
.charged { max-width: 80ch; margin: 0 0 var(--space-6); }
.looks-section { margin-top: var(--space-8); }
.looks-section h3 { font-size: var(--text-lg); margin: var(--space-6) 0 var(--space-3); }
.looks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); max-width: 80ch; }
.look p { margin: 0; }
.look-why, .look-note { margin-top: var(--space-1) !important; font-size: var(--text-sm); color: var(--text-muted); }
.checked { max-width: 80ch; margin: var(--space-6) 0 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); }
.checked p { margin: 0; color: var(--text-strong); }

/* Print: evidence on paper or PDF. Always the light palette, no interface chrome, rows and cards kept whole,
   and a line saying when, by whom and from where it was printed (base.html .print-meta). */
.print-meta { display: none; }
@media print {
  :root, :root[data-theme="dark"], :root:not([data-theme="light"]) {
    --text-xs: 12px; --text-sm: 13px; --text-md: 14px; --text-lg: 16px; --text-xl: 20px;
    --bg: #fff;
    --surface: #fff;
    --surface-2: var(--color-base-50);
    --surface-3: var(--color-base-100);
    --sidebar-bg: var(--color-base-50);
    --hover: var(--color-base-100);
    --chip-border: var(--color-base-200);
    --border: var(--color-base-200);
    --text: var(--color-font-default-light);
    --text-strong: var(--color-font-important-light);
    --text-muted: var(--color-font-subtle-light);
    --accent: var(--color-primary-600);
    --accent-strong: var(--color-primary-700);
    --accent-text: #fff;
    --link: var(--color-primary-700);
    --ok: #166534;    --ok-bg: #dcfce7;
    --warn: #854d0e;  --warn-bg: #fef9c3;
    --error: #b91c1c; --error-bg: #fee2e2;
    --info: var(--color-primary-700); --info-bg: var(--color-primary-50);
    --focus: var(--color-primary-600);
    --menu-bg: #fff; --menu-border: var(--color-base-200); --button-border: var(--color-base-200);
    --row-stripe: var(--color-base-50);
    --viz-s1: #2a78d6; --viz-s2: #eb6834; --viz-s3: #1baf7a; --viz-grid: var(--color-base-200); --viz-other: var(--color-base-500);
    --viz-o1: #1c5cab; --viz-o2: #3987e5; --viz-o3: #86b6ef; --viz-texture-ground: var(--color-base-100);
    color-scheme: light;
  }
  @page { margin: 14mm 12mm; }
  body { background: #fff; font-size: 11pt; }
  .sidebar, .sidebar-collapse, .defaults-toggle, .page-header-end, .skip-link, .filter-fold-body, .add-column, .actions, .jt, .section-tools, #more-row,
  button.copy, .remove-col, .menu, .results-summary:empty, .dropzone, .upload-form, .export-links { display: none !important; }
  .viz { break-inside: avoid; }
  .viz figcaption { break-after: avoid; }
  .viz-table > summary { display: none; }
  th.mono, td.mono { overflow-wrap: anywhere; }
  details.section > summary::before { display: none; }
  .with-sidebar .shell { display: block; }
  .page-header { min-height: 0; padding: 0 0 var(--space-2); border-bottom: 1px solid var(--border); }
  main { max-width: none; padding: var(--space-4) 0 0; }
  .print-brand { display: flex; align-items: center; gap: var(--space-3); margin: 0 0 var(--space-3); }
  .print-brand img { height: 32px; width: auto; }
  .print-brand p { margin: 0; font-size: 10pt; }
  .brand-footer { padding: var(--space-2) 0 0; font-size: 8pt; }
  .print-meta { display: block; font-size: 9pt; color: var(--text-muted); margin: 0 0 var(--space-4); }
  a { color: inherit; text-decoration: none; }
  .table-wrap { overflow: visible; box-shadow: none; }
  .card, .table-wrap, .filters, details.section { box-shadow: none; }
  tr, .card, .alert, .error-summary, details.section > summary, .kpi, .viz-rows > li, .viz-line-chart, .viz-legend { break-inside: avoid; }
  .kpi, .viz { box-shadow: none; }
  thead { display: table-header-group; }
  h1, h2, h3 { break-after: avoid; }
  .inventory { display: block; }
  .two-col { display: block; }
  .two-col > section + section { margin-top: var(--space-6); }
  /* A4 is narrower than the phone breakpoint; keep the detail lists in two columns on paper. */
  .meta { grid-template-columns: max-content 1fr; gap: var(--space-1) var(--space-6); }
  .meta dd { margin-bottom: 0; }
}

/* Network maps (templates/network/maps/, workhorse_web/network/maps/): pictures drawn at fixed pixel coordinates in a
   focusable, named .figure-wrap that scrolls sideways (design §5.9; rule 12 allows it beside .table-wrap). Boxes are
   surfaces with a hairline edge; marks and lines take the categorical slots for the three targets a reader looks for
   (internet gateway, NAT gateway, firewall endpoint: --viz-s1..3, validated all-pairs in both themes), every other
   target the neutral mark and its word; unknown is a hatch, never a colour; a part not read is dashed and says so.
   Text wears text tokens, at 4.5:1 or more on every fill here (muted text stays off the marker's darker fill). Every
   box is a link; focus and hover draw its edge in the focus colour. */
:root { --map-edge: var(--color-base-400); --map-band: var(--color-base-50); --map-marker: var(--color-base-100); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --map-edge: var(--color-base-600); --map-band: color-mix(in srgb, var(--color-base-800) 55%, var(--color-base-900)); --map-marker: var(--color-base-800); }
}
:root[data-theme="dark"] { --map-edge: var(--color-base-600); --map-band: color-mix(in srgb, var(--color-base-800) 55%, var(--color-base-900)); --map-marker: var(--color-base-800); }

.map { margin: 0; }
.map figcaption h2 { margin-bottom: var(--space-1); }
.map .viz-desc { margin-bottom: var(--space-2); }
.map-note strong { color: var(--text-strong); font-weight: 600; }
.figure-wrap { position: relative; overflow-x: auto; margin-top: var(--space-2); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04); }
.figure-wrap:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.figure-wrap a { scroll-margin: var(--space-4); } /* a box scrolled into view keeps room for its focus edge */
.map-svg { display: block; overflow: visible; font-family: var(--font); }
.map-svg text { font-size: 12px; fill: var(--text); }
.map-svg .map-name { font-size: 13px; font-weight: 600; fill: var(--text-strong); }
.map-svg .map-kind { font-weight: 600; fill: var(--text-strong); }
.map-svg .map-muted { fill: var(--text-muted); }
.map-svg .map-mono { font-family: var(--mono); }
.map-svg .map-link-text { fill: var(--link); text-decoration: underline; }

.map-group-row { fill: var(--surface); }
.map-group-row.map-band-even { fill: var(--map-band); }
.map-group-org { fill: none; stroke: var(--map-edge); stroke-width: 1; }
.map-group-account { fill: var(--map-band); }
.map-group.map-unread, .map-box.map-unread { stroke: var(--text-muted); stroke-width: 1.5; stroke-dasharray: 6 4; }
.map-box { fill: var(--surface); stroke: var(--map-edge); stroke-width: 1; }
.map-box.map-unread { fill: none; }
.map-box-marker { fill: var(--map-marker); }
.map-box-empty { fill: none; stroke: var(--border); }
.map-box.map-edge-k1, .map-box.map-edge-k2, .map-box.map-edge-k3 { stroke-width: 1.5; }
.map-box.map-edge-k1 { stroke: var(--viz-s1); } .map-box.map-edge-k2 { stroke: var(--viz-s2); } .map-box.map-edge-k3 { stroke: var(--viz-s3); }

/* Marks: a <use> sets the colour, the symbol's shapes fill or stroke with it (templates/network/maps/_defs.html). */
.map-k1 { color: var(--viz-s1); } .map-k2 { color: var(--viz-s2); } .map-k3 { color: var(--viz-s3); }
.map-other { color: var(--viz-other); } .map-none, .map-unknown { color: var(--text-muted); } .map-ink { color: var(--text-strong); }
.map-shape { fill: currentColor; }
.map-ring { fill: none; stroke: currentColor; stroke-width: 1.5; }
.map-cross { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.map-hatch-box { fill: url(#map-hatch); stroke: currentColor; stroke-width: 1; }
.map-hatch-line { stroke: var(--text-muted); stroke-width: 1.5; }
.map-meter-track { fill: var(--surface-3); }
.map-meter-fill { fill: var(--text-muted); }
.map-line { fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.map-pill { fill: var(--surface-2); stroke: var(--map-edge); stroke-width: 1; }
.map-svg .map-pill-text { font-size: 11px; font-weight: 500; fill: var(--text-strong); }

/* Links: the box (or the heading, or the count) is the target; focus and hover show on its edge. */
.map-hit { fill: transparent; }
a.map-node:focus-visible, a.map-head:focus-visible, a.map-sublink:focus-visible { outline: none; }
a.map-node:hover .map-box, a.map-node:focus-visible .map-box { stroke: var(--focus); stroke-width: 2.5; }
a.map-head:hover .map-hit, a.map-head:focus-visible .map-hit,
a.map-sublink:hover .map-hit, a.map-sublink:focus-visible .map-hit { stroke: var(--focus); stroke-width: 2; }
a.map-node:hover .map-name, a.map-head:hover .map-name { text-decoration: underline; }

/* Network detail's attributes hold long unbroken words (route53resolver/ListResolverQueryLogConfigAssociations), which
   break anywhere rather than push the page sideways at 320px. */
.meta dd { overflow-wrap: anywhere; }
.map-legend { margin: var(--space-2) 0 0; }
.map-legend-mark { flex: none; overflow: visible; }
.map-totals { margin: 0 0 var(--space-3); padding-left: var(--space-4); }
.map-totals li { margin-bottom: var(--space-1); }
.map-downloads { font-size: var(--text-sm); margin: var(--space-2) 0 var(--space-3); }

@media (forced-colors: active) {
  .map-svg use, .map-svg .map-line, .map-legend use, .map-legend line, .map-meter-fill { forced-color-adjust: none; }
  .map-box, .map-group-org { stroke: CanvasText; }
  .map-svg text { fill: CanvasText; }
  .map-svg .map-link-text { fill: LinkText; }
}

@media print {
  :root, :root[data-theme="dark"], :root:not([data-theme="light"]) { --map-edge: var(--color-base-400); --map-band: var(--color-base-50); --map-marker: var(--color-base-100); }
  .map { break-inside: avoid; }
  .figure-wrap { overflow: visible; border: 0; box-shadow: none; }
  .map-svg { max-width: 100%; height: auto; } /* the viewBox scales a wide map down to the page */
  .map-downloads { display: none; }
}

/* Discovery report (templates/discovery/): a document an integration team reads top to bottom. Each section is its
   question, its headline figures as quiet tiles, its charts (the dashboard's marks, .viz-*), its findings in
   sentences and the small print of what was read. No tables. A finding's tone is an icon and a word, tinted with the
   badge tokens; tones say what a finding is, never how bad, so nothing here is red. Status parts of a chart keep
   their symbol in the legend, "unknown" is hatched (a second unknown part takes the 135° mirror), and "All accounts"
   on a line chart is the strong ink, heavier, never a series colour. */
.disc-head h1 { font-size: 24px; letter-spacing: -0.015em; }
.disc-account { margin-top: var(--space-4); }
.disc-unread { margin: 0 0 var(--space-6); }
.disc-unread p { margin: 0; }
.disc-contents { margin: 0 0 var(--space-8); }
.disc-contents h2 { margin: 0 0 var(--space-2); font-size: var(--text-sm); font-weight: 600; color: var(--text-muted); }
.disc-contents ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.disc-contents a {
  display: inline-flex; align-items: center; gap: var(--space-2); min-height: 40px; padding: var(--space-1) var(--space-3);
  border: 1px solid var(--chip-border); border-radius: 999px; background: var(--surface);
  color: var(--text-strong); font-weight: 500; text-decoration: none;
}
.disc-contents a:hover { background: var(--hover); border-color: var(--control-border); }
.disc-contents-note { display: inline-flex; align-items: center; gap: 2px; font-size: var(--text-xs); font-weight: 600; color: var(--warn); font-variant-numeric: tabular-nums; }
.disc-contents-note .material-symbols-outlined { font-size: 16px; }
.disc-contents-note.is-quiet { color: var(--text-muted); font-weight: 500; }

.disc-section { margin-top: var(--space-12); padding-top: var(--space-8); border-top: 1px solid var(--border); scroll-margin-top: var(--space-4); }
.disc-contents + .viz-defs + .disc-section { margin-top: 0; }
.disc-section-head { margin: 0 0 var(--space-6); }
.disc-section-head h2 { margin: 0 0 var(--space-2); font-size: var(--text-xl); letter-spacing: -0.01em; }
.disc-section-head .lede { margin: 0; }
.disc-section-link { margin: var(--space-2) 0 0; max-width: 70ch; font-size: var(--text-sm); color: var(--text-muted); }
.disc-section-link a { font-weight: 500; }

/* Headline figures: the value is what's read, the label names it, the note qualifies it. A tile is as wide as its
   value needs ("38.0 TiB of 39.9 TiB" on one line) and the row shares out the rest; labels and notes wrap inside
   rather than widen it. */
.disc-figures { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: 0 0 var(--space-6); }
.disc-figure { flex: 1 1 auto; min-width: min(10rem, 100%); max-width: 100%; padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--surface-2); }
.disc-figure dt, .disc-figure-note { contain: inline-size; }
.disc-figure dt { font-size: var(--text-sm); font-weight: 500; color: var(--text-muted); }
.disc-figure dd { margin: 0; }
.disc-figure-value { margin: var(--space-1) 0 0 !important; font-size: 24px; line-height: 1.2; font-weight: 600; color: var(--text-strong); overflow-wrap: anywhere; }
.disc-figure-value a { color: inherit; text-decoration-color: var(--link); text-underline-offset: 4px; }
.disc-figure-value a:hover { color: var(--link); }
.disc-figure.is-muted .disc-figure-value { color: var(--text-muted); font-weight: 500; }
.disc-figure-note { margin-top: var(--space-1) !important; font-size: var(--text-sm); color: var(--text-muted); }
/* A note of two parts (what it breaks into, then how much was read) is two lines in a tile. */
.disc-figure-note .figure-note-line { display: block; }
.disc-figure-value.disc-figure-badge { font-size: var(--text-md); align-self: center; }
/* Notes too long for a tile ({% figurenote %}) read under the row, each after its figure's name, so no tile holds a
   paragraph and stretches its row. */
.figure-notes { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: grid; gap: var(--space-1); max-width: 80ch; font-size: var(--text-sm); color: var(--text-muted); }
.figure-notes-label { font-weight: 600; color: var(--text); }
.figure-notes .figure-note-line + .figure-note-line::before { content: "; "; }

/* Charts: two to a row on a wide screen; a line, or a chart left alone in its row, takes the row. */
.disc-charts { margin: 0; }
.disc-chart figcaption h3 { margin: 0 0 var(--space-1); font-size: var(--text-lg); }
span.viz-row-label { color: var(--text); }
.disc-rows .is-muted .viz-row-label { color: var(--text-muted); }
.disc-rows .is-muted .viz-row-value { color: var(--text-muted); font-weight: 500; }
.disc-rows-long .viz-row-value { max-width: 14rem; white-space: normal; text-align: left; font-weight: 500; }
rect.viz-rail { fill: var(--viz-grid); }
rect.viz-unknown-alt { fill: url(#viz-texture-alt); }
.viz-swatch.viz-s1 { background: var(--viz-s1); } .viz-swatch.viz-s2 { background: var(--viz-s2); } .viz-swatch.viz-s3 { background: var(--viz-s3); }
.viz-swatch.viz-other { background: var(--viz-other); }
.viz-swatch.viz-unknown-alt { background: repeating-linear-gradient(45deg, var(--viz-other) 0 1.5px, var(--viz-texture-ground) 1.5px 4px); }
.disc-mark { font-weight: 700; color: var(--text-strong); }
.disc-inside { font-size: 12px; font-weight: 700; pointer-events: none; }
/* A chart that takes the row keeps its bars to a readable length, and its labels room to be whole. */
.disc-chart.viz-wide .disc-rows { max-width: 60rem; }
.disc-chart.viz-wide .viz-row-label { max-width: 20rem; }
.disc-scale-ticks { display: flex; justify-content: space-between; font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.disc-line { grid-template-columns: 52px minmax(0, 1fr) minmax(0, 13rem); }
.viz-line.viz-total { stroke: var(--text-strong); stroke-width: 3; }
circle.viz-total { fill: var(--text-strong); }
.viz-key.viz-total { height: 3px; background: var(--text-strong); }
.viz-end-name.is-total { fill: var(--text-strong); font-weight: 600; }
.disc-words > summary { margin-top: var(--space-4); }
.disc-words-list { margin: var(--space-2) 0 0; padding-left: var(--space-4); font-size: var(--text-sm); color: var(--text); max-width: 80ch; }
.disc-words-list li + li { margin-top: var(--space-1); }
@container (max-width: 599px) {
  .disc-line { grid-template-columns: 44px minmax(0, 1fr) 60px; column-gap: var(--space-2); }
  .disc-line .viz-end-name { display: none; }
}
@media (max-width: 600px) {
  .disc-rows-long .viz-row-value { max-width: 10rem; }
  /* Labels take a row of their own here, so the scale's empty label cell goes and its ticks sit under the tracks. */
  .disc-scale > span:first-child { display: none; }
}

/* Findings: worth a look, then worth knowing, then clear. The sentence leads; why it matters follows, quieter. */
.disc-findings { margin-top: var(--space-8); max-width: 80ch; }
.disc-findings h3 { margin: 0 0 var(--space-4); font-size: var(--text-lg); }
.disc-findings ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }
.disc-finding { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: var(--space-3); align-items: start; }
.disc-finding p { margin: 0; }
.disc-finding-sentence { padding-top: 2px; font-weight: 500; color: var(--text-strong); overflow-wrap: anywhere; }
.disc-finding-why { margin-top: var(--space-1) !important; font-size: var(--text-sm); color: var(--text-muted); }
.disc-tone-icon { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 24px; height: 24px; border-radius: 999px; background: var(--surface-3); color: var(--text-strong); }
.disc-tone-icon .material-symbols-outlined { font-size: 16px; }
.disc-tone-attention .disc-tone-icon { background: var(--warn-bg); color: var(--warn); }
.disc-tone-info .disc-tone-icon { background: var(--info-bg); color: var(--info); }
.disc-tone-clear .disc-tone-icon { background: var(--ok-bg); color: var(--ok); }
/* The tone's word: read aloud and printed; on screen the icon carries it, and the list's order says it again. */
.disc-tone-word { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* A section with nothing measured says why, in the space its figures would take. */
.disc-state { display: flex; align-items: flex-start; gap: var(--space-3); max-width: 80ch; padding: var(--space-4); border: 1px dashed var(--control-border); border-radius: var(--radius); background: var(--surface); }
.disc-state > .material-symbols-outlined { color: var(--text-muted); }
.disc-state p { margin: 0; }
.disc-state-title { font-weight: 600; color: var(--text-strong); margin-bottom: var(--space-1) !important; }
.disc-coverage { margin: var(--space-6) 0 0; max-width: 80ch; font-size: var(--text-sm); color: var(--text-muted); }

/* A finding's drill-down: its tone and section above the sentence, and the way back to the report. */
.disc-eyebrow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-2) !important; font-size: var(--text-sm); font-weight: 500; color: var(--text-muted); }
.disc-back { margin-top: var(--space-3) !important; }
.disc-back a { display: inline-flex; align-items: center; gap: var(--space-1); font-weight: 500; }
.disc-back .material-symbols-outlined { font-size: 18px; }

@media (forced-colors: active) {
  .disc-tone-icon, .disc-figure { border: 1px solid CanvasText; }
  .viz-swatch.viz-s1, .viz-swatch.viz-s2, .viz-swatch.viz-s3, .viz-swatch.viz-other, .viz-swatch.viz-unknown-alt, .viz-key.viz-total { forced-color-adjust: none; }
}

@media print {
  .disc-contents, .disc-account, .disc-words, .disc-back { display: none !important; }
  .disc-section { margin-top: var(--space-8); padding-top: var(--space-6); }
  .disc-section-head, .disc-findings h3 { break-after: avoid; }
  .disc-figures, .disc-figure, .disc-finding, .disc-state { break-inside: avoid; }
  .disc-figure { background: none; border: 1px solid var(--border); }
  .disc-figure-value a { text-decoration: none; }
  /* On paper the icon's tint may not print, so the tone's word shows before each sentence. */
  .disc-tone-word { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; white-space: normal; font-weight: 700; }
  .disc-tone-icon { border: 1px solid currentColor; }
  /* Legend swatches and line keys are backgrounds, which print drops by default: without them a legend is words
     with nothing to match. */
  .disc-chart :is(.viz-swatch, .viz-key) { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}

/* Identity: principals and their policies explained (templates/identity/, IAM principals design §4, §5). */
.identity-page .report-head h1 { overflow-wrap: anywhere; } /* a role name can be one long word */
.principal-summary { max-width: 80ch; margin: 0 0 var(--space-6); color: var(--text-strong); }
.policy-cards { display: grid; gap: var(--space-4); margin: 0 0 var(--space-6); }
.policy-head { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-3); align-items: baseline; }
.policy-head h3, .policy-head p { margin: 0; }
.policy-description { margin: var(--space-2) 0; max-width: 80ch; }
.policy-summary { margin: var(--space-3) 0 var(--space-2); font-weight: 600; color: var(--text-strong); }
ol.statements { margin: 0 0 var(--space-3); padding-left: var(--space-6); max-width: 100ch; }
ol.statements > li, ul.statements > li { margin: 0 0 var(--space-2); overflow-wrap: anywhere; }
ul.statements { max-width: 100ch; }
details.which { margin-top: var(--space-1); font-size: var(--text-sm); }
details.which ul { margin: var(--space-1) 0 0; }
.policy-caveat, .json-note { font-size: var(--text-sm); max-width: 80ch; }
details.policy-json { margin-top: var(--space-3); }
details.policy-json > summary { cursor: pointer; font-weight: 600; }
.json-tools { margin-top: var(--space-2); }
pre.policy-json-text { margin: var(--space-2) 0 0; padding: var(--space-3); white-space: pre-wrap; overflow-wrap: anywhere;
  font-family: var(--mono); font-size: var(--text-sm); background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); }
ul.group-list li, ul.never-used li { margin-bottom: var(--space-1); }
ul.never-used { columns: 22rem; column-gap: var(--space-6); }
ul.never-used li { break-inside: avoid; }
.role-meta { margin-top: var(--space-4); }
/* The tree's copy tools aren't part of the data: copying a subtree leaves their labels out. */
.jt, .section-tools { -webkit-user-select: none; user-select: none; }

/* Relationship maps (templates/relationships/_connected*.html, workhorse_web/diagrams/neighbourhood.py): "Connected to"
   on every resource's page, under the rules in "Network maps". The resource whose page it is sits in the middle with
   the heaviest edge; what it connects to and what connects to it are the maps' plain boxes; a party (an account, an
   identity provider, an AWS service, everyone) is shaded with a muted edge, so it reads apart from a resource by
   more than colour, and says what it is in words; a box not read or not found is the maps' dashed outline with its
   reason. Lines are neutral, as the tree's, a step lighter than a map's routes, and end in an arrow at what is named
   (the marker is in _connected_legend.html). A column's heading is quieter than its kinds' headings. On a wide screen
   the diagram shows above its table without a disclosure; on a phone, where it would scroll, it waits behind "Show
   the diagram" and the table leads. */
.connected { margin-bottom: var(--space-8); }
.connected-lede { font-size: var(--text-lg); color: var(--text-strong); margin-bottom: var(--space-1); max-width: 80ch; }
.connected-desc, .connected-help { color: var(--text-muted); font-size: var(--text-sm); max-width: 80ch; }
.connected-note { max-width: 80ch; }
.connected-note p { margin-bottom: var(--space-1); }
.connected-note ul { margin: 0 0 var(--space-3); padding-left: var(--space-6); }
.connected-note li { margin-bottom: var(--space-1); }
.connected h3 { margin-top: var(--space-6); }
.connected-figure { margin: var(--space-4) 0; }
.connected-figure > summary { cursor: pointer; color: var(--link); font-weight: 500; width: fit-content; padding: var(--space-3) 0; }
.connected-figure > summary:hover { text-decoration: underline; }
.connected-figure[open] .connected-show, .connected-figure:not([open]) .connected-hide { display: none; }
.connected-map figcaption { margin-bottom: var(--space-2); }
.connected-map .map-svg { margin: 0 auto; } /* centred in its region while it fits; scrolled from its start when not */
.connected-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.connected-legend .badge { font-size: var(--text-xs); }
.connected-table .cell-direction { white-space: nowrap; }
.connected-table .connected-id { word-break: break-all; } /* an id breaks where the line ends, not after "i-" */
.connected-table .cell-path { min-width: 24ch; }
.connected-table .cell-path .mono { overflow-wrap: anywhere; } /* it breaks between steps first (<wbr>) */
ul.connected-matches { margin: var(--space-1) 0 0; padding: 0; list-style: none; }
ul.connected-matches li { margin-bottom: var(--space-1); }
.connected-depth { margin-top: var(--space-4); }
.connected-ring h3 { margin-top: var(--space-6); }

.map-svg .map-side { font-size: 12px; font-weight: 600; fill: var(--text-muted); letter-spacing: 0.02em; }
.map-group-side, .map-group-kind, .map-group-focus { fill: none; stroke: none; }
.map-box-focus { fill: var(--surface); stroke: var(--text-strong); stroke-width: 2; }
.map-box-party { fill: var(--map-band); stroke: var(--text-muted); rx: 14px; } /* a pill: a party's shape, not only its shade */
.map-box-more { fill: transparent; stroke: none; }
.map-conn, .map-conn-unread { color: var(--viz-other); }
.map-line.map-conn, .map-line.map-conn-unread { stroke-width: 1.5; marker-end: url(#connected-arrow); }
.map-line.map-conn-unread { stroke-dasharray: 5 4; }
.connected-arrowhead { fill: var(--viz-other); }

/* A phone: the table first; the diagram behind its disclosure. Wider: the diagram is shown, the disclosure isn't. */
@media (min-width: 641px) {
  .connected-figure > summary { display: none; }
  .connected-figure:not([open])::details-content { content-visibility: visible; }
}
@media print {
  .connected-figure > summary { display: none; }
  .connected-figure:not([open])::details-content { content-visibility: visible; }
  .connected-depth { display: none; }
}

/* Diagrams (workhorse_web/diagrams/, design §4): layouts other pages share, drawn by the network maps' template under
   the rules in "Network maps" above. The tree (diagrams/tree.py): a root or a GCP organization heads its tree in the
   band's fill with a heavier edge (it is also the top box, and its id names its kind); an organizational unit or a
   folder is the plain box, dashed when it wasn't read. A box lists its accounts or projects, each a link of its own,
   its name a step heavier than the muted id under it so the two read as one item; marks are the map's pills. The
   lines between boxes say only "beneath", never anything in colour: neutral, and lighter than a map's routes. */
.map-box-root, .map-box-organization { fill: var(--map-band); stroke: var(--text-muted); stroke-width: 1.5; }
.map-svg .map-leaf { font-weight: 500; }
.map-tree { color: var(--viz-other); }
.map-line.map-tree { stroke-width: 1.5; }
/* A pill of AWS's own default policy (FullAWSAccess) recedes: no fill, a quieter edge and regular muted words, which
   stay at 4.5:1 on the box. A pill that says something keeps the map's fill and strong words. */
.map-pill.map-pill-muted { fill: var(--surface); stroke: var(--border); }
.map-svg .map-pill-text.map-pill-muted { font-weight: 400; fill: var(--text-muted); }

/* A tree's two forms (templates/organization/_structure.html): the diagram and its outline, each behind a disclosure.
   A wide screen shows the diagram and folds the outline into "Show as an outline"; a phone shows the outline and folds
   the diagram into "Show the diagram"; paper prints the outline. The form a width shows has its summary hidden and its
   content shown (::details-content), so nothing in the markup moves and no script runs; a browser without
   ::details-content shows both as disclosures. */
.tree-view { margin: var(--space-6) 0 var(--space-8); }
.tree-view > h3 { margin-bottom: var(--space-2); }
.tree-view > .viz-desc { max-width: 80ch; margin: 0 0 var(--space-2); }
.tree-view > details > summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); width: fit-content; margin-top: var(--space-3); padding: var(--space-1) 0; }
.tree-view > details[open] > summary { margin-bottom: var(--space-2); }
.tree-view .figure-wrap { margin-top: var(--space-2); }
@supports selector(::details-content) {
  @media (min-width: 641px) {
    .tree-diagram > summary { display: none; }
    .tree-diagram::details-content { content-visibility: visible; }
  }
  @media (max-width: 640px) {
    .tree-outline > summary { display: none; }
    .tree-outline::details-content { content-visibility: visible; }
  }
}
/* The outline: a unit's line (its kind small above its name and id, then what it holds), the policies attached to it,
   the accounts directly in it, then the units beneath it, each level indented along a rule. */
.tree-outline-list { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.tree-outline-list .tree-outline-list { margin: var(--space-3) 0 0 var(--space-2); padding-left: var(--space-4); border-left: 1px solid var(--border); }
.tree-outline-place + .tree-outline-place { margin-top: var(--space-4); }
.tree-outline-head { margin: 0; }
.tree-outline-head .mono { overflow-wrap: anywhere; }
.tree-outline-kind { display: block; font-size: var(--text-xs); color: var(--text-muted); }
.tree-outline-counts { font-size: var(--text-sm); color: var(--text); }
.tree-outline-policies { margin: var(--space-1) 0 0; font-size: var(--text-sm); overflow-wrap: anywhere; }
.tree-outline-seats { list-style: none; margin: var(--space-2) 0 0; padding: 0; }
.tree-outline-seats > li { margin-top: var(--space-1); overflow-wrap: anywhere; }
.tree-outline-seats .badge { font-weight: 500; }
.tree-outline-unplaced { margin: var(--space-4) 0 0; }
.org-facts { margin-bottom: var(--space-4); }
.org-part { margin-top: var(--space-8); }
.org-part > h3 { margin-bottom: var(--space-2); }
.org-policy-name { overflow-wrap: anywhere; } /* RegionLockEuropeAndUsEastOnly…: one word, broken where it must be */
.org-facts .fact-why { max-width: 60ch; }
.org-trusted { list-style: none; margin: 0; padding: 0; }
.org-trusted > li + li { margin-top: var(--space-1); }
@media print {
  .tree-diagram { display: none; }
  .tree-view > details > summary { display: none; }
  @supports selector(::details-content) { .tree-outline::details-content { content-visibility: visible; } }
  .tree-outline-list, .tree-outline-place { break-inside: auto; }
  .tree-outline-head { break-after: avoid; }
  .tree-outline-add { display: none; } /* Add it is for the screen */
}

/* Report pages (templates/reports/: Data at rest, Keys, Certificates, In transit, Organization, the Identity overview):
   the Discovery report's figures, findings and charts over the tables of what they count, in one reading order.
   The figures answer the page's question, what was read qualifies them, the findings say what is worth a look, and
   the charts break the figures down. Every rule here hangs off the report pages' own classes (.report-page,
   .report-figures, .report-coverage, .report-table), so the Discovery report keeps its own look. */
.report-page .report { margin-top: var(--space-6); padding-top: var(--space-6); }

/* Figures: a row of tiles whose labels, values and notes line up across the row (each tile is a subgrid of three
   rows), so a two-line label never pushes its value below its neighbours'. On a wide page the tiles share one row
   and a long value ("38.2 TiB of 40.1 TiB") keeps its tile wide enough for one line; narrower, they wrap two or
   three to a row, each still wide enough for such a value. */
.report-figures { container-type: inline-size; margin: 0 0 var(--space-6); }
.report-figures:has(+ .report-coverage) { margin-bottom: var(--space-3); } /* what was read qualifies the figures: close under them */
.report-figures .disc-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); margin: 0; }
.report-figures .disc-figure { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; align-content: start; min-width: 0; }
.report-figures .disc-figure-value { overflow-wrap: break-word; }
.report-figures .disc-figure-value a { display: inline-block; min-width: 24px; } /* a one-digit link is still a target */
/* Up to six share one row; more (Connectivity's eight) wrap in rows of tiles at least 15rem wide, so no label or
   note is squeezed into a column of single words. */
@container (min-width: 60rem) {
  .report-figures .disc-figures:not(:has(> :nth-child(7))) { grid-template-columns: none; grid-template-rows: repeat(3, auto); grid-auto-flow: column; grid-auto-columns: minmax(min-content, 1fr); }
  .report-figures .disc-figures:not(:has(> :nth-child(7))) .disc-figure-value { white-space: nowrap; }
}
/* On a phone each figure is a line: its label on the left, its value on the right, its note under both, so five take a
   third of a screen rather than two screens of half-empty tiles. */
@container (max-width: 30rem) {
  .report-figures .disc-figures { grid-template-columns: minmax(0, 1fr); gap: var(--space-2); }
  .report-figures .disc-figure { grid-row: auto; grid-template-rows: none; grid-template-columns: minmax(0, 1fr) auto; column-gap: var(--space-3); align-items: baseline; padding: var(--space-2) var(--space-3); }
  .report-figures .disc-figure dt { grid-column: 1; grid-row: 1; }
  .report-figures .disc-figure-value { grid-column: 2; grid-row: 1; max-width: 60cqi; margin: 0 !important; font-size: var(--text-xl); text-align: right; }
  .report-figures .disc-figure-note { grid-column: 1 / -1; grid-row: 2; }
}

/* What was read: right under the figures it qualifies. Every account read in full is one sentence; otherwise each
   account that wasn't is a line of its own, its name first. */
.report-coverage { margin: 0; overflow-wrap: break-word; } /* a listing's name can be wider than a phone */
.report-coverage p { margin: 0; }
.report-coverage ul { margin: var(--space-1) 0 0; padding-left: var(--space-4); }
.report-coverage li + li { margin-top: var(--space-1); }
.report-coverage-account { font-weight: 500; color: var(--text); }

/* Findings, then charts, each under its own heading. */
.report-page .report-findings { margin-top: var(--space-8); }
.report-page .report-findings h2, .report-charts h2 { margin: 0 0 var(--space-4); }
.report-charts { margin-top: var(--space-8); }
.disc-state .report-state-next { margin-top: var(--space-2); }

/* The tables: a paragraph about a table keeps a readable measure and room before the count under it. */
.report-page section > p:not(.results-summary) { max-width: 80ch; }
.report-page section > p.help { margin-bottom: var(--space-3); }
/* GCP Identity's parts (templates/identity/gcp/): each list, the project cards and How this was made under a heading
   of their own inside the part, spaced as a page's sections are. */
.gcp-identity section > h3 { margin-top: var(--space-8); }

/* Columns wrap where a reader expects: between words, never inside a date, never after the hyphen of "AWS-managed"
   or "Internet-facing" in a squeezed column. Each cell says how much room its words need, and a table wider than its
   region scrolls inside it, never the page. A name breaks inside a word only when one word
   is wider than its column. Headings wrap between their words, so a short column isn't as wide as its label. The
   widths include the cell's padding (border-box): 19ch leaves "Customer-managed" its line. */
.report-table thead th { white-space: normal; vertical-align: bottom; }
.report-table time { white-space: nowrap; }
.report-table .cell-name { min-width: 19ch; overflow-wrap: break-word; }
.report-table .cell-name.cell-wide { min-width: 24ch; }  /* a name with a sentence under it: a key's description */
.report-table .cell-short { min-width: 12ch; }  /* a word or two a line: "Target Co production", "Pending deletion" */
.report-table .cell-words { min-width: 15ch; }  /* a few words: "Redirects HTTP to HTTPS", "Root › Workloads › Dev" */
.report-table .cell-phrase { min-width: 19ch; } /* with a long compound: "Customer-managed key", "ACM, Amazon-issued" */
.report-table .cell-text { min-width: 16ch; }   /* sentences, which take what room is left: the setting that says so */
/* An id or a policy name in a cell (a key id, ELBSecurityPolicy-TLS13-1-2-2021-06) breaks once, not at every hyphen. */
.report-table td > .mono.wrap { display: inline-block; min-width: 21ch; }
.report-table .cell-name .mono { overflow-wrap: anywhere; }
.report-table td .badge { max-width: 100%; }
.report-table thead tr.filter-row input.filter-date { min-width: 7rem; } /* still shows >2026-01-01 whole */
/* A number's reason ("Its scan didn't read …") is a sentence: it reads from the left, under its right-aligned value. */
.report-table td.num .fact-why { text-align: left; }
/* A table wider than its region scrolls sideways (Keys, certificates and IAM users do even on a laptop). Its first
   column, the row's name, stays in place as it does on a phone, so a row read at its far end still says whose it is;
   a field focused while scrolled is kept clear of it. */
@media (min-width: 641px) { .table-wrap:has(> .report-table) { scroll-padding-left: 16rem; } }
.report-table tbody th[scope="row"]:first-child,
.report-table :is(thead tr:first-child th:first-child, thead tr.filter-row td:first-child) {
  position: sticky; left: 0; z-index: 1; background: var(--surface); box-shadow: inset -1px 0 0 var(--border);
}
.report-table tbody tr:nth-child(even) th[scope="row"]:first-child { background: linear-gradient(var(--row-stripe), var(--row-stripe)), var(--surface); }
.report-table tbody tr:hover th[scope="row"]:first-child { background: var(--hover); }

@media print {
  /* On paper: the report and the tables, without the controls that only work on screen. */
  .report-page .overview-account, .report-page .table-filters, .report-page thead tr.filter-row { display: none !important; }
  .report-page .report { margin-top: var(--space-4); padding-top: var(--space-4); }
  .report-page .report-coverage, .report-page .report-findings h2, .report-charts h2 { break-after: avoid; }
  .report-figures .disc-figures { grid-template-columns: none; grid-template-rows: repeat(3, auto); grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
  .report-figures .disc-figure-value { white-space: normal; font-size: 20px; }
  /* A table fits the paper's width: smaller type, tighter cells, nothing held to a screen's column widths, words
     whole except ids. The widest tables (Keys, certificates, IAM users) print on landscape pages of their own, the
     report before them staying portrait. */
  .report-table { font-size: 9pt; }
  .report-table :is(th, td) { padding: var(--space-1) var(--space-2); }
  .report-table :is(.cell-short, .cell-words, .cell-phrase, .cell-text), .report-table td > .mono.wrap { min-width: 0; }
  .report-table td { overflow-wrap: break-word; }
  .report-table .mono { overflow-wrap: anywhere; }
  .report-table .cell-name, .report-table .cell-name.cell-wide { min-width: 18ch; }
  @page report-wide { size: A4 landscape; }
  .report-page section:has(> .table-wrap > .report-wide) { page: report-wide; }
  .report-table tbody th[scope="row"]:first-child,
  .report-table :is(thead tr:first-child th:first-child, thead tr.filter-row td:first-child) { position: static; box-shadow: none; }
}

/* Security services (templates/security/services.html, workhorse_web/security/services.py): the matrix of accounts ×
   services over the table of every (account, service). A cell is a symbol and words and opens its row in the table:
   the symbol takes the state's colour and the words never do, so nothing is said by colour alone. "Not read" is
   muted and italic, never a colour that could read as one more state. The matrix scrolls inside its region, its
   account column held in place as the report tables' first columns are. */
.svc-legend { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); list-style: none; margin: 0 0 var(--space-3); padding: 0; font-size: var(--text-sm); color: var(--text-muted); }
.svc-legend li { display: inline-flex; align-items: baseline; gap: var(--space-1); }
.svc-mark { display: inline-block; flex: none; width: 1.25em; text-align: center; font-weight: 600; }
.svc-state-on .svc-mark { color: var(--ok); }
.svc-state-partly .svc-mark { color: var(--warn); }
.svc-state-idle .svc-mark, .svc-state-off .svc-mark, .svc-state-not_read .svc-mark { color: var(--text-muted); }
.svc-matrix thead th { min-width: 12ch; }
.svc-matrix thead th:first-child { min-width: 19ch; }
.svc-matrix td.svc-cell { padding: 0; vertical-align: top; }
.svc-cell a { display: flex; align-items: baseline; gap: var(--space-1); min-height: 24px; padding: var(--space-2) var(--space-3); color: var(--text); text-decoration: none; }
.svc-cell a .svc-words { text-decoration: underline; text-decoration-color: var(--border); text-underline-offset: 3px; }
.svc-cell a:hover .svc-words, .svc-cell a:focus-visible .svc-words { text-decoration-color: currentColor; }
.svc-cell a:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.svc-cell.svc-state-not_read a { color: var(--text-muted); font-style: italic; }
tbody tr:hover .svc-cell.svc-state-not_read a { color: var(--text); }
@media (forced-colors: active) {
  .svc-mark { color: CanvasText !important; }
  .svc-cell a .svc-words { text-decoration-color: currentColor; }
}
@media print {
  .svc-cell a { padding: var(--space-1) var(--space-2); color: #000; }
  .svc-cell a .svc-words { text-decoration: none; }
  .svc-matrix thead th { min-width: 0; }
}

/* Relationship pages (templates/relationships/, workhorse_web/relationships/views.py, diagrams/bands.py): the Resource
   map and Across accounts and clouds. Each draws columns of groups (a band's own outline, a group in the band's fill)
   holding boxes, and lines that run along lanes between the columns. A line ends in its count and kind, a small box of
   its own that is the line's link; the lines are the neutral colour, thinner than a network map's routes, and end in
   an arrowhead at what they name (direction is drawn, not coloured). What no resource here holds is dashed, said in
   the legend and in words. A wide screen shows the diagram; a phone folds it behind "Show the diagram", so the table,
   its twin, leads; paper prints the table. */
.rel-view { margin: var(--space-8) 0 var(--space-6); }
.rel-view > h2 { margin-bottom: var(--space-3); }
.rel-view > .viz-desc { max-width: 80ch; margin: 0 0 var(--space-2); }
.rel-view > .rel-note { color: var(--text); }
.rel-controls { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3) var(--space-6); margin: 0 0 var(--space-4); }
.rel-controls .views { margin: 0; }
.rel-controls .views a { display: inline-flex; align-items: center; min-height: 38px; }
.rel-kind { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; }
.rel-kind label { font-weight: 500; color: var(--text-strong); }
.rel-kind select { min-height: 38px; max-width: 100%; }
.rel-diagram > summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); width: fit-content; margin-top: var(--space-3); padding: var(--space-2) 0; }
.rel-diagram[open] > summary { margin-bottom: var(--space-2); }
.rel-diagram .figure-wrap { margin-top: var(--space-2); }
@supports selector(::details-content) {
  @media (min-width: 641px) {
    .rel-diagram > summary { display: none; }
    .rel-diagram::details-content { content-visibility: visible; }
  }
}
.rel-legend { margin-top: var(--space-3); }
.rel-words { margin: 0 0 var(--space-2); max-width: 100ch; font-size: var(--text-sm); color: var(--text-muted); }
.rel-words-head { color: var(--text); font-weight: 500; }
.rel-word { white-space: nowrap; }
.rel-word b { font-weight: 600; color: var(--text-strong); }
.rel-table { margin-top: var(--space-8); }
.rel-table > h2 { margin-bottom: var(--space-2); }
.rel-table > p.help { max-width: 80ch; }
.rel-references .rel-stated { display: block; margin-top: var(--space-1); font-size: var(--text-xs); color: var(--text-muted); overflow-wrap: anywhere; }
.rel-references .cell-path { min-width: 16ch; }
.rel-references .cell-path .mono { font-size: var(--text-xs); overflow-wrap: anywhere; }

/* The diagram: a band is an outline with its name above its groups; a group is a filled container with its heading;
   boxes are the map's. */
.map-group.map-band { fill: none; stroke: var(--border); stroke-width: 1; }
.map-group.map-band-group { fill: var(--map-band); stroke: none; }
.map-svg .map-band-title { font-size: 12px; font-weight: 600; fill: var(--text-muted); letter-spacing: 0.02em; }
.map-box-party { fill: var(--map-band); }
.map-box-count { fill: var(--surface); stroke: var(--map-edge); }
.map-box-count.map-count-dashed { stroke-dasharray: 4 3; }
.map-svg .map-count { font-size: 11px; font-weight: 600; fill: var(--text-strong); font-variant-numeric: tabular-nums; }
.map-svg .map-count-kind { font-size: 11px; fill: var(--text-muted); }
.map-rel, .map-rel-end, .map-rel-dashed, .map-rel-dashed-end { color: var(--viz-other); }
.map-line.map-rel, .map-line.map-rel-end, .map-line.map-rel-dashed, .map-line.map-rel-dashed-end { stroke-width: 1.5; }
.map-line.map-rel-dashed, .map-line.map-rel-dashed-end { stroke-dasharray: 5 4; }
.map-line.map-rel-end, .map-line.map-rel-dashed-end { marker-end: url(#rel-arrow); }
.rel-arrow { fill: var(--viz-other); }
a.map-node-count:hover .map-box, a.map-node-count:focus-visible .map-box { stroke: var(--focus); stroke-width: 2; }
a.map-node-count:hover .map-count-kind, a.map-node-count:focus-visible .map-count-kind { fill: var(--text); }

@media (forced-colors: active) {
  .map-line.map-rel, .map-line.map-rel-end, .map-line.map-rel-dashed, .map-line.map-rel-dashed-end { stroke: CanvasText; }
  .rel-arrow { fill: CanvasText; }
  .map-group.map-band { stroke: CanvasText; }
}
@media print {
  .rel-diagram { display: none; }
  .rel-controls { display: none; }
}

/* Data residency (templates/residency/, workhorse_web/residency/): the world map and its twin, the copies to other
   Regions and every data store. The map is Natural Earth's land in the neutral ramp on a paler sea; a Region is a
   circle in categorical slot 1 (one hue: size, not colour, says how much), a multi-region a dashed outline, a copy to
   another country a curve in slot 2 with its arrow and its count in a pill, the one accent on the map. Circles are
   haloed in the surface colour so neighbours stay apart, labels in it so they read over land and sea alike. A wide
   screen shows the map and a phone folds it behind "Show the map" (the twin, below it, carries everything), as the
   Organization page does its diagram; under 720px wide it scrolls inside its region rather than shrink its labels. */
:root { --res-sea: var(--color-base-50); --res-land: var(--color-base-200); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --res-sea: color-mix(in srgb, var(--color-base-800) 45%, var(--color-base-900)); --res-land: var(--color-base-700); }
}
:root[data-theme="dark"] { --res-sea: color-mix(in srgb, var(--color-base-800) 45%, var(--color-base-900)); --res-land: var(--color-base-700); }

.res-where > p { max-width: 80ch; }
.res-map { margin: var(--space-4) 0 var(--space-6); }
.res-map > summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); width: fit-content; padding: var(--space-1) 0; }
.res-map[open] > summary { margin-bottom: var(--space-2); }
@supports selector(::details-content) {
  @media (min-width: 641px) {
    .res-map > summary { display: none; }
    .res-map::details-content { content-visibility: visible; }
  }
}
.res-map-figure { margin: 0; }
.res-map-figure figcaption h3 { margin: 0 0 var(--space-1); }
.res-map-figure .viz-desc { margin-bottom: var(--space-2); max-width: 80ch; }
.res-map-wrap { padding: 0; }
.res-map-svg { display: block; width: 100%; min-width: 720px; height: auto; font-family: var(--font); }
.res-sea { fill: var(--res-sea); }
.res-land { fill: var(--res-land); }
.res-marker circle { fill: var(--viz-s1); fill-opacity: 0.78; stroke: var(--surface); stroke-width: 1.5; }
.res-marker-ring circle { fill: var(--surface); fill-opacity: 1; stroke: var(--viz-s1); stroke-width: 2; }
.res-area ellipse { fill: var(--viz-s1); fill-opacity: 0.08; stroke: var(--text-muted); stroke-width: 1.5; stroke-dasharray: 5 4; }
.res-line { fill: none; stroke: var(--viz-s2); stroke-width: 2; stroke-linecap: round; }
.res-arrow { fill: var(--viz-s2); }
.res-pill rect { fill: var(--surface); stroke: var(--viz-s2); stroke-width: 1.5; }
.res-pill text { font-size: 11px; font-weight: 600; fill: var(--text-strong); font-variant-numeric: tabular-nums; }
.res-label { font-size: 11px; font-weight: 500; fill: var(--text-strong); paint-order: stroke; stroke: var(--surface); stroke-width: 3px; stroke-linejoin: round; pointer-events: none; }
.res-area-label { fill: var(--text-muted); font-style: italic; }
/* The circle, the outline or the pill is the link: hover and focus draw its edge in the focus colour. */
.res-marker:focus-visible, .res-area:focus-visible, .res-pill:focus-visible { outline: none; }
.res-marker:hover circle, .res-marker:focus-visible circle { stroke: var(--focus); stroke-width: 3; fill-opacity: 1; }
.res-area:hover ellipse, .res-area:focus-visible ellipse { stroke: var(--focus); stroke-width: 2.5; stroke-dasharray: none; }
.res-pill:hover rect, .res-pill:focus-visible rect { stroke: var(--focus); stroke-width: 2.5; }
.res-legend { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); list-style: none; margin: var(--space-3) 0 0; padding: 0; font-size: var(--text-sm); color: var(--text-muted); }
.res-legend li { display: inline-flex; align-items: center; gap: var(--space-2); }
.res-key { flex: none; overflow: visible; }
.res-key-dot { fill: var(--viz-s1); fill-opacity: 0.78; }
.res-key-ring { fill: var(--surface); stroke: var(--viz-s1); stroke-width: 2; }
.res-key-area { fill: var(--viz-s1); fill-opacity: 0.08; stroke: var(--text-muted); stroke-width: 1.5; stroke-dasharray: 4 3; }
.res-key-line { stroke: var(--viz-s2); stroke-width: 2; }
.res-key-head { fill: var(--viz-s2); }

/* The twin: a row a circle links to says so when it is reached. */
.res-places tbody tr:target > * { background: var(--info-bg); }
.res-places-note { margin-top: var(--space-2); }
.res-copies, .res-stores { margin-top: var(--space-8); }
.res-none { color: var(--text-muted); }
.res-ends { list-style: none; margin: var(--space-1) 0 0; padding: 0; font-size: var(--text-sm); color: var(--text); }
.res-ends li + li { margin-top: 2px; }
.res-copy-table td .fact-why, .res-store-table td .fact-why { margin-top: var(--space-1); }

@media (forced-colors: active) {
  .res-marker circle, .res-area ellipse, .res-line, .res-arrow, .res-pill rect, .res-land, .res-key * { forced-color-adjust: none; }
  .res-label { stroke: Canvas; fill: CanvasText; }
}
@media print {
  @supports selector(::details-content) {
    .res-map > summary { display: none; }
    .res-map::details-content { content-visibility: visible; }
  }
  .res-map-svg { min-width: 0; }
  .res-places tbody tr:target > * { background: none; }
}

/* Connectivity (templates/reach/connectivity*.html, workhorse_web/reach/connectivity.py): the figures, the Links table
   whose cells stack a name over its facts, a link's Details, and the hubs' defaults. Words and symbols carry every
   state; the colours only repeat them. Cells keep a readable width and an id wraps only when it must: a table wider
   than the screen scrolls inside its region. */
.figure-unmeasured { color: var(--text-muted); font-weight: 500; }
.derive-notice { margin-bottom: var(--space-4); }
.links-table th[scope="row"], .links-table td, .register-group td, .register-group th[scope="row"], .hubs-table td, .hubs-table th[scope="row"] { vertical-align: top; overflow-wrap: break-word; }
.links-table th[scope="row"], .register-group th[scope="row"], .hubs-table th[scope="row"] { min-width: 22ch; }
.links-table td { min-width: 22ch; }
.hubs-table td.defaults { min-width: 32ch; }
.hubs-table td.shared { min-width: 24ch; max-width: 30ch; }
.register-group td { min-width: 22ch; }
.link-kind { display: block; font-size: var(--text-sm); font-weight: 400; color: var(--text-muted); }
.end-title { font-weight: 600; color: var(--text-strong); }
.link-details > summary { cursor: pointer; color: var(--link); }
.link-details[open] > summary { margin-bottom: var(--space-2); }
.link-details dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--space-1) var(--space-3); margin: 0; font-size: var(--text-sm); min-width: 28ch; max-width: 60ch; }
.link-details dt { color: var(--text-muted); }
.link-details dd { margin: 0; }
.detail-line { display: block; }
tbody tr:hover .link-kind, tbody tr:hover .link-details dt { color: var(--text); } /* the hovered row's tint, as .fact-why does */
.register-group h2 { font-size: var(--text-lg); margin-top: var(--space-8); }
.register-group h2 .muted { font-weight: 400; font-size: var(--text-sm); }
.defaults-list { margin: 0; padding-left: var(--space-4); font-size: var(--text-sm); }
.defaults-list li + li { margin-top: var(--space-1); }
.defaults-sentence { margin: 0 0 var(--space-2); font-size: var(--text-sm); }
@media (max-width: 640px) {
  .link-details dl { grid-template-columns: 1fr; }
}

/* Lifecycle (templates/lifecycle/): a source's URL wraps anywhere, so the list reflows at 320px (WCAG 1.4.10). */
.lifecycle-sources .muted { overflow-wrap: anywhere; }

/* Network paths (templates/reach/paths*.html, path_detail*.html, probe*.html; workhorse_web/reach/paths.py): the
   figures by forwarding word and their legend, the path table whose cells stack a name over its facts, each
   direction's legs as step tables, and the probe's two-sided form. A word and a symbol carry every state (⇄ → ⋯ ? ○
   for forwarding, ✓ ◐ ✕ ? ○ for connections); the tints only repeat them. A table wider than the screen scrolls inside
   its region. */
.paths-probe-link { margin: 0; }
.paths-probe-link .button { display: inline-flex; align-items: center; gap: var(--space-2); }
.paths-probe-link .material-symbols-outlined { font-size: 18px; }
.paths-callout { margin-bottom: var(--space-4); }
.paths-callout p { margin: 0; }
.paths-freshness { margin-top: 0; color: var(--text-muted); font-size: var(--text-sm); }
.paths-summary { margin: 0 0 var(--space-6); }
/* The tile of the forwarding word shown now: a strong edge (and aria-current on its link), not colour alone. */
.paths-figures { margin-bottom: var(--space-4); }
.paths-figures .disc-figure.figure-current { box-shadow: inset 0 0 0 2px var(--text-strong); }
.fwd-mark { display: inline-block; min-width: 1.25em; font-weight: 700; color: var(--text-strong); }
.paths-legend-h { margin: 0 0 var(--space-2); font-size: var(--text-md); }
.paths-legend { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); gap: var(--space-2) var(--space-6); margin: 0; font-size: var(--text-sm); }
.paths-legend dt { font-weight: 600; color: var(--text-strong); }
.paths-legend dd { margin: 0; color: var(--text-muted); max-width: 60ch; }
.paths-filters { align-items: flex-start; }
.paths-filters .field .help { max-width: 24ch; }
.paths-more-filters { flex: 1 1 100%; }
.paths-more-filters > summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); width: fit-content; padding: var(--space-1) 0; }
.paths-more-filters[open] > summary { margin-bottom: var(--space-2); }
.paths-more-fields { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); align-items: flex-end; }
.paths-more-fields .field { margin: 0; }
.paths-more-fields select { max-width: 100%; }
#f-code { max-width: 36ch; }
.paths-context { max-width: 80ch; }
.paths-table th[scope="row"], .paths-table td, .paths-pairs th[scope="row"], .paths-pairs td { vertical-align: top; overflow-wrap: break-word; }
.paths-table th[scope="row"], .paths-table td:nth-child(2) { min-width: 21ch; }
.paths-table td:nth-child(3) { min-width: 19ch; }
.paths-table td:nth-child(4) { min-width: 14ch; }
.paths-table td:nth-child(5) { min-width: 24ch; }
.paths-table td:nth-child(6), .paths-table td:nth-child(7) { min-width: 11ch; }
.end-id { display: block; font-size: var(--text-xs); color: var(--text-muted); overflow-wrap: break-word; }
a.end-id { color: var(--link); }
.paths-trace { display: inline-block; margin-top: var(--space-2); font-size: var(--text-sm); font-weight: 500; }
.paths-table .badge, .path-direction .badge, .probe-answer .badge { white-space: normal; }
.fwd-both, .fwd-one_way { background: var(--info-bg); color: var(--info); }
.fwd-unknown { background: var(--warn-bg); color: var(--warn); }
.conn-open, .conn-some { background: var(--info-bg); color: var(--info); }
.conn-refused { background: var(--surface-3); color: var(--text-strong); }
.conn-unknown { background: var(--warn-bg); color: var(--warn); }
.conn-side { display: block; }
.conn-side + .conn-side, .conn-services + .conn-side { margin-top: var(--space-2); }
.conn-from { font-size: var(--text-sm); color: var(--text); }
.conn-allows { font-weight: 600; color: var(--text-strong); }
.paths-pairs th[scope="row"], .paths-pairs td:nth-child(2) { min-width: 20ch; }
.paths-pairs td:last-child { min-width: 24ch; }
.paths-not-listed { max-width: 80ch; }
.paths-not-listed ul { padding-left: var(--space-4); }
.paths-not-listed li + li { margin-top: var(--space-1); }

/* A path's detail, and the probe's answer: one section per direction, one step table per leg. */
.path-summary { color: var(--text); }
.path-meta { margin-top: var(--space-4); }
.path-direction { margin-top: var(--space-8); }
.path-direction > h2 { margin-bottom: var(--space-2); }
.path-head { font-weight: 600; }
.path-head-unknown { color: var(--warn); }
.path-leg { margin: var(--space-3) 0; }
.path-leg[open] { margin-bottom: var(--space-6); }
.path-leg > summary { cursor: pointer; padding: var(--space-1) 0; }
.path-leg > summary h3 { display: inline; margin: 0; font-weight: 500; overflow-wrap: anywhere; }
.path-leg[open] > summary { margin-bottom: var(--space-2); }
.path-outcome { font-weight: 600; color: var(--text-strong); }
.path-steps th[scope="row"] { min-width: 18ch; font-weight: 500; vertical-align: top; }
.path-steps td { vertical-align: top; overflow-wrap: anywhere; }
.path-steps td:nth-child(2) { min-width: 18ch; }
.path-steps td:nth-child(3) { min-width: 24ch; }
.path-steps td:nth-child(4) { min-width: 20ch; }
.path-pointer { white-space: nowrap; }
.path-step-n { display: inline-block; min-width: 2ch; color: var(--text); font-variant-numeric: tabular-nums; }
.path-why { max-width: 80ch; margin: var(--space-2) 0 0; }
.path-ends th[scope="row"], .path-ends td { vertical-align: top; }
.path-ends th[scope="row"] { min-width: 22ch; }
.path-ends td:nth-child(4) { min-width: 10ch; white-space: nowrap; }
.path-ends td:nth-child(5) { min-width: 22ch; }
.path-connections { margin: var(--space-4) 0 var(--space-6); }
.path-connections h3 { margin-bottom: var(--space-2); }
.path-connections td, .path-connections th[scope="row"] { vertical-align: top; }
.path-connections td:last-child { min-width: 28ch; }
.path-decided > summary { cursor: pointer; }
.path-decided ul { margin: var(--space-1) 0 var(--space-2); padding-left: var(--space-4); font-size: var(--text-sm); overflow-wrap: anywhere; }
.path-decided + .path-decided, .path-decided + .detail-line, .detail-line + .path-decided { margin-top: var(--space-1); }
.path-check { margin-top: var(--space-8); max-width: 960px; }
.path-check h2 { margin-top: 0; }
.path-check-form { margin-top: var(--space-3); }
.path-check-ends { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: var(--space-3) var(--space-4); }
.path-check-ends .field { margin: 0; min-width: 0; }
.path-check-ends select, .path-check-ends input { width: 100%; max-width: 100%; }
.path-check-service { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); align-items: flex-end; margin-top: var(--space-4); }
.path-check-service .field, .path-check-service .actions { margin: 0; }

/* Can it reach? */
.probe-form { max-width: 960px; margin: 0 0 var(--space-6); }
.probe-ends { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: var(--space-4); }
.probe-end { margin: 0; padding: var(--space-3) var(--space-4) var(--space-1); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); min-width: 0; }
.probe-end legend { padding: 0 var(--space-1); font-weight: 600; color: var(--text-strong); }
.probe-end select, .probe-end input { width: 100%; max-width: 100%; }
.probe-end .error-text { color: var(--error); margin: 0 0 var(--space-3); }
.probe-end:has([aria-invalid="true"]) { border-color: var(--error); }
.probe-service { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); align-items: flex-end; margin-top: var(--space-4); }
.probe-service .field { margin: 0; }
.probe-service .error-text { color: var(--error); }
.probe-service .actions { margin: 0; }
.probe-answer { max-width: 80ch; margin: 0 0 var(--space-6); }
.probe-answer h2 { margin-top: 0; }
.probe-answer p { margin: 0 0 var(--space-2); overflow-wrap: anywhere; }
.probe-answer p:last-child { margin-bottom: 0; }
.probe-connections-line { margin-top: var(--space-3); }

@media (max-width: 640px) {
  /* A phone stacks each row of these tables as a block, each cell labelled, so a path's forwarding and connections
     and a step's words show without a sideways scroll. */
  .paths-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .paths-stack, .paths-stack tbody, .paths-stack tr, .paths-stack th[scope="row"], .paths-stack td { display: block; width: auto; min-width: 0; text-align: left; }
  .paths-stack tr { padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
  .paths-stack tbody tr:last-child { border-bottom: 0; }
  .paths-stack th[scope="row"], .paths-stack td, table.compact.paths-stack :is(th, td) { padding: var(--space-1) var(--space-3); border: 0; }
  .paths-stack td:is(:nth-child(n)) { min-width: 0; }
  .paths-stack [data-label]::before { content: attr(data-label); display: block; font-size: var(--text-xs); font-weight: 600; color: var(--text-muted); }
  /* Stacked, the row's name needn't stay pinned (the app pins a wide table's first column on a phone). */
  .table-wrap .paths-stack tbody th[scope="row"]:first-child { position: static; min-width: 0; max-width: none; box-shadow: none; background: transparent; overflow-wrap: break-word; }
}
@media print {
  .paths-probe-link, .paths-filters, .path-check, .probe-form { display: none; }
}

/* Transit gateways (templates/reach/hubs*.html, templates/reach/hub*.html, workhorse_web/reach/hubs.py): the list of
   hubs, and a hub's settings, findings, the matrix of which segment reaches which, its diagram, its segments with their
   members and routes, and its attachments. Reach is neither good nor bad by itself, so the matrix says it in shapes
   and words, never in a status colour: a reached cell's symbol is strong, an unreached one muted, an unknown one muted
   and italic; the diagonal (a segment's own members) sits on a tint. Tables wider than the screen scroll inside their
   regions, and a long id wraps only where it must. */
.hubs-list th[scope="row"], .hubs-list td, .hub-members th[scope="row"], .hub-members td, .hub-attachments th[scope="row"], .hub-attachments td, .hub-routes th[scope="row"], .hub-routes td { vertical-align: top; overflow-wrap: break-word; }
.hubs-list th[scope="row"] { min-width: 18ch; }
.hubs-list td .mono, .hub-members td .mono, .hub-attachments td .mono { white-space: nowrap; }
@media (min-width: 641px) { .hub-members th .mono, .hub-attachments th .mono { white-space: nowrap; } } /* a phone pins and narrows the first column */
.hub-attachments td:nth-child(6) { min-width: 16ch; }
.hubs-list td.hub-defaults { min-width: 20ch; max-width: 28ch; }
.hubs-list td.shared { min-width: 18ch; max-width: 26ch; }
.hubs-list td.hub-findings { min-width: 16ch; }
.hubs-list td.hub-region { white-space: nowrap; }
.hub-id { display: block; font-size: var(--text-xs); }
.hub-flag { font-weight: 600; color: var(--text-strong); }
.hubs-note { max-width: 80ch; margin-top: var(--space-6); font-size: var(--text-sm); }
.hub-ident { color: var(--text-muted); overflow-wrap: anywhere; }
.hub-ident .mono { color: var(--text); }
.hub-jump ul { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); list-style: none; margin: 0 0 var(--space-6); padding: 0; font-size: var(--text-sm); }
.hub-jump a { display: inline-flex; align-items: center; min-height: 32px; }
.hub-section { margin: 0 0 var(--space-8); scroll-margin-top: var(--space-4); }
.hub-section > h2 { margin-bottom: var(--space-3); }
.hub-section > .help { max-width: 80ch; margin-bottom: var(--space-3); }
.hub-options { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); gap: var(--space-3) var(--space-6); margin: 0 0 var(--space-3); max-width: 120ch; }
.hub-options dt { font-size: var(--text-sm); color: var(--text-muted); }
.hub-options dd { margin: 0; overflow-wrap: anywhere; }
.hub-findings.disc-findings { margin-top: 0; }
.hub-findings .hub-finding-kind { margin: var(--space-6) 0 var(--space-3); font-size: var(--text-md); }
.hub-findings > h2 + .hub-finding-kind { margin-top: var(--space-2); }
.hub-finding-links { margin: var(--space-1) 0 0 !important; font-size: var(--text-sm); }
.hub-finding-links a { display: inline-flex; align-items: center; min-height: 28px; }
.hub-finding-open .disc-finding-sentence { text-decoration: underline; text-decoration-color: var(--focus); text-decoration-thickness: 2px; text-underline-offset: 4px; }
.hub-drill { padding: var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); max-width: 100%; }
.hub-drill-sentence { max-width: 80ch; font-weight: 500; color: var(--text-strong); }
.hub-subhead { margin: var(--space-4) 0 var(--space-2); font-size: var(--text-md); }
.hub-legend { margin-bottom: var(--space-3); }
.hub-legend li .svc-mark { color: var(--text-strong); }
.hub-legend .hub-cell-none .svc-mark, .hub-legend .hub-cell-na .svc-mark, .hub-legend .hub-cell-unknown .svc-mark { color: var(--text-muted); }
.hub-matrix thead th { min-width: 14ch; vertical-align: bottom; overflow-wrap: anywhere; }
.hub-matrix thead th:first-child, .hub-matrix th[scope="row"] { min-width: 16ch; }
.hub-matrix-corner { font-size: var(--text-xs); font-weight: 500; color: var(--text-muted); }
.hub-matrix th[scope="row"] { vertical-align: top; overflow-wrap: anywhere; }
.hub-matrix td.hub-cell { padding: 0; vertical-align: top; }
.hub-cell a { display: flex; align-items: baseline; gap: var(--space-1); min-height: 44px; padding: var(--space-2) var(--space-3); color: var(--text); text-decoration: none; }
.hub-cell .svc-mark { color: var(--text-strong); }
.hub-cell-text { display: flex; flex-direction: column; min-width: 0; }
.hub-cell a .svc-words { text-decoration: underline; text-decoration-color: var(--border); text-underline-offset: 3px; }
.hub-cell a:hover .svc-words, .hub-cell a:focus-visible .svc-words { text-decoration-color: currentColor; }
.hub-cell a:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.hub-cell-detail { font-size: var(--text-xs); color: var(--text-muted); overflow-wrap: anywhere; }
.hub-cell-all .svc-words, .hub-cell-some .svc-words { font-weight: 600; color: var(--text-strong); }
.hub-cell-none .svc-mark, .hub-cell-na .svc-mark, .hub-cell-none a, .hub-cell-na a { color: var(--text-muted); }
.hub-cell-unknown a { color: var(--text-muted); font-style: italic; }
.hub-cell-unknown .svc-mark { color: var(--text-muted); }
.hub-cell-diagonal { background: var(--surface-2); }
tbody tr:hover .hub-cell-detail, tbody tr:hover .hub-cell-unknown a { color: var(--text); }
.hub-segment { margin: var(--space-6) 0 var(--space-8); padding-top: var(--space-4); border-top: 1px solid var(--border); scroll-margin-top: var(--space-4); }
.hub-segment > h3 { margin-bottom: var(--space-2); overflow-wrap: anywhere; }
.hub-segment-facts { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); margin: 0 0 var(--space-3); font-size: var(--text-sm); }
.hub-segment-facts dt { color: var(--text-muted); }
.hub-segment-facts dd { margin: 0; color: var(--text); max-width: 60ch; }
.hub-unknowns { margin-bottom: var(--space-3); font-size: var(--text-sm); }
.hub-routes-details { margin-top: var(--space-3); }
.hub-routes-details > summary { cursor: pointer; color: var(--link); width: fit-content; min-height: 32px; padding: var(--space-1) 0; }
.hub-routes-details[open] > summary { margin-bottom: var(--space-2); }
.hub-truncated { max-width: 80ch; font-size: var(--text-sm); color: var(--text); }
.hub-members th[scope="row"] { min-width: 16ch; }
.hub-members td { min-width: 14ch; }
.hub-routes th[scope="row"] { min-width: 14ch; }
.hub-routes td { min-width: 10ch; }
.hub-route-blackhole th[scope="row"] { font-weight: 600; }
.hub-pointer { font-size: var(--text-xs); }
.hub-env-production { font-weight: 600; color: var(--text-strong); }
.hub-attachments th[scope="row"] { min-width: 18ch; }
.hub-attachments td { min-width: 10ch; }
.hub-attachments tr:target { background: var(--info-bg); }
.hub-attachments tr { scroll-margin-top: var(--space-4); }
/* The diagram's own boxes: a segment's route table is drawn with a stronger edge, so the lines' ends read as the table
   that routes, not as one of its attachments. */
.map-box-segment { fill: var(--map-band); stroke: var(--text-muted); stroke-width: 1.5; }
@media (max-width: 640px) {
  .hub-options { grid-template-columns: 1fr; }
  .hub-segment-facts { flex-direction: column; }
}
@media (forced-colors: active) {
  .hub-cell .svc-mark { color: CanvasText !important; }
  .hub-cell a .svc-words { text-decoration-color: currentColor; }
}
@media print {
  .hub-jump, .hub-routes-details > summary { display: none; }
  .hub-cell a { min-height: 0; padding: var(--space-1) var(--space-2); color: #000; }
  .hub-cell a .svc-words { text-decoration: none; }
}

/* Assistant: the ask page, a run's answer, and the page panel. An answer reads as a short report. */
.assistant-panel { margin: 0 0 var(--space-4); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); max-width: 70ch; }
.assistant-panel > summary { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); cursor: pointer; font-size: var(--text-sm); font-weight: 600; color: var(--text-strong); list-style: none; }
.assistant-panel > summary::-webkit-details-marker { display: none; }
.assistant-panel > summary .material-symbols-outlined { font-size: 18px; }
.assistant-panel > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.assistant-panel[open] > summary { border-bottom: 1px solid var(--border); }
.assistant-panel form { padding: var(--space-3); }
.assistant-panel textarea { width: 100%; box-sizing: border-box; }
.assistant-panel .actions { margin-top: var(--space-3); }
.what-group { margin: 0 0 var(--space-4); padding: 0; min-width: 0; width: 100%; }
.what-group h3 { font-size: var(--text-md); margin: 0 0 var(--space-2); color: var(--text-strong); }
.what-group > .help { margin-bottom: var(--space-2); }
.what-group .choice { margin: 0 0 var(--space-2); }
.what-group .choice .help { margin-left: calc(16px + var(--space-2)); max-width: 60ch; }
.what-group .field { margin: var(--space-2) 0 0; }
.what-group textarea { width: 100%; box-sizing: border-box; }
.run-progress { display: block; width: 100%; max-width: 40ch; height: 8px; margin: 0 0 var(--space-2); accent-color: var(--accent); }
.run-steps { max-width: 70ch; padding-left: var(--space-6); }
.run-answer { max-width: 75ch; }
.run-answer h2 { margin-top: 0; }
.run-answer h3 { margin: var(--space-6) 0 var(--space-2); font-size: var(--text-lg); }
.run-answer p, .run-answer li { line-height: 1.6; }
.answer-summary { font-size: var(--text-lg); color: var(--text-strong); }
.recommendations > li { margin-bottom: var(--space-3); }
.recommendations p { margin: 0 0 var(--space-1); }
.recommendations .why { color: var(--text-muted); }
.run-answer .play { margin: 0 0 var(--space-4); }
.run-answer .play h4 { margin: 0 0 var(--space-2); }
.run-answer .play ol { margin: 0 0 var(--space-2); padding-left: var(--space-6); }
.cites { font-size: var(--text-sm); color: var(--text-muted); white-space: normal; }
.not-measured { margin: var(--space-6) 0; }
.not-measured h2 { margin-top: 0; font-size: var(--text-md); }
.not-measured p { margin: 0 0 var(--space-2); }
.facts-read { max-width: 75ch; }
.facts-read details.fact { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); margin-bottom: var(--space-2); }
.facts-read details.fact > summary { padding: var(--space-2) var(--space-3); cursor: pointer; font-weight: 600; color: var(--text-strong); }
.facts-read details.fact > summary:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.facts-read details.fact > ul, .facts-read details.fact > p { margin: 0; padding: var(--space-2) var(--space-3) var(--space-3) var(--space-6); }
.facts-read details.fact > p { padding-left: var(--space-3); }
.facts-read p.fact { margin: 0 0 var(--space-2); padding: var(--space-2) var(--space-3); }
.provenance { max-width: 75ch; font-size: var(--text-sm); }
.settings-sent { max-width: 75ch; }
.run-answer > .help { margin-bottom: var(--space-4); }
.what > legend { margin-bottom: var(--space-3); }
.what-group { margin-bottom: var(--space-6); }
.assistant-panel .field { margin-top: var(--space-4); }

/* Executive overview (templates/executive/overview.html and its partials; the PDF, overview_print.html, carries its
   own styles): one screen an executive reads in two minutes, top to bottom. The figures are the Discovery report's
   tiles (.disc-figures inside .report-figures); each area is a card whose status is a chip of icon and word on its
   tone's tint, from the badge tokens, so a status never rests on colour alone and dark mode follows the tokens; a card
   not measured is dashed, never quiet like a good one. The top risks are numbered, the brief reads as a short report
   (the assistant's .answer-summary, .recommendations and .cites), and how it was decided is definition lists. No data
   tables. The cards and the definitions fall to one column on a phone. */
.exec-head h1 { font-size: 24px; letter-spacing: -0.015em; }
.exec-asof { color: var(--text-strong); font-weight: 500; overflow-wrap: anywhere; }
.exec-asof .mono { font-weight: 400; }
.exec-head .lede { margin-top: var(--space-1); }
.exec-account { margin-top: var(--space-4); }
.exec-head-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.exec-unread { margin: 0 0 var(--space-6); }
.exec-unread p { margin: 0; }
.exec-contents { margin: 0 0 var(--space-8); }
.exec-section { margin-top: var(--space-12); padding-top: var(--space-8); border-top: 1px solid var(--border); scroll-margin-top: var(--space-4); }
.exec-contents + .exec-section { margin-top: 0; }
.exec-section-head { margin: 0 0 var(--space-6); }
.exec-section-head h2 { margin: 0 0 var(--space-2); font-size: var(--text-xl); letter-spacing: -0.01em; }
.exec-section-head .lede { margin: 0; }
.exec-figures { margin: 0; }
.exec-summary { max-width: 70ch; margin: var(--space-6) 0 0; font-size: var(--text-lg); line-height: 1.6; color: var(--text-strong); }
.exec-none { max-width: 70ch; margin: 0; }

/* A status: the icon and the word, on its tone's tint. "Not measured" takes the strong grey ink, not the muted one,
   which falls short of 4.5:1 on its tint. */
.exec-status {
  display: inline-flex; align-items: center; gap: var(--space-1); flex: none; padding: 2px var(--space-2) 2px 6px;
  border-radius: 999px; font-size: var(--text-xs); font-weight: 600; line-height: 1.5; white-space: nowrap;
  background: var(--surface-3); color: var(--text);
}
.exec-status .material-symbols-outlined { font-size: 16px; }
.exec-tone-attention { background: var(--error-bg); color: var(--error); }
.exec-tone-warn { background: var(--warn-bg); color: var(--warn); }
.exec-tone-ok { background: var(--ok-bg); color: var(--ok); }
.exec-tone-muted { background: var(--surface-3); color: var(--text); }

/* Posture: how many areas have each status, then the two groups of cards. */
.exec-tally { list-style: none; margin: 0 0 var(--space-8); padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-6); }
.exec-tally li { display: inline-flex; align-items: center; gap: var(--space-2); }
.exec-tally-n { font-weight: 600; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.exec-group + .exec-group { margin-top: var(--space-8); }
.exec-group h3 { margin: 0 0 var(--space-3); font-size: var(--text-lg); }
.exec-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr)); }
.exec-card {
  display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; padding: var(--space-4);
  background: var(--surface); border: 1px solid var(--border); border-top: 3px solid var(--exec-accent, var(--border));
  border-radius: var(--radius); box-shadow: 0 1px 2px rgb(0 0 0 / 0.04);
}
.exec-card-attention { --exec-accent: var(--error); }
.exec-card-warn { --exec-accent: var(--warn); }
.exec-card-ok { --exec-accent: var(--ok); }
.exec-card-muted { border-style: dashed; border-top-style: solid; border-color: var(--control-border); background: transparent; box-shadow: none; }
/* The status sits under the title in every card, so the chips line up down a column whatever the titles' lengths. */
.exec-card-head { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-2); }
.exec-card-title { margin: 0; font-size: var(--text-md); overflow-wrap: anywhere; }
.exec-card p { margin: 0; }
.exec-card-sentence { color: var(--text-strong); overflow-wrap: anywhere; }
.exec-card-count { font-size: var(--text-sm); font-weight: 600; color: var(--text); }
.exec-card-coverage { font-size: var(--text-sm); color: var(--text-muted); }
.exec-card-coverage > summary { width: fit-content; min-height: 24px; cursor: pointer; color: var(--text); font-weight: 500; }
.exec-card-coverage > summary:hover { color: var(--text-strong); }
.exec-card-coverage > p { margin: var(--space-1) 0 0; overflow-wrap: anywhere; }
.exec-card-link { margin-top: auto !important; padding-top: var(--space-1); }
.exec-card-link a { display: inline-flex; align-items: center; gap: var(--space-1); min-height: 24px; font-size: var(--text-sm); font-weight: 500; text-decoration: none; }
.exec-card-link a > span:first-child { text-decoration: underline; }
.exec-card-link a:hover > span:first-child { text-decoration-thickness: 2px; }
.exec-card-link .material-symbols-outlined { font-size: 16px; }

/* Top risks: a number, the area above the sentence, why it matters, the way to the evidence. */
.exec-risks { list-style: none; counter-reset: exec-risk; margin: 0; padding: 0; display: grid; gap: var(--space-6); max-width: 80ch; }
.exec-risk { counter-increment: exec-risk; display: grid; grid-template-columns: 32px minmax(0, 1fr); column-gap: var(--space-4); row-gap: var(--space-1); }
.exec-risk::before {
  content: counter(exec-risk); grid-column: 1; grid-row: 1 / span 4; display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 999px; background: var(--surface-3); color: var(--text-strong); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.exec-risk > p { grid-column: 2; margin: 0; }
.exec-risk-area { font-size: var(--text-sm); font-weight: 500; color: var(--text-muted); }
.exec-risk-sentence { font-size: var(--text-lg); font-weight: 600; line-height: 1.4; color: var(--text-strong); overflow-wrap: anywhere; }
.exec-risk-why { color: var(--text); }
.exec-risk-link a { font-size: var(--text-sm); font-weight: 500; }

/* What changed: the two checks compared, the findings that moved by how, then the week in one sentence. */
.exec-changes > :not(.exec-section-head) { max-width: 80ch; }
.exec-changes-span { margin: 0; color: var(--text-strong); }
.exec-moves { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.exec-moves li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.exec-moves li + li { margin-top: var(--space-2); }
.exec-move-area { color: var(--text-strong); font-weight: 600; }
.exec-move-arrow { color: var(--text-muted); }
.exec-headline-changes { margin: 0 0 var(--space-3); padding-left: var(--space-6); }
.exec-headline-changes li + li { margin-top: var(--space-1); }
.exec-shift-kind { margin: var(--space-6) 0 var(--space-2); font-size: var(--text-md); }
.exec-shifts { margin: 0; padding-left: var(--space-6); }
.exec-shifts li + li { margin-top: var(--space-2); }
.exec-shift-sentence { color: var(--text-strong); overflow-wrap: anywhere; }
.exec-shift-meta { font-size: var(--text-sm); color: var(--text-muted); }
.exec-changes-tenant { margin: var(--space-2) 0 0; }
.exec-week { margin: var(--space-6) 0 0; }

/* The brief: the assistant's answer as a short report, then the way to a new one (or why there can't be one). */
.exec-brief { max-width: 75ch; }
.exec-brief-title { margin: 0 0 var(--space-1); font-size: var(--text-lg); }
.exec-brief-meta { font-size: var(--text-sm); color: var(--text-muted); margin-bottom: var(--space-4); }
.exec-brief-stale { margin: 0 0 var(--space-4); }
.exec-brief-stale p { margin: 0; }
.exec-brief h4 { margin: var(--space-6) 0 var(--space-2); font-size: var(--text-md); }
.exec-brief p, .exec-brief li { line-height: 1.6; }
.exec-brief .questions { padding-left: var(--space-6); }
.exec-brief .questions li + li { margin-top: var(--space-2); }
.exec-brief-empty { display: flex; align-items: flex-start; gap: var(--space-3); max-width: 75ch; padding: var(--space-4); border: 1px dashed var(--control-border); border-radius: var(--radius); }
.exec-brief-empty > .material-symbols-outlined { color: var(--text-muted); }
.exec-brief-empty p { margin: 0; }
.exec-brief-empty-title { font-weight: 600; color: var(--text-strong); margin-bottom: var(--space-1) !important; }
.exec-brief-new { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); max-width: 75ch; margin-top: var(--space-6); }
.exec-brief-new form { margin: 0; }
.exec-brief-new .help { flex: 1 1 20rem; }
.exec-brief-refusal { display: flex; align-items: flex-start; gap: var(--space-2); margin: 0; color: var(--text); }
.exec-brief-refusal .material-symbols-outlined { color: var(--info); font-size: 18px; margin-top: 1px; }

/* How this was made: the statuses' meanings beside their chips, then the areas two to a row (one on a phone). */
.exec-method h3 { margin: var(--space-8) 0 var(--space-3); font-size: var(--text-lg); }
.exec-method .exec-section-head + h3 { margin-top: 0; }
.exec-method h4 { margin: var(--space-6) 0 var(--space-3); font-size: var(--text-md); color: var(--text-muted); }
.exec-legend { display: grid; gap: var(--space-3); max-width: 80ch; margin: 0 0 var(--space-4); }
.exec-legend > div { display: grid; grid-template-columns: 9rem minmax(0, 1fr); gap: var(--space-4); align-items: baseline; }
.exec-legend dt { line-height: 1; }
.exec-legend dd { margin: 0; }
.exec-method-note { max-width: 75ch; color: var(--text); }
.exec-areas { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(24rem, 100%), 1fr)); gap: var(--space-4) var(--space-8); margin: 0; }
.exec-areas > div { min-width: 0; }
.exec-areas dt { font-weight: 600; color: var(--text-strong); }
.exec-areas dd { margin: var(--space-1) 0 0; }
.exec-area-rule { font-size: var(--text-sm); color: var(--text-muted); overflow-wrap: anywhere; }
.exec-area-rule code { color: var(--text); }
@media (max-width: 600px) {
  .exec-head-actions { width: 100%; }
  .exec-legend > div { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
  .exec-risk { grid-template-columns: 28px minmax(0, 1fr); column-gap: var(--space-3); }
  .exec-risk::before { width: 28px; height: 28px; }
}
@media (forced-colors: active) {
  .exec-status, .exec-risk::before { border: 1px solid CanvasText; }
}
@media print {
  /* The browser's own print of the page; the PDF download is overview_print.html. */
  .exec-head-actions, .exec-contents, .exec-account, .exec-brief-new, .exec-card-link, .exec-risk-link, .exec-changes-tenant,
  main:has(.exec-head) .assistant-panel { display: none !important; }
  .exec-section { margin-top: var(--space-8); padding-top: var(--space-6); }
  .exec-section-head, .exec-group h3, .exec-method h3, .exec-method h4, .exec-shift-kind { break-after: avoid; }
  .exec-section-head, .exec-card, .exec-risk, .exec-legend > div, .exec-areas > div, .exec-tally, .exec-brief-empty { break-inside: avoid; }
  /* Six figures read three to a row on paper, not the report pages' one row of narrow columns. */
  .exec-figures.report-figures .disc-figures { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: none; grid-auto-flow: row; }
  .exec-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }
  .exec-card { box-shadow: none; }
  /* Tints may not print: the chip keeps an edge, and its icon and word say the rest. */
  .exec-status { border: 1px solid currentColor; }
  .exec-method { break-before: page; }
}

/* Posture by account: the account's name stays in view while the table scrolls sideways (on any width, not just a
   phone), and the chips are compact: the icon above a smaller word, so a laptop shows more columns. The pinned cell
   paints its row's own background, so nothing shows through in either theme. */
table.exec-accounts tbody th[scope="row"], table.exec-accounts thead tr:nth-child(2) th:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--surface); box-shadow: inset -1px 0 0 var(--border);
  min-width: 9rem; max-width: 14rem; overflow-wrap: anywhere; white-space: normal;
}
table.exec-accounts tbody tr:nth-child(even) th[scope="row"] { background: linear-gradient(var(--row-stripe), var(--row-stripe)), var(--surface); }
table.exec-accounts tbody tr:hover th[scope="row"] { background: var(--hover); }
table.exec-accounts thead tr:first-child td { border-bottom: 0; }
table.exec-accounts .exec-status-compact {
  flex-direction: column; gap: 0; padding: 2px var(--space-2); border-radius: var(--radius); font-size: 11px;
  line-height: 1.25; white-space: normal; text-align: center; min-width: 5.5rem;
}
table.exec-accounts td, table.exec-accounts thead th { padding-left: var(--space-2); padding-right: var(--space-2); }
table.exec-accounts thead th { white-space: normal; vertical-align: bottom; }
table.exec-accounts thead th[colspan] { white-space: nowrap; }
table.exec-accounts td:nth-child(2) { white-space: normal; min-width: 8rem; max-width: 10rem; }

/* The historical view (docs/superpowers/specs/2026-10-24-historical-view-design.md) */
.history-menu summary .material-symbols-outlined:first-child { font-size: 20px; color: var(--text-muted); }
.history-menu .menu-panel { min-width: 260px; }
.history-menu .menu-panel form { margin: 0; }
/* On a phone the panel hangs from the header's right edge (the shared rule pins both sides, which a 260px panel can't fit). */
/* A closed menu's panel takes no room: left laid out it sits past the right edge of a narrow header, which the 320px reflow
   check measures (the header's own panels hang from the nav when open). */
@media (max-width: 800px) { .page-header-end .menu:not([open]) > .menu-panel { display: none; } }
.history-menu .menu-note { padding: var(--space-2) var(--space-3); }
.as-of-pill {
  display: inline-flex; align-items: center; gap: var(--space-1); margin: 0; padding: var(--space-1) var(--space-3);
  border-radius: 999px; font-weight: 700; background: var(--warn-bg); color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
}
.as-of-pill .material-symbols-outlined { font-size: 20px; }
.as-of-banner {
  margin: 0 0 var(--space-6); padding: var(--space-3) var(--space-4); border-radius: var(--radius);
  background: var(--warn-bg); color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
}
.as-of-banner p { margin: 0; }
.as-of-banner ul { margin: var(--space-2) 0 0; padding-left: var(--space-6); }
.as-of-banner a { color: inherit; font-weight: 600; }
tr.day-row th { text-align: left; background: var(--surface-2); color: var(--text-strong); font-weight: 600; }
.actions-cell { text-align: right; white-space: nowrap; }
.actions-cell form { display: inline; margin: 0; }
.delete-disclosure { display: inline-block; text-align: left; white-space: normal; vertical-align: top; }
.delete-disclosure > summary { cursor: pointer; padding: var(--space-2) var(--space-3); color: var(--text-muted); font-weight: 500; }
.delete-disclosure > summary:hover { color: var(--text-strong); }
.delete-disclosure form { max-width: 28ch; padding: var(--space-2) var(--space-3); }
@media print { .as-of-banner, .as-of-pill { print-color-adjust: exact; -webkit-print-color-adjust: exact; } .history-menu { display: none; } }
@media (max-width: 640px) {
  .history-table th, .history-table td { padding: var(--space-2); }
  .history-table .button { padding-left: var(--space-2); padding-right: var(--space-2); }
  .history-table .button { white-space: nowrap; }
}
/* At phone width each row stacks: what it is above, its button below at full width, so nothing clips. */
@media (max-width: 600px) {
  .history-stack, .history-stack tbody, .history-stack tr, .history-stack th, .history-stack td { display: block; }
  .history-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .history-stack tr { padding: var(--space-2) 0; border-bottom: 1px solid var(--border); }
  .history-stack tr.day-row { padding: 0; }
  .history-stack th, .history-stack td { padding: var(--space-1) var(--space-2); border: 0; box-shadow: none; text-align: left; white-space: normal; }
  .table-wrap .history-stack tbody th[scope="row"]:first-child { position: static; min-width: 0; max-width: none; box-shadow: none; background: none; font-weight: 600; }
  .history-stack td[data-label]::before { content: attr(data-label) ": "; color: var(--text-muted); }
  .history-stack .actions-cell { padding-top: var(--space-2); }
  .history-stack .actions-cell form { display: block; }
  .history-stack .actions-cell .button { display: block; width: 100%; text-align: center; box-sizing: border-box; }
  .history-stack .delete-disclosure { display: block; }
  .history-stack .delete-disclosure form { max-width: none; }
}

/* The collector queue (templates/queue/) */
.job-details > p { margin: 0 0 var(--space-1); }
.job-details > p:last-child { margin-bottom: 0; }
.job-details details { max-width: 60ch; }
.job-details summary { cursor: pointer; color: var(--error); }
.job-details .wrap-pre { white-space: pre-wrap; overflow-wrap: anywhere; margin: var(--space-2) 0 0; }
.job-error { color: var(--error); overflow-wrap: anywhere; }
.wrap-anywhere { overflow-wrap: anywhere; }
.queue-recent { margin: 0 0 var(--space-3); }
.queue-recent li { margin-bottom: var(--space-3); }
.external-id { font-size: var(--text-lg); overflow-wrap: anywhere; user-select: all; }

/* Settings > GCP: the quarantined packages follow the projects table with room between them */
.gcp-waiting { margin-top: var(--space-6); }
