/* Frontage - console UI.
 * Palette shared with the project docs: indigo-slate accent, cool
 * neutrals, desaturated severity ramp. Severity vars (--sev-*) are
 * injected per-page from reporting/severity.py.
 */

:root {
  --ground: #f4f6f9;
  --surface: #ffffff;
  --surface-2: #eef1f5;
  --ink: #1a1e28;
  --ink-soft: #58616f;
  --ink-faint: #646c7a;   /* 4.6:1 or better on every light surface (was #8b93a1, 3.1:1) */
  --line: #e0e4ea;
  --line-strong: #cdd3dc;
  --accent: #3a4d8f;
  --accent-2: #5468b4;
  --accent-ink: #2c3c73;
  --accent-soft: #e9ecf7;
  --bad: #b1242c;
  /* overlay behind the side nav - must darken the page in BOTH themes,
     so it is derived from a different base per palette. */
  --scrim: color-mix(in srgb, var(--ink) 42%, transparent);
  --on-accent: #ffffff;
  --topbar-h: 56px;   /* shared by .topbar and the side nav below it */
  --r: 10px;
  --r-sm: 6px;
  --shadow-sm: 0 1px 2px rgba(20, 26, 40, .05), 0 1px 3px rgba(20, 26, 40, .05);
  --shadow-md: 0 2px 4px rgba(20, 26, 40, .04), 0 6px 16px rgba(20, 26, 40, .07);
  --shadow-lg: 0 4px 10px rgba(20, 26, 40, .06), 0 16px 40px rgba(20, 26, 40, .10);
  --ease: 140ms cubic-bezier(.4, 0, .2, 1);
  --font-sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI Variable Text",
               "Segoe UI", Inter, Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
  color-scheme: light;
}

/* Dark palette.
 *
 * Deliberately declared twice: the media query is the "Match system"
 * case (skipped when the user has explicitly chosen Light), the
 * attribute selector is an explicit Dark choice saved on the account -
 * base.html puts data-theme on <html> from user.theme, see app/prefs.py.
 * CSS can't express "either of these" in one rule without style
 * queries, so KEEP THE TWO BLOCKS IN SYNC.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground: #0d1016;
    --surface: #161a23;
    --surface-2: #1e232e;
    --ink: #e7eaf0;
    --ink-soft: #a3acbb;
    --ink-faint: #848d9b;   /* 4.6:1 or better on every dark surface (was #6b7482, 3.7:1) */
    --line: #272d38;
    --line-strong: #333b48;
    --accent: #8b9dd6;
    --accent-2: #a2b1e2;
    --accent-ink: #aab9e4;
    --accent-soft: #1c2333;
    --bad: #e0656b;
    --scrim: color-mix(in srgb, var(--ground) 72%, transparent);
    --on-accent: #10141c;   /* accent is light in dark mode: ink on it, not white */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .40);
    --shadow-md: 0 2px 6px rgba(0, 0, 0, .45), 0 8px 24px rgba(0, 0, 0, .35);
    --shadow-lg: 0 6px 16px rgba(0, 0, 0, .50), 0 20px 48px rgba(0, 0, 0, .45);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --ground: #0d1016;
  --surface: #161a23;
  --surface-2: #1e232e;
  --ink: #e7eaf0;
  --ink-soft: #a3acbb;
  --ink-faint: #848d9b;   /* 4.6:1 or better on every dark surface (was #6b7482, 3.7:1) */
  --line: #272d38;
  --line-strong: #333b48;
  --accent: #8b9dd6;
  --accent-2: #a2b1e2;
  --accent-ink: #aab9e4;
  --accent-soft: #1c2333;
  --bad: #e0656b;
  --scrim: color-mix(in srgb, var(--ground) 72%, transparent);
  --on-accent: #10141c;   /* accent is light in dark mode: ink on it, not white */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .40);
  --shadow-md: 0 2px 6px rgba(0, 0, 0, .45), 0 8px 24px rgba(0, 0, 0, .35);
  --shadow-lg: 0 6px 16px rgba(0, 0, 0, .50), 0 20px 48px rgba(0, 0, 0, .45);
  color-scheme: dark;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font: 15px/1.55 var(--font-sans);
  -webkit-font-smoothing: antialiased;
}

/* one consistent, visible focus ring everywhere (was inputs-only) */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* A bare text link gets a slightly rounded ring; anything with its own
   shape (a pill, a button) keeps that shape, which the outline follows. */
:where(a:not([class])):focus-visible { border-radius: 3px; }

a { color: var(--accent-ink); }
/* One scale, three levels. h1 is a page title, h2 a section, h3 a block
   inside one; .diff-h and .set-sub below are the same level as h3 and
   are kept on the same figures deliberately.

   overflow-wrap on h1: several page titles are a hostname
   (scan_detail, check_result) and a long one has no space to break at,
   so without this it pushes the whole page sideways at 360px. */
h1 { font-size: 1.5rem; margin: 0; overflow-wrap: break-word; }
h2 { font-size: 1.05rem; margin: 28px 0 12px; }
h3 { font-size: .95rem; margin: 22px 0 10px; }
code { font-family: var(--font-mono); font-size: .88em;
       background: var(--surface-2); padding: .1em .4em; border-radius: 4px; }
.dim { color: var(--ink-faint); }
/* `.mono` was only ever defined as `.finding dd.mono`, so the same class
   on the cron column, the audit detail, the report status and the asset
   line of a triage card rendered in the body sans face. One definition,
   and `.finding dd.mono` keeps its own size below. */
.mono { font-family: var(--font-mono); font-size: .92em; }
/* An empty state is a sentence standing where a table or a list would
   be. Boxed like one, so the page does not look half-built: this is the
   same hairline-on-surface panel as .card, at list density. */
.empty {
  margin: 0; padding: 18px 20px;
  background: var(--surface); border: 1px dashed var(--line-strong);
  border-radius: var(--r); color: var(--ink-soft); font-size: 13.5px;
}
.empty a { white-space: nowrap; }
/* The dashed frame says "this will fill in"; this line says what
   fills it. Only on the states that are genuinely waiting for data:
   a completed scan with no findings is a result, not an empty box. */
.empty small { display: block; margin-top: 5px; color: var(--ink-faint); font-size: 12.5px; }
/* Inside a panel the frame is already there, so it would be a box in a
   box: the trends chart card and the posture card both say "nothing
   yet" from inside one. */
.card > .empty, .posture-card .empty, .pending-panel .empty {
  padding: 8px 0; background: none; border: 0;
}

/* ---- top bar ---- */
.topbar {
  display: flex; align-items: center; gap: 24px;
  padding: 0 24px; height: var(--topbar-h);
  position: sticky; top: 0; z-index: 20;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(10px);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
.brand {
  display: inline-flex; align-items: center; gap: 9px;
  font-weight: 600; text-decoration: none; color: var(--ink);
  letter-spacing: -.01em;
}
/* Terms and privacy: long-form reading, so a measure that keeps lines short. */
.legal { max-width: 72ch; margin: 8px auto 48px; }
.legal h1 { margin: 18px 0 4px; }
.legal h2 { font-size: 1.05rem; margin: 28px 0 8px; }
.legal p, .legal li { font-size: 15px; line-height: 1.65; color: var(--ink-soft); }
.legal ul { padding-left: 22px; }
.legal li { margin-bottom: 6px; }
.legal strong { color: var(--ink); font-weight: 600; }
.legal-meta { color: var(--ink-faint); margin: 0 0 18px; }
.legal-nav { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; font-size: 13.5px; margin: 0 0 4px; }
.legal-switch a { margin-left: 16px; }
.legal-switch a[aria-current="page"] { color: var(--ink); font-weight: 600; text-decoration: none; }
.legal-foot { margin-top: 36px; padding-top: 14px; border-top: 1px solid var(--line); font-size: 13px; color: var(--ink-faint); }
.consent { display: flex; gap: 10px; align-items: flex-start; font-size: 13px; color: var(--ink-soft); margin: 4px 0 16px; }
.consent input { width: auto; margin: 3px 0 0; flex: none; }
.brand .mark { display: block; width: 22px; height: 22px; flex: none; color: var(--accent); }
/* The nav links used to carry margin-right:auto and push the logout
   block to the right edge; with them in the drawer the brand does.
   Scoped to .topbar - the landing page reuses bare .brand. */
.topbar .brand { margin-right: auto; }
.logout { display: flex; align-items: center; gap: 12px; }
.who {
  font-size: 13px; color: var(--ink-faint); text-decoration: none;
  transition: color var(--ease);
}
.who:hover { color: var(--ink); }
.role-tag {
  font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
  padding: 1px 6px; border-radius: 999px; background: var(--accent-soft); color: var(--accent-ink);
}
.logout { flex: none; }
.logout button {
  border: 1px solid var(--line-strong); background: var(--surface); white-space: nowrap;
  color: var(--ink-soft); border-radius: var(--r-sm); padding: 5px 10px; font-size: 13px; cursor: pointer;
  transition: color var(--ease), border-color var(--ease), background var(--ease);
}
.logout button:hover { color: var(--ink); border-color: var(--ink-faint); background: var(--surface-2); }

/* ---- side nav drawer ----
 * Slides in from the left at every viewport width - this is the nav, not
 * a mobile fallback. console.js toggles `nav-open` on <body> and keeps
 * #nav-toggle's aria-expanded in sync; everything below keys off that
 * one class. Scoped to .nav-* / .sidenav so nothing leaks into pages
 * that share console.css but have no top bar.
 */
.nav-toggle {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; padding: 0;
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink-soft); cursor: pointer;
  transition: color var(--ease), border-color var(--ease), background var(--ease);
}
.nav-toggle:hover { color: var(--ink); border-color: var(--ink-faint); background: var(--surface-2); }
body.nav-open .nav-toggle {
  color: var(--accent-ink); background: var(--accent-soft);
  border-color: color-mix(in srgb, var(--accent) 35%, var(--line-strong));
}

/* three bars, drawn from one span so the button stays a single hit box */
.nav-toggle-bars { position: relative; display: block; }
.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  width: 16px; height: 2px; border-radius: 2px; background: currentColor;
}
.nav-toggle-bars::before,
.nav-toggle-bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle-bars::before { top: -5px; }
.nav-toggle-bars::after { top: 5px; }

/* Seated below the sticky top bar rather than over it, so the toggle
   stays visible and clickable while the drawer is open - it is the
   primary close affordance, and a full-height panel would bury it. */
.sidenav {
  position: fixed; top: var(--topbar-h); left: 0; bottom: 0; z-index: 40;
  width: 248px; max-width: 82vw;
  display: flex; flex-direction: column; gap: 2px;
  padding: 14px 12px;
  overflow-y: auto;
  /* Keeps a flick at the end of the drawer's own scroll from chaining
     into the page underneath it. */
  overscroll-behavior: contain;
  background: var(--surface);
  border-right: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  /* Parked off-canvas to the LEFT, which contributes no scrollable
     overflow in LTR, so the page never gains a horizontal scrollbar
     while the drawer is closed. visibility also keeps the hidden links
     out of the tab order; the delay below holds it visible until the
     slide-out has finished.

     The delay is on the CLOSED state only, and deliberately 0s on the
     open state. `visibility` animates discretely, so transitioning it
     over 200ms meant it did not become `visible` until part-way
     through - and the script focuses the first link synchronously on
     open, so that focus call landed on a still-hidden element and was
     silently dropped. Opening the menu left a keyboard user's focus
     stranded on the toggle. */
  transform: translateX(-100%);
  visibility: hidden;
  transition: transform 200ms cubic-bezier(.4, 0, .2, 1), visibility 0s linear 200ms;
}
body.nav-open .sidenav {
  transform: translateX(0); visibility: visible;
  transition: transform 200ms cubic-bezier(.4, 0, .2, 1), visibility 0s;
}

.sidenav-head {
  display: flex; flex-direction: column; gap: 3px;
  padding: 2px 12px 12px; margin-bottom: 6px;
  border-bottom: 1px solid var(--line);
}
.sidenav-title { font-size: 13px; font-weight: 600; color: var(--ink); }
/* Shown only while the top bar is too narrow to carry the address itself
   (see the 880px block below, which hides .who at the same point). */
.sidenav-who { display: none; font-size: 12px; color: var(--ink-faint); word-break: break-all; }

/* Ten links with no structure was a wall. The heading is a label, not
   a control: it is not focusable and not clickable, and the links keep
   their own tab order. */
.sidenav-group {
  margin: 18px 0 6px; padding: 14px 12px 0;
  font-size: 11px; font-weight: 600; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-faint);
  /* A rule, not just a dimmer colour. The heading and the links were
     both grey and only a shade apart, which at 11px uppercase is not
     enough to read as a different KIND of thing. The line separates the
     groups whatever the two greys are doing, and it keeps working for
     anyone who cannot tell those greys apart at all. */
  border-top: 1px solid var(--line);
}
.sidenav-sec { display: flex; flex-direction: column; gap: 2px; }
/* The heading is a SIBLING of .sidenav-sec, not a child, so the old
   `.sidenav-sec:first-of-type .sidenav-group` never matched anything. */
.sidenav-group:first-of-type {
  margin-top: 6px; padding-top: 0; border-top: 0;
}
/* Settings sits apart at the bottom, pushed there rather than spaced,
   so the gap does not change with the number of groups a role sees. */
.sidenav-foot {
  margin-top: auto; padding-top: 10px;
  border-top: 1px solid var(--line);
}

.sidenav a {
  padding: 8px 12px; border-radius: var(--r-sm); text-decoration: none;
  color: var(--ink-soft); font-size: 14px;
  transition: background var(--ease), color var(--ease);
}
.sidenav a:hover { background: var(--surface-2); color: var(--ink); }
.sidenav a.active { background: var(--accent-soft); color: var(--accent-ink); font-weight: 500; }

.nav-scrim {
  position: fixed; top: var(--topbar-h); right: 0; bottom: 0; left: 0; z-index: 30;
  background: var(--scrim);
  opacity: 0; visibility: hidden;
  transition: opacity 200ms cubic-bezier(.4, 0, .2, 1), visibility 0s linear 200ms;
}
body.nav-open .nav-scrim {
  opacity: 1; visibility: visible;
  transition: opacity 200ms cubic-bezier(.4, 0, .2, 1), visibility 0s;
}

/* The global reduced-motion block below already clamps every transition
   to .01ms, which makes the drawer appear and vanish instantly; stated
   here too so the intent survives a future edit to that block. */
@media (prefers-reduced-motion: reduce) {
  .sidenav, .nav-scrim { transition: none; }
}

.wrap { max-width: 960px; margin: 0 auto; padding: 28px 24px 80px; }

.page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; }
/* The title side has to be allowed to shrink (a hostname title), the
   action side must not (it is a button). */
.page-head > :first-child { min-width: 0; }
.page-actions { flex: none; }
.back { font-size: 13px; text-decoration: none; display: inline-block; margin-bottom: 6px; }

/* ---- buttons / forms ---- */
.btn-primary {
  display: inline-block; border: 0; border-radius: var(--r-sm); cursor: pointer;
  background: var(--accent);
  color: var(--on-accent); font-size: 14px; font-weight: 500;
  padding: 9px 16px; text-decoration: none;
  transition: background var(--ease);
}
.btn-primary:hover { background: var(--accent-ink); }
/* The quieter partner of .btn-primary, for a second action beside it.
   Same size and shape so the pair lines up; outline instead of fill. */
.btn-secondary {
  display: inline-block; border: 1px solid var(--line); border-radius: var(--r-sm); cursor: pointer;
  background: var(--surface); color: var(--ink); font-size: 14px; font-weight: 500;
  padding: 8px 15px; text-decoration: none;
  transition: border-color var(--ease), box-shadow var(--ease);
}
.btn-secondary:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); }
.report-links { display: flex; gap: 8px; flex-wrap: wrap; }

form label { display: block; margin: 0 0 14px; font-size: 13px; color: var(--ink-soft); }
/* textarea is in the list because /register has one: left out, it fell
   back to the browser's own box and sat beside these looking like a
   different form. */
form input[type=email], form input[type=password], form input[type=text],
form input[type=date], form input:not([type]), form textarea {
  display: block; width: 100%; margin-top: 5px;
  padding: 9px 11px; font-size: 14px; font-family: inherit; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 6px;
}
form textarea { line-height: 1.5; resize: vertical; }
form input:focus-visible, form select:focus-visible,
form textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
form select {
  display: block; margin-top: 5px; padding: 8px 10px; font-size: 14px;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: 6px;
}

/* A row of controls that filters the page below it. Three pages carry
   one (assets, audit, trends) and they have to look like the same bar:
   wrapping so two selects and a button cannot push 360px sideways,
   bottom-aligned so the controls share a baseline whatever height their
   labels are, and the labels on the same micro-type as .inline-form and
   the table headers they sit above. */
.filter-bar {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: 12px 18px; margin-bottom: 16px;
}
.filter-bar label {
  display: flex; flex-direction: column; gap: 3px; margin: 0;
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint);
}
.filter-bar select { margin-top: 0; min-width: 10rem; max-width: 100%; }

.row-actions { white-space: nowrap; text-align: right; }
/* Several actions in one cell: a single row, forms included. */
.row-actions-list { display: flex; gap: 6px; justify-content: flex-end; align-items: center; }
.row-actions-list .inline-form { display: inline-flex; }
/* The same for cells that hold the forms directly (team, users, scopes...). */
.row-actions > .inline-form, .row-actions > .link-btn { display: inline-flex; vertical-align: middle; }
.row-actions > .inline-form + .inline-form,
.row-actions > .inline-form + .link-btn,
.row-actions > .link-btn + .inline-form,
.row-actions > .link-btn + .link-btn { margin-left: 6px; }
/* Row actions (run now, edit, pause, delete, revoke...): small outlined
   buttons rather than underlined text, the same whether the action is a
   <button> in a form or an <a>. Destructive ones are red only in their
   text and border, and fill on hover so the click is deliberate. */
.link-btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 28px; padding: 0 10px; margin: 0;
  font: inherit; font-size: 12.5px; font-weight: 500; line-height: 1; white-space: nowrap;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: 6px;
  text-decoration: none; cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.link-btn:hover {
  background: var(--surface-2);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line-strong));
  color: var(--accent-ink);
}
.link-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.link-btn.danger {
  color: var(--bad);
  border-color: color-mix(in srgb, var(--bad) 40%, var(--line-strong));
}
.link-btn.danger:hover { color: #fff; background: var(--bad); border-color: var(--bad); }
.link-btn:disabled, .link-btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

td.detail { max-width: 380px; font-size: 11px; color: var(--ink-faint); overflow: hidden; text-overflow: ellipsis; }
tr.row-off td { opacity: .5; }
/* A schedule whose last run was refused. Sits under the target so it
   reads as that row's status, and wraps rather than widening the table. */
.sched-refused { display: block; margin-top: 4px; font-size: 12.5px; color: var(--ink-faint); overflow-wrap: anywhere; }
.sched-refused .pill { margin-right: 4px; }
.cron-bad { color: var(--bad); }

/* ---- scan diff ("what changed") ---- */
.diff {
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--r); padding: 12px 16px; margin: 4px 0 18px; background: var(--surface);
}
.diff-summary { font-size: 13.5px; display: flex; gap: 14px; flex-wrap: wrap; align-items: baseline; }
.diff-summary strong { font-weight: 600; }
.d-added { color: var(--sev-high); font-weight: 600; }
.d-resolved { color: var(--sev-low); font-weight: 600; }
.diff-h { font-size: .95rem; margin: 14px 0 8px; }
.diff .findings, .diff .resolved-list { margin-top: 0; }
.resolved-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 6px; }
.resolved-list li { font-size: 13px; }
.diff-none { margin: 4px 0 16px; }
form small { display: block; margin-top: 5px; color: var(--ink-faint); font-size: 12px; }
.form-error {
  background: color-mix(in srgb, var(--bad) 10%, var(--surface));
  border: 1px solid var(--bad); color: var(--ink);
  padding: 10px 14px; border-radius: 6px; font-size: 14px; margin-bottom: 18px;
}

.auth-card {
  max-width: 360px; margin: 10vh auto 0; background: var(--surface);
  border: 1px solid var(--line); border-radius: 14px; padding: 32px;
  box-shadow: var(--shadow-lg);
}
.auth-card h1 { margin-bottom: 4px; font-size: 1.3rem; letter-spacing: -.01em; }
.auth-mark { display: block; width: 44px; height: 44px; margin-bottom: 16px; color: var(--accent); }
.auth-sub { margin: 0 0 22px; font-size: 13px; color: var(--ink-faint); }
.auth-card .btn-primary { width: 100%; text-align: center; }

.scan-form { max-width: 520px; background: var(--surface); border: 1px solid var(--line);
             border-radius: var(--r); padding: 22px; box-shadow: var(--shadow-sm); }
fieldset.scan-type { border: 1px solid var(--line); border-radius: 6px; margin: 4px 0 16px; padding: 12px 14px; }
fieldset.scan-type legend { font-size: 12px; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .06em; padding: 0 6px; }
.radio { display: flex; gap: 8px; align-items: baseline; color: var(--ink); margin: 6px 0; }
.radio small { display: inline; color: var(--ink-faint); }
.scope-ref { margin-top: 34px; }

/* ---- the panel box ----
 * One declaration of the box that .posture-card, .scan-form, .enrol,
 * table.grid and .stat all already draw the same way: the surface
 * colour, a hairline in --line, the standard radius and the small
 * shadow. It exists so the next feature reaches for a class instead of
 * writing a sixth copy of it in a page-local <style> block, which is
 * how trends and the self-serve result page ended up with boxes at
 * 14px, 20px and 22px padding.
 */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 18px; box-shadow: var(--shadow-sm);
}
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }

/* ---- stat cards / sparkline ---- */
.cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-bottom: 8px; }
.stat {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 16px; display: flex; flex-direction: column; gap: 4px;
  box-shadow: var(--shadow-sm);
  transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease);
}
.stat::before {                      /* hairline accent along the top edge */
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  opacity: .7;
}
.stat:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--line-strong); }
.stat-n { font-size: 1.75rem; font-weight: 650; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.stat-n.is-bad { color: var(--bad); }
.stat-l { font-size: 12px; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .06em; }
.spark-bars { display: flex; align-items: flex-end; gap: 4px; height: 38px; }
.spark-bar {
  width: 100%; border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, var(--accent-2), var(--accent));
  opacity: .85; transition: opacity var(--ease);
}
.stat:hover .spark-bar { opacity: 1; }

/* A wide table scrolls inside its own box rather than pushing the whole
   page sideways. The trends breakdown is eleven columns, which overflows
   any phone and most split-screen windows; without this the entire page
   gained a horizontal scrollbar and the nav drifted off-screen with it. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-scroll > table.grid { min-width: 640px; }

/* ---- tables ---- */
table.grid { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 13.5px;
             background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
             overflow: hidden; box-shadow: var(--shadow-sm); }
table.grid th {
  text-align: left; padding: 10px 12px; font-size: 11px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--ink-faint); border-bottom: 1px solid var(--line-strong);
  background: color-mix(in srgb, var(--surface-2) 55%, var(--surface));
}
table.grid td { padding: 10px 12px; border-bottom: 1px solid var(--line); }
table.grid tbody tr:last-child td { border-bottom: 0; }
table.grid tbody tr { transition: background var(--ease); }
table.grid tbody tr:hover { background: var(--surface-2); }
/* The pointer belongs only on a row that is actually a link. Every page
   but the dashboard renders plain data rows, and offering them a hand
   cursor promised a click that console.js never wired up. */
table.grid tbody tr[data-href]:hover { cursor: pointer; }
table.grid td.num { font-variant-numeric: tabular-nums; color: var(--ink-faint); }
table.grid a { text-decoration: none; }

/* ---- status pills ---- */
.pill {
  display: inline-block; font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .05em; padding: 2px 8px; border-radius: 999px;
  background: var(--surface-2); color: var(--ink-soft);
}
/* A status never breaks across lines, even in a narrow table column. */
.pill { white-space: nowrap; }
.pill-queued  { background: var(--surface-2); color: var(--ink-soft); }
.pill-running { background: var(--accent-soft); color: var(--accent-ink); }
.pill-done    { background: color-mix(in srgb, var(--sev-low, #3f7488) 18%, var(--surface)); color: var(--ink); }
.pill-error   { background: color-mix(in srgb, var(--bad) 15%, var(--surface)); color: var(--bad); }

/* ---- run state ---- */
.run-state { display: flex; align-items: center; gap: 12px; padding: 18px 0; }
.progress { font-family: var(--font-mono); font-size: 13px; color: var(--ink-soft); }
.spinner {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--line-strong); border-top-color: var(--accent);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation: none; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .btn-primary:hover, .stat:hover { transform: none; }
}
.error-box {
  background: var(--surface-2); border: 1px solid var(--line-strong); border-radius: 6px;
  padding: 12px 14px; font-size: 13px; white-space: pre-wrap; color: var(--bad); overflow-x: auto;
}

/* ---- result panel ---- */
.result-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 8px 0 20px; flex-wrap: wrap; }
.sev-tiles { display: flex; gap: 8px; }
.tile {
  min-width: 66px; text-align: center; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: opacity var(--ease), transform var(--ease);
}
.tile.is-zero { opacity: .4; box-shadow: none; }
.tile-n { display: block; font-size: 1.15rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.tile-l { display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-faint); }

/* ---- finding cards (markup shared with the PDF via _finding_card.html.j2) ---- */
.findings { display: flex; flex-direction: column; gap: 12px; }
.finding {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 3px solid var(--sev-info); border-radius: var(--r);
  padding: 14px 16px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--ease), border-color var(--ease);
}
.finding:hover { box-shadow: var(--shadow-md); }
.finding.sev-critical { border-left-color: var(--sev-critical); }
.finding.sev-high     { border-left-color: var(--sev-high); }
.finding.sev-medium   { border-left-color: var(--sev-medium); }
.finding.sev-low      { border-left-color: var(--sev-low); }
.finding.sev-info     { border-left-color: var(--sev-info); }
.finding > header { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.finding > header h3 { flex: 1; margin: 0; font-size: 1rem; }
.finding-cat { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint); white-space: nowrap; }
.sev-pill {
  display: inline-block; min-width: 62px; text-align: center; color: #fff;
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  padding: 2px 8px; border-radius: 4px;
}
.finding dl { margin: 0; display: grid; grid-template-columns: 120px 1fr; gap: 3px 14px; }
.finding dt { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint); padding-top: 2px; }
.finding dd { margin: 0; font-size: 13.5px; }
.finding dd.mono { font-family: var(--font-mono); font-size: 12px; word-break: break-word; }
.finding > footer { margin-top: 10px; padding-top: 8px; border-top: 1px dashed var(--line); font-size: 11px; color: var(--ink-faint); text-align: right; }
.finding > footer .link-btn { height: 26px; font-size: 12px; }

/* ---- triage (scan detail) ----
 * The .triage-* classes were left in the markup as hooks with nothing
 * behind them, so a triage card ran its heading, the handoff rows and
 * the save controls together as one undivided block. They get the
 * dashed hairline .finding > footer already uses rather than a new
 * device, and the muted group's opacity moves here from a style
 * attribute so it sits with .tile.is-zero and tr.row-off.
 */
/* `.finding dl` sets margin: 0, so this has to out-specify it. */
.finding dl.triage-handoff {
  margin: 12px 0 0; padding-top: 10px;
  border-top: 1px dashed var(--line);
}
.triage-form { margin-top: 14px; }
.triage-muted { opacity: .75; }

/* ---- sections and leads ----
 * Named for the settings page, where they started, but these are now
 * the console's standard section rhythm: one bottom margin, one
 * hairline-underlined h2, one lead paragraph. Settings, assets, users,
 * scopes, reports, the new-scan page, the dashboard and the triage
 * block all use them, so a section that opts out reads as a different
 * page rather than a different thing.
 */
.set-section { margin-bottom: 38px; }
.set-section:last-child { margin-bottom: 0; }
.set-section > h2 {
  padding-bottom: 8px; border-bottom: 1px solid var(--line);
}
/* Same level as h3, and kept on the same figures on purpose. */
.set-sub { font-size: .95rem; margin: 22px 0 10px; }
.set-lead { margin: 0 0 16px; font-size: 13px; color: var(--ink-faint); max-width: 62ch; }
.set-lead code { font-size: 12px; }
.set-counts { grid-template-columns: repeat(3, 1fr); }

/* definition list used for read-only account / system facts */
.kv {
  margin: 0 0 4px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--shadow-sm); overflow: hidden;
}
.kv > div {
  display: grid; grid-template-columns: 190px 1fr; gap: 14px;
  padding: 11px 16px; border-bottom: 1px solid var(--line);
}
.kv > div:last-child { border-bottom: 0; }
.kv dt {
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); padding-top: 3px;
}
.kv dd { margin: 0; font-size: 13.5px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; }
.kv dd .dim { font-size: 12.5px; }

.form-ok {
  background: color-mix(in srgb, var(--sev-low, #3f7488) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--sev-low, #3f7488) 45%, var(--surface));
  color: var(--ink);
  padding: 10px 14px; border-radius: 6px; font-size: 14px; margin-bottom: 18px;
}

.code-block {
  margin: 0 0 16px; padding: 12px 14px; overflow-x: auto;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: 12px; line-height: 1.5; color: var(--ink-soft);
}

/* ---- two-factor enrolment ---- */
.enrol {
  display: flex; gap: 22px; align-items: flex-start; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  padding: 22px; box-shadow: var(--shadow-sm);
}
.enrol-qr {
  display: block; width: 200px; height: 200px; flex: none;
  background: #fff;                      /* QR needs light quiet-zone in both themes */
  padding: 8px; border-radius: var(--r-sm); border: 1px solid var(--line);
}
.enrol-side { flex: 1; min-width: 240px; }
.enrol-side p { margin: 0 0 8px; }
.enrol-secret {
  font-family: var(--font-mono); font-size: 13px; letter-spacing: .06em;
  word-break: break-all; background: var(--surface-2); color: var(--ink);
  padding: 8px 10px; border-radius: var(--r-sm); margin-bottom: 16px !important;
}
.enrol-side form input { max-width: 180px; letter-spacing: .3em; font-family: var(--font-mono); }

.recovery-panel {
  background: color-mix(in srgb, var(--sev-high, #b1242c) 7%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--sev-high, #b1242c) 40%, var(--surface));
  border-radius: var(--r); padding: 20px 22px; box-shadow: var(--shadow-sm);
}
.recovery-panel h3 { margin: 0 0 8px; font-size: 1rem; }
.recovery-panel p { margin: 0 0 12px; font-size: 13px; color: var(--ink-soft); max-width: 62ch; }
.recovery-list {
  list-style: none; margin: 0 0 14px; padding: 14px 16px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 22px;
  font-family: var(--font-mono); font-size: 13.5px; letter-spacing: .04em;
}
.two-up { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.two-up .scan-form { max-width: none; }
.two-up .set-sub { margin-top: 0; }
.auth-alt { margin: 14px 0 0; font-size: 12.5px; text-align: center; }

/* ---- compact density (Settings → Appearance) ----
 * Same layout, less air. Only spacing/scale is touched so nothing can
 * reflow differently between the two modes.
 */
[data-density="compact"] .wrap { padding: 18px 24px 56px; }
[data-density="compact"] .page-head { margin-bottom: 14px; }
[data-density="compact"] section { margin-bottom: 18px; }
[data-density="compact"] .set-section { margin-bottom: 26px; }
[data-density="compact"] .cards { gap: 10px; }
[data-density="compact"] .stat { padding: 11px 13px; }
[data-density="compact"] .card { padding: 13px; }
[data-density="compact"] .empty { padding: 12px 14px; }
[data-density="compact"] .stat-n { font-size: 1.45rem; }
[data-density="compact"] table.grid { font-size: 12.5px; }
[data-density="compact"] table.grid th,
[data-density="compact"] table.grid td { padding: 6px 10px; }
[data-density="compact"] .kv > div { padding: 7px 14px; }
[data-density="compact"] .finding { padding: 12px 14px; }
[data-density="compact"] .scan-form { padding: 16px; }
[data-density="compact"] form label { margin-bottom: 10px; }

/* ---- responsive ----
 * The nav links no longer live in the top bar, so the old horizontal
 * overflow-scroll rules for .topnav are gone with them. What is left is
 * the bar tightening up and the lower-value chrome (email, brand
 * wordmark) dropping out first.
 */
@media (max-width: 880px) {
  .topbar {
    gap: 12px;
    /* env() keeps the bar clear of a notch in landscape; the max() means
       phones without one are unaffected. */
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }
  .who { display: none; }
  .sidenav-who { display: block; }
  .sidenav {
    padding-left: max(12px, env(safe-area-inset-left));
    padding-bottom: max(14px, env(safe-area-inset-bottom));
  }
  .wrap { padding: 22px 16px 64px; }
}

/* Touch ergonomics. 34px and a 33px link are comfortable with a mouse
   and awkward with a thumb, so both go to the 44px minimum wherever the
   pointer is coarse. The width clause is a backstop for small screens
   that report a fine pointer. */
@media (pointer: coarse), (max-width: 560px) {
  .nav-toggle { width: 44px; height: 44px; }
  .sidenav a { display: flex; align-items: center; min-height: 44px; padding: 10px 12px; }
  .logout button { min-height: 38px; padding-inline: 12px; }
  /* .link-btn is the row action on six pages (delete, disable, run now,
     expire now, save, Clear) and was a 12px line of text about 20px
     tall, which is the smallest target in the console and the one most
     often next to a destructive twin. Grown, not shrunk, and the text
     stays the same size. */
  .link-btn { min-height: 44px; padding-inline: 8px; }
  .pw-reset > summary { display: flex; align-items: center; min-height: 44px; padding-inline: 8px; }
  /* The controls in a filter bar or a row form sit side by side, so they
     all go to 44px together or they end up at different heights. */
  .filter-bar select,
  .inline-form select, .inline-form input { min-height: 44px; }
  /* Stop the page scrolling behind the open drawer. Confined to touch
     and narrow screens on purpose: these have overlay scrollbars, so
     locking costs no layout shift, whereas on a desktop with a gutter
     scrollbar it would jolt the page sideways on every open. */
  body.nav-open { overflow: hidden; }
}

@media (max-width: 560px) {
  /* flex-start, not stretch: stretch turned the single page action into
     a full-width banner that read as a section header rather than a
     button. */
  .page-head { flex-direction: column; align-items: flex-start; }
  .sev-tiles { flex-wrap: wrap; }
  table.grid { font-size: 12.5px; }
  table.grid th, table.grid td { padding: 8px 9px; }
  .kv > div { grid-template-columns: 1fr; gap: 2px; }
  .kv dt { padding-top: 0; }
  .recovery-list { grid-template-columns: 1fr; }
  .two-up { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
  .cards { grid-template-columns: repeat(2, 1fr); }
  .set-counts { grid-template-columns: repeat(2, 1fr); }
  .finding dl { grid-template-columns: 1fr; }
  .finding dt { margin-top: 6px; }
}

/* ---- admin: user management (/admin/users) ----
 * Pending registrations are the reason the page exists, so they get an
 * accented panel above the full account table. Everything else reuses
 * .grid / .pill / .link-btn.
 */

/* accent frame around the pending-registrations table */
.pending-panel {
  border-left: 3px solid var(--accent);
  border-radius: var(--r);
  background: color-mix(in srgb, var(--accent-soft) 60%, var(--surface));
  padding: 10px 12px;
  box-shadow: var(--shadow-sm);
}
.pending-panel table.grid { box-shadow: none; }

/* one-line form inside a table cell: label, control and button on a row */
.inline-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.inline-form label {
  display: flex; flex-direction: column; gap: 3px; margin: 0;
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-faint);
}
/* Controls on one row have to start at the same height. `form select`
   carries no top margin and `form input` carries 5px, so a row with
   both (the triage controls, the asset filters) had its fields and its
   labels 5px out of step. */
.inline-form select,
.inline-form input,
.inline-form textarea { margin-top: 0; }

/* compact variant of the primary button, for inline row actions */
.btn-primary.btn-sm { padding: 7px 13px; font-size: 13px; }

/* the signed-in admin's own row */
tr.row-self > td { background: color-mix(in srgb, var(--accent-soft) 55%, var(--surface)); }
tr.row-self > td:first-child { font-weight: 600; }

/* per-row actions: links on one line, password disclosure under them */
.user-actions { white-space: normal; }
.act-line { white-space: nowrap; }
.act-line > small { font-size: 11px; white-space: normal; }

/* password reset, folded away per row so the table stays readable */
.pw-reset { display: block; margin-top: 2px; }
/* Several of these sit in one row-actions cell (change role, change email,
   reset two-factor, reset password). Closed, they share a line instead of
   stacking one per line, which made every account row four lines tall;
   the one that is open takes the full width below them. */
.user-actions .pw-reset:not([open]) { display: inline-block; margin-right: 12px; }
.pw-reset.is-danger > summary { color: var(--bad); }
.btn-danger { background: var(--bad); color: var(--on-accent); }
.pw-reset > summary {
  cursor: pointer; padding: 2px 4px;
  font-size: 12px; color: var(--accent-ink); text-decoration: underline;
}
.pw-reset > summary::marker { content: ""; }
.pw-reset > summary::-webkit-details-marker { display: none; }
.pw-reset > form {
  display: inline-block; margin-top: 8px; text-align: left; width: 230px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 12px;
}
.pw-reset > form label { margin-bottom: 10px; }

/* ---- security posture score (/ dashboard) ----
 * The number, the band and the reasons. Scoring lives in
 * app/posture.py; this file only draws it.
 *
 * Two constraints shape everything below. The CSP is
 * `script-src 'self'`, so the gauge has to arrive already drawn: it is
 * flex boxes with percentage widths, no canvas and no script. And the
 * console has two palettes, so the band colours are derived from the
 * --sev-* custom properties base.html injects (single source:
 * reporting/severity.py) rather than written out here. Those are
 * mid-tone print colours that hold up on both grounds; text stays on
 * --ink and the band colour is used for fills, borders and tints only,
 * so nothing depends on a light or dark background to stay readable.
 */
.posture { margin-bottom: 22px; }
.posture-h { margin: 0 0 12px; }

.posture-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 18px;
  box-shadow: var(--shadow-sm);
  /* base.html always injects --sev-*, from reporting/severity.py.
     No literal colour is written here: this panel has to follow the
     palette, and a hex value would be wrong in one of the two themes. */
  --posture-urgent: var(--sev-critical);
  --posture-risk: var(--sev-high);
  --posture-attention: var(--sev-medium);
  --posture-reasonable: var(--sev-low);
  --posture-strong: var(--accent);
}

/* One hook per band, so every piece of the panel can say "colour me by
   the band I belong to" without the band list being repeated. */
.posture .is-urgent     { --band: var(--posture-urgent); }
.posture .is-risk       { --band: var(--posture-risk); }
.posture .is-attention  { --band: var(--posture-attention); }
.posture .is-reasonable { --band: var(--posture-reasonable); }
.posture .is-strong     { --band: var(--posture-strong); }
/* severity chips reuse the same hook */
.posture .is-critical { --band: var(--sev-critical); }
.posture .is-high     { --band: var(--sev-high); }
.posture .is-medium   { --band: var(--sev-medium); }
.posture .is-low      { --band: var(--sev-low); }
.posture .is-info     { --band: var(--sev-info); }

/* ---- the headline ---- */
.posture-top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px; }
.posture-figure { margin: 0; display: flex; align-items: baseline; gap: 8px; }
.posture-score {
  font-size: 3rem; font-weight: 680; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -.03em;
  color: var(--ink);
}
.posture-outof { font-size: 12px; color: var(--ink-faint);
                 text-transform: uppercase; letter-spacing: .06em; }
.posture-band {
  margin: 0; padding: 4px 11px;
  border-left: 3px solid var(--band, var(--line-strong));
  border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--band, var(--surface-2)) 16%, var(--surface));
  color: var(--ink);
  font-size: 14px; font-weight: 650; letter-spacing: -.01em;
}
.posture-blurb { margin: 0; flex: 1 1 14rem; min-width: 0;
                 font-size: 13px; color: var(--ink-soft); }

/* ---- the gauge ---- */
.posture-gauge { margin: 16px 0 4px; }
.posture-track {
  position: relative; display: flex; height: 13px;
  border-radius: 999px; background: var(--surface-2);
}
.posture-seg { display: block; height: 100%;
               background: color-mix(in srgb, var(--band) 60%, var(--surface)); }
/* The marker is the last child, so the last SEGMENT is second from the
   end. Rounding the ends here rather than clipping the track means the
   marker is never cut in half at 0 or 100. */
.posture-track > .posture-seg:first-child { border-radius: 999px 0 0 999px; }
.posture-track > .posture-seg:nth-last-child(2) { border-radius: 0 999px 999px 0; }
.posture-marker {
  position: absolute; top: -4px; bottom: -4px; width: 4px;
  transform: translateX(-50%);
  border-radius: 999px;
  background: var(--band, var(--ink));
  box-shadow: 0 0 0 2px var(--surface);
}
.posture-scale {
  display: flex; list-style: none; margin: 7px 0 0; padding: 0;
  font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-faint);
}
.posture-scale-item { padding-right: 6px; min-width: 0;
                      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.posture-scale-item.is-here { color: var(--ink); font-weight: 650; }

.posture-why { margin: 14px 0 0; font-size: 12px; color: var(--ink-faint); }
.posture-coverage {
  margin: 10px 0 0; padding: 9px 11px;
  border-left: 3px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface-2); font-size: 12.5px; color: var(--ink-soft);
}
.posture-coverage.is-capped { border-left-color: var(--accent);
                              background: color-mix(in srgb, var(--accent-soft) 70%, var(--surface)); }

/* ---- what is pulling it down ---- */
.posture-sub {
  margin: 20px 0 8px; font-size: 11px; font-weight: 650;
  text-transform: uppercase; letter-spacing: .08em; color: var(--ink-faint);
}
.posture-rows, .posture-drivers { list-style: none; margin: 0; padding: 0; }
.posture-row {
  display: grid; grid-template-columns: auto 1fr auto; gap: 3px 10px;
  align-items: center; padding: 7px 0; border-top: 1px solid var(--line);
}
.posture-row:first-child { border-top: 0; }
.posture-count { font-size: 13px; color: var(--ink-soft); min-width: 0; }
.posture-points { font-size: 13.5px; font-weight: 650;
                  font-variant-numeric: tabular-nums; color: var(--ink); }
/* The share bar sits on its own grid line so a long count sentence can
   wrap on a phone without squeezing it to nothing. */
.posture-barwrap { grid-column: 1 / -1; height: 4px; border-radius: 999px;
                   background: var(--surface-2); overflow: hidden; }
.posture-bar { display: block; height: 100%; background: var(--band, var(--ink-faint)); }

.posture-chip {
  display: inline-block; padding: 1px 8px; border-radius: 999px;
  font-size: 10.5px; font-weight: 650; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink); white-space: nowrap;
  background: color-mix(in srgb, var(--band) 20%, var(--surface));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--band) 38%, transparent);
}

.posture-drivers > li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 9px;
  padding: 7px 0; border-top: 1px solid var(--line); font-size: 13px;
}
.posture-drivers > li:first-child { border-top: 0; }
.posture-drivers a { text-decoration: none; }
.posture-drivers a:hover { text-decoration: underline; }
.posture-tag {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-faint); border: 1px solid var(--line-strong);
  border-radius: 999px; padding: 0 7px;
}
.posture-none, .posture-more, .posture-fp {
  margin: 8px 0 0; font-size: 12.5px; color: var(--ink-faint);
}

[data-density="compact"] .posture-card { padding: 13px; }
[data-density="compact"] .posture-score { font-size: 2.4rem; }

/* 360px with no horizontal overflow. The band scale is the first thing
   to go: it is a legend for a picture whose current value is already
   spelled out in words above it, so losing it costs nothing, whereas
   five labels in five narrow columns either overflow or shred. */
@media (max-width: 560px) {
  .posture-card { padding: 14px; }
  .posture-score { font-size: 2.5rem; }
  .posture-scale { display: none; }
  .posture-row { grid-template-columns: auto 1fr; }
  .posture-points { grid-column: 2; justify-self: end; }
}

/* ---------------------------------------------------------- site footer ---
   One footer for every page (app/templates/_site_footer.html). The body is
   a column so that on a short page the footer sits at the bottom of the
   window rather than halfway up it; on a long page it simply follows the
   content. */
body.site { min-height: 100vh; display: flex; flex-direction: column; }
body.site > main.wrap { flex: 1 0 auto; width: 100%; box-sizing: border-box; }

.site-foot {
  margin-top: 48px;
  border-top: 1px solid var(--line);
  background: color-mix(in srgb, var(--surface) 60%, transparent);
  font-size: 13.5px;
}
.site-foot-in {
  max-width: 1120px; margin: 0 auto; padding: 32px 24px 18px;
  display: grid; grid-template-columns: minmax(0, 2fr) repeat(3, minmax(0, 1fr)); gap: 28px;
}
.site-foot-brand p { margin: 10px 0 0; color: var(--ink-soft); max-width: 40ch; }
.site-foot-col { display: flex; flex-direction: column; gap: 8px; }
.site-foot-col h2 { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: var(--ink); }
.site-foot-col a { color: var(--ink-soft); text-decoration: none; }
.site-foot-col a:hover { color: var(--accent); text-decoration: underline; }
.site-foot-base {
  max-width: 1120px; margin: 0 auto; padding: 14px 24px 26px;
  display: flex; flex-wrap: wrap; gap: 6px 24px; justify-content: space-between;
  border-top: 1px solid var(--line); color: var(--ink-soft); font-size: 12.5px;
}
.site-foot-dim { color: var(--ink-faint); }
.site-foot-brand .site-foot-dim { font-size: 12.5px; }

@media (max-width: 760px) {
  .site-foot-in { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .site-foot-brand { grid-column: 1 / -1; }
}
@media (max-width: 420px) {
  .site-foot-in { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------- registration ---
   The request-access form (app/templates/register.html): wider than the
   sign-in card, grouped into fieldsets, two columns where there is room. */
.auth-card.auth-card-wide { max-width: 760px; }
.reg-form fieldset { border: 0; border-top: 1px solid var(--line); margin: 18px 0 0; padding: 14px 0 0; min-width: 0; }
.reg-form legend { font-weight: 600; color: var(--ink); padding: 0 8px 0 0; font-size: 14.5px; }
.reg-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 4px 18px; }
.reg-grid .reg-span { grid-column: 1 / -1; }
.reg-form label small { display: block; }
.reg-confirm .consent { margin-bottom: 6px; }
.field-error { display: block; color: var(--bad); font-weight: 500; margin-top: 2px; }
[aria-invalid="true"] { border-color: var(--bad) !important; }
.free-check-h { font-size: 1.05rem; margin: 22px 0 4px; }
/* The honeypot: off-screen for people, still in the form for scripts. */
.hp-field { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
@media (max-width: 620px) {
  .reg-grid { grid-template-columns: 1fr; }
}
/* Review flags and details beside a pending registration (Users page). */
.pill-warn { background: color-mix(in srgb, var(--sev-medium, #a9862b) 18%, var(--surface)); color: var(--ink);
  text-transform: none; letter-spacing: 0; font-weight: 500; margin-top: 4px; }
.reg-details { margin-top: 6px; font-size: 13px; }
.reg-details summary { cursor: pointer; color: var(--accent); }
.reg-details dl { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 2px 12px; margin: 6px 0 0; }
.reg-details dt { color: var(--ink-faint); }
.reg-details dd { margin: 0; overflow-wrap: anywhere; }
.reg-note { white-space: pre-wrap; }

/* ---------------------------------------------- house style, Oct 2026 ---
   The signed-in pages in the same voice as the public site (landing.css):
   a wider measure, larger page and section headings, surfaces set apart
   by a step in tone rather than by outlines and shadows, and labels in
   sentence case instead of small tracked capitals. It only restyles:
   every page keeps its content, order and controls. Severity and status
   badges keep their capitals, because they are badges. Kept as one block
   at the end so it reads as one decision and is easy to review. */

/* Shadows only on what floats (the drawer, menus): --shadow-lg stays. */
:root:root:root { --shadow-sm: none; --shadow-md: none; }

body { font-size: 15.5px; line-height: 1.6; }
.wrap { max-width: 1200px; padding: 44px 32px 104px; }
.site-foot-in, .site-foot-base { max-width: 1200px; padding-left: 32px; padding-right: 32px; }

h1 {
  font-size: clamp(1.65rem, 1.25rem + 1vw, 2.15rem);
  font-weight: 650; letter-spacing: -.028em; line-height: 1.15;
}
h2 { font-size: 1.3rem; font-weight: 640; letter-spacing: -.018em; margin: 48px 0 16px; }
h3 { font-size: 1.05rem; font-weight: 620; letter-spacing: -.01em; }
.page-head { margin-bottom: 28px; align-items: center; }
.set-section { margin-bottom: 56px; }
.set-section > h2 { padding-bottom: 0; border-bottom: 0; }
.set-lead { font-size: 14.5px; color: var(--ink-soft); }
.posture-h { margin: 0 0 16px; }

/* Top bar: the page's own ground, like the public header. */
.topbar { background: var(--ground); box-shadow: none; }
body .brand-label { font-size: 17px; font-weight: 650; letter-spacing: -.015em; }

/* Labels: sentence case at a readable size. */
.sidenav-group,
.stat-l, .tile-l, .finding-cat, .finding dt, .kv dt, table.grid th,
.filter-bar label, .inline-form label, fieldset.scan-type legend,
.posture-outof, .posture-scale, .posture-sub, .posture-tag, .role-tag {
  text-transform: none;
  letter-spacing: 0;
}
.sidenav-group { font-size: 13px; font-weight: 600; color: var(--ink-soft); }
.stat-l, .tile-l { font-size: 13.5px; color: var(--ink-soft); }
.tile-l { font-size: 12.5px; }
.finding-cat { font-size: 13px; color: var(--ink-soft); }
.finding dt, .kv dt { font-size: 13.5px; color: var(--ink-soft); }
table.grid th { font-size: 13.5px; font-weight: 600; color: var(--ink-soft); }
.filter-bar label, .inline-form label { font-size: 13.5px; color: var(--ink-soft); }
fieldset.scan-type legend { font-size: 13.5px; color: var(--ink-soft); }
.posture-outof { font-size: 14px; }
.posture-scale { font-size: 12.5px; }
.posture-sub { font-size: 14.5px; font-weight: 620; color: var(--ink); margin-top: 28px; }
.posture-tag, .role-tag { font-size: 12px; }

/* Surfaces: tone, not outlines. */
.card, .posture-card, .stat, .tile, table.grid, .kv, .auth-card,
.recovery-panel, .pending-panel {
  border-color: transparent;
}
.card, .posture-card { padding: 28px; border-radius: 8px; }
.finding { border-width: 0 0 0 3px; border-radius: 8px; padding: 20px 24px; }
.findings { gap: 16px; }
table.grid { font-size: 14.5px; border-radius: 8px; }
table.grid th { background: var(--surface); padding: 14px 16px; }
table.grid td { padding: 13px 16px; }
.kv dd { font-size: 14.5px; }
.kv > div { padding: 14px 20px; }

/* Stat boxes: no gradient edge, no lift. */
.stat { padding: 22px 24px; border-radius: 8px; }
.stat::before { display: none; }
.stat:hover { transform: none; border-color: transparent; }
.stat-n { font-size: 2rem; }
.spark-bar { background: var(--accent); }

.auth-card { border-radius: 10px; padding: 40px; }
.auth-card h1 { font-size: 1.6rem; letter-spacing: -.022em; }
/* Some labels are written in lower case in the markup (the capitals used
   to come from CSS); start them with a capital. */
.stat-l { display: block; }
.stat-l::first-letter, .tile-l::first-letter, .finding-cat::first-letter,
.finding dt::first-letter, .kv dt::first-letter, table.grid th::first-letter,
.posture-sub::first-letter, .posture-scale li::first-letter { text-transform: uppercase; }
.scan-form, .enrol { border-color: transparent; border-radius: 8px; padding: 28px; }
.auth-card { box-shadow: none; }
.legal-switch { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.legal-switch a { margin-left: 0; }
.legal-draft { background: color-mix(in srgb, var(--sev-medium, #a9862b) 16%, var(--surface));
  padding: 14px 18px; border-radius: 8px; color: var(--ink) !important; }
.legal h3 { font-size: .98rem; margin: 22px 0 6px; }
.legal .legal-caps { text-transform: uppercase; font-size: 13.5px; letter-spacing: .01em; }
.legal table { width: 100%; border-collapse: collapse; font-size: 14px; margin: 8px 0 16px; }
.legal th, .legal td { text-align: left; vertical-align: top; padding: 9px 10px; border-bottom: 1px solid var(--line); }
.legal th { font-weight: 600; color: var(--ink); }
.legal td { color: var(--ink-soft); }
/* A scan whose modules did not all complete (ScanResult.incomplete). */
.partial-note { background: color-mix(in srgb, var(--sev-medium, #a9862b) 14%, var(--surface));
  padding: 14px 18px; border-radius: 8px; margin: 0 0 20px; color: var(--ink); }

/* ------------------------------------------------------------ analytics ---
   app/templates/analytics.html. Written in the house style above: tone
   for surfaces, no outlines or shadows, sentence-case labels, large
   numbers. Every chart is inline SVG drawn on the server, so the chart
   rules here are fills and strokes on SVG classes; colors are console
   tokens and --sev-*, so both themes come out right with no extra rules.

   SVG text is sized in viewBox units, so it shrinks with the chart. The
   charts therefore stop shrinking at a minimum width and scroll inside
   their own box on a phone rather than turning their labels to dust. */
.an-sub { margin: 6px 0 0; color: var(--ink-soft); font-size: 14.5px; }

/* ---- headline tiles ---- */
.an-kpis {
  display: grid; gap: 12px; margin: 8px 0 20px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.an-kpi {
  background: var(--surface); border-radius: 8px; padding: 22px 24px 20px;
  display: flex; flex-direction: column; gap: 6px; min-width: 0;
}
.an-kpi p { margin: 0; }
.an-kpi-l { font-size: 13.5px; color: var(--ink-soft); font-weight: 500; }
.an-kpi-v { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; }
.an-kpi-n {
  font-size: 2.35rem; font-weight: 660; line-height: 1.1; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.an-kpi-n2 { margin-left: 10px; }
.an-kpi-unit { font-size: 14px; color: var(--ink-soft); }
.an-kpi-pre { align-self: center; }
.an-kpi-none { font-size: 1.45rem; font-weight: 620; line-height: 1.5; letter-spacing: -.015em; color: var(--ink); }
.an-kpi-s { font-size: 13px; color: var(--ink-soft); line-height: 1.5; }
.an-kpi-sevs { display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: 13px; color: var(--ink-soft); }
.an-dot-item { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.an-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }

.an-better { color: var(--accent-ink); font-weight: 600; }
.an-worse { color: var(--bad); font-weight: 600; }
.an-flat { color: var(--ink-soft); }

/* The band chip, colored by the same ramp as the dashboard's gauge. */
.an-band {
  display: inline-block; margin-right: 6px; padding: 1px 9px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; color: var(--ink);
  background: color-mix(in srgb, var(--band, var(--ink-faint)) 20%, var(--surface));
}
.an-band.is-urgent, .an-score-n.is-urgent, .an-band-label.is-urgent { --band: var(--sev-critical); }
.an-band.is-risk, .an-score-n.is-risk, .an-band-label.is-risk { --band: var(--sev-high); }
.an-band.is-attention, .an-score-n.is-attention, .an-band-label.is-attention { --band: var(--sev-medium); }
.an-band.is-reasonable, .an-score-n.is-reasonable, .an-band-label.is-reasonable { --band: var(--sev-low); }
.an-band.is-strong, .an-score-n.is-strong, .an-band-label.is-strong { --band: var(--accent); }

.an-callout {
  margin: 0 0 20px; padding: 14px 18px; border-radius: 8px; font-size: 14px;
  background: var(--surface-2); color: var(--ink-soft);
}
.an-callout strong { color: var(--ink); font-weight: 620; }
.an-callout-wait { background: var(--accent-soft); color: var(--ink); }

/* ---- sections and panels ---- */
.an-section { margin: 44px 0 20px; }
.an-head { margin-bottom: 14px; }
.an-head h2 { margin: 0; }
.an-note { margin: 4px 0 0; font-size: 13.5px; color: var(--ink-soft); max-width: 72ch; }
.an-card { background: var(--surface); border-radius: 8px; padding: 24px 26px 18px; min-width: 0; }
.an-grid2 {
  display: grid; gap: 12px; margin: 12px 0 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.an-panel { display: flex; flex-direction: column; }
.an-panel .an-chart { margin-top: auto; }
.an-h { margin: 0; font-size: 1.12rem; }
.an-panel > .an-note { margin-bottom: 14px; }
.an-panel > .empty { margin-top: auto; }

.an-legend {
  list-style: none; margin: 0 0 14px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px 20px; font-size: 13.5px; color: var(--ink-soft);
}
.an-key { display: inline-flex; align-items: center; gap: 7px; }
.an-key strong { color: var(--ink); font-weight: 620; font-variant-numeric: tabular-nums; }
.an-key.is-zero { opacity: .55; }
.an-swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; background: var(--line-strong); }
.an-swatch.is-new { background: var(--sev-high); }
.an-swatch.is-resolved { background: var(--accent); }
.an-swatch.is-done { background: var(--accent); }
.an-swatch.is-failed { background: var(--bad); }

/* ---- the SVG charts ---- */
.an-chart { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.an-svg { display: block; width: 100%; height: auto; min-width: 440px; }
.an-chart-main .an-svg { min-width: 600px; }
.an-grid { stroke: var(--line); stroke-width: 1; shape-rendering: crispEdges; }
.an-grid.is-base { stroke: var(--line-strong); }
.an-tick { fill: var(--ink-faint); font-size: 12.5px; font-family: var(--font-sans); font-variant-numeric: tabular-nums; }
.an-chart:not(.an-chart-main) .an-tick { font-size: 14px; }
.an-tick.is-y { text-anchor: end; }
.an-tick.is-x { text-anchor: middle; }
.an-band-label { fill: var(--band, var(--ink-faint)); font-weight: 600; }
.an-seg { stroke: var(--surface); stroke-width: 1.5; }
.an-col-bg { fill: var(--ink); fill-opacity: 0; transition: fill-opacity var(--ease); }
.an-col:hover .an-col-bg { fill-opacity: .045; }
.an-hit { fill: transparent; }
.an-flow.is-new { fill: var(--sev-high); }
.an-flow.is-resolved { fill: var(--accent); }
.an-act.is-done { fill: var(--accent); }
.an-act.is-failed { fill: var(--bad); }
.an-line { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.an-point { fill: var(--surface); stroke: var(--accent); stroke-width: 2; }
.an-point.is-last { fill: var(--accent); stroke: var(--surface); stroke-width: 2.5; }
.an-point:hover { fill: var(--accent); }

/* ---- categories: plain HTML bars, so they reflow on a phone ---- */
.an-cats { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.an-cat {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 5px 12px; align-items: baseline;
}
.an-cat-name { font-size: 14px; color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
.an-cat-n { font-size: 14px; font-weight: 640; font-variant-numeric: tabular-nums; }
.an-cat-track { grid-column: 1 / -1; height: 10px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.an-cat-bar { display: flex; height: 100%; border-radius: 999px; overflow: hidden; gap: 2px; }
.an-cat-seg { display: block; height: 100%; min-width: 3px; }
.an-cat-detail { grid-column: 1 / -1; font-size: 12.5px; color: var(--ink-faint); }

/* ---- tables ---- */
.an-table td { vertical-align: middle; }
.an-finding a { font-weight: 560; }
.an-asset { display: block; font-size: 12.5px; color: var(--ink-faint); font-family: var(--font-mono); overflow-wrap: anywhere; }
.an-tag {
  display: inline-block; margin-left: 6px; padding: 0 8px; border-radius: 999px;
  font-size: 12px; color: var(--ink-soft); background: var(--surface-2); white-space: nowrap;
}
.an-sev { display: inline-flex; align-items: center; gap: 7px; font-size: 13.5px; color: var(--ink); white-space: nowrap; }
.an-sev::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--sev); }
table.grid td.an-age { color: var(--ink); white-space: nowrap; }
table.grid td.an-strong { color: var(--ink); font-weight: 620; }
.an-zero { color: var(--ink-faint); font-weight: 400; }   /* quiet, but AA in both themes */
.an-score-n {
  display: inline-block; min-width: 2.6em; text-align: center; padding: 1px 8px; border-radius: 999px;
  font-weight: 640; color: var(--ink);
  background: color-mix(in srgb, var(--band, var(--ink-faint)) 20%, var(--surface));
}
.an-spark { display: block; width: 112px; height: 30px; }
.an-spark polyline { fill: none; stroke: var(--ink-soft); stroke-width: 1.75; stroke-linejoin: round; stroke-linecap: round; }
.an-nowrap { white-space: nowrap; }
.an-targets { min-width: 900px; }
.an-foot { margin: 12px 0 0; font-size: 13px; color: var(--ink-faint); }
.an-warn { color: var(--ink-soft); }

/* ---- empty ---- */
.an-empty { background: var(--surface); border-radius: 8px; padding: 32px 32px 28px; max-width: 760px; }
.an-empty h2 { margin: 0 0 8px; }
.an-empty p { margin: 8px 0 0; color: var(--ink-soft); }

[data-density="compact"] .an-kpi { padding: 14px 16px; }
[data-density="compact"] .an-kpi-n { font-size: 1.8rem; }
[data-density="compact"] .an-card { padding: 16px 18px 12px; }

@media (max-width: 900px) {
  .an-grid2 { grid-template-columns: minmax(0, 1fr); }
  .an-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .an-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .an-kpi { padding: 16px; }
  .an-kpi-n { font-size: 1.8rem; }
  .an-kpi-none { font-size: 1.15rem; }
  .an-card { padding: 18px 16px 12px; }
  .an-empty { padding: 22px 18px; }
}
@media (max-width: 380px) {
  .an-kpis { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------- portal layout and components ---
   A permanent sidebar on wide screens, one page header, one empty state
   and one status pill. Markup lives in base.html and _ui.html. Written in
   the house style above: tone steps instead of rules, sentence case, no
   shadows at rest. Kept last so it reads as one decision. */

:root { --sidenav-w: 248px; }

/* ---- side nav: brand, groups, links ---- */
.sidenav-head { border-bottom: 0; padding: 0 0 8px; margin-bottom: 2px; gap: 6px; }
.sidenav a.sidenav-brand {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 12px; color: var(--ink); background: none;
}
.sidenav a.sidenav-brand:hover { background: none; color: var(--ink); }
.sidenav-brand .mark { display: block; width: 22px; height: 22px; flex: none; color: var(--accent); }
.sidenav-title { font-size: 17px; font-weight: 650; letter-spacing: -.015em; }
.sidenav-who { padding: 0 12px; }
.sidenav-group {
  border-top: 0; margin: 22px 0 6px; padding: 0 12px;
  font-size: 12.5px; font-weight: 600; color: var(--ink-faint);
}
.sidenav-group:first-of-type { margin-top: 14px; }
.sidenav-foot { border-top: 0; padding-top: 18px; }
.sidenav a { font-size: 14.5px; font-weight: 500; }
.sidenav a.active { font-weight: 600; }

/* ---- permanent sidebar from 1100px ----
   The same nav element, pinned open: no toggle, no scrim, no slide. The
   top bar keeps the account and Sign out, and loses its own logo, which
   now heads the sidebar. Below 1100px everything above (the drawer) is
   unchanged. */
@media (min-width: 1100px) {
  body.has-nav { padding-left: var(--sidenav-w); }
  .has-nav .nav-toggle,
  .has-nav .nav-scrim,
  .has-nav .topbar .brand { display: none; }
  .has-nav .sidenav {
    top: 0; width: var(--sidenav-w); max-width: none; z-index: 25;
    padding: 18px 14px 22px;
    transform: none; visibility: visible; transition: none;
    background: var(--surface); border-right: 0; box-shadow: none;
  }
  .has-nav .topbar { padding: 0 32px; border-bottom-color: transparent; }
  .has-nav .logout { margin-left: auto; }
  body.has-nav.nav-open { overflow: visible; }
  body.has-nav > main.wrap { max-width: 1160px; padding-top: 28px; }
  .has-nav .site-foot-in, .has-nav .site-foot-base { max-width: 1160px; }
}

/* ---- page header ----
   Back link, title, one line of description; the actions at the right,
   level with the last line of the title block. */
.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px 32px; margin: 0 0 36px;
}
.page-head-main { min-width: 0; flex: 1 1 auto; }
.page-head-main > p { margin: 10px 0 0; }
.page-desc, .page-head-main > p.dim {
  font-size: 15px; line-height: 1.55; color: var(--ink-soft); max-width: 72ch;
}
.page-head .back {
  display: inline-flex; margin: 0 0 12px; font-size: 14px; font-weight: 500;
  color: var(--ink-soft); text-decoration: none; transition: color var(--ease);
}
.page-head .back:hover { color: var(--accent-ink); }
.page-head-main > .partial-note { margin-top: 16px; }
.page-head-main > .cf-mods { margin-top: 12px; }
.page-actions { flex: none; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
[data-density="compact"] .page-head { margin-bottom: 22px; }

/* ---- empty state ---- */
.empty-state {
  display: flex; align-items: flex-start; gap: 16px;
  padding: 24px 26px; border-radius: 8px; background: var(--surface);
}
.empty-state-icon {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 8px;
  background: var(--accent-soft); color: var(--accent-ink);
}
.empty-state-icon .ui-icon { display: block; }
.empty-state-body { min-width: 0; padding-top: 1px; }
.empty-state-title { margin: 0; font-size: 15.5px; font-weight: 620; line-height: 1.45; color: var(--ink); }
.empty-state-text { margin: 4px 0 0; font-size: 14.5px; line-height: 1.55; color: var(--ink-soft); max-width: 64ch; }
.empty-state-meta { margin: 8px 0 0; font-size: 13.5px; color: var(--ink-soft); }
.empty-state-meta + .empty-state-meta { margin-top: 2px; }
.empty-state-action { margin: 16px 0 0; display: flex; flex-wrap: wrap; gap: 10px; }
.empty-state.is-compact { padding: 6px 0; gap: 12px; background: none; }
.empty-state.is-compact .empty-state-icon { width: 32px; height: 32px; border-radius: 7px; }
.empty-state.is-compact .empty-state-title { font-size: 14.5px; padding-top: 4px; }
[data-density="compact"] .empty-state { padding: 16px 18px; }
[data-density="compact"] .empty-state.is-compact { padding: 4px 0; }
/* A notice that is not an empty list (a limit reached, a security note)
   keeps the older .empty class: the same surface, no dashed frame. */
.empty {
  padding: 16px 20px; border: 0; border-radius: 8px;
  background: var(--surface); color: var(--ink-soft); font-size: 14.5px;
}
.empty small { font-size: 13.5px; color: var(--ink-faint); }
.card > .empty, .posture-card .empty, .pending-panel .empty { padding: 8px 0; background: none; }

/* ---- status pill ----
   One shape for every state: a dot in the state's color and a
   sentence-case label on a light tint. Tones are good, warn, bad, info
   (in progress) and neutral, all from the console tokens. A pill with no
   tone is a plain tag (a count, "you", a check name) and has no dot. The
   older pill-<state> classes map onto the same tones. */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 1px 9px; border-radius: 999px; vertical-align: middle;
  font-size: 12.5px; font-weight: 550; line-height: 1.55; white-space: nowrap;
  text-transform: none; letter-spacing: 0;
  background: var(--surface-2); color: var(--ink-soft);
}
/* A sentence in a pill (a report status, a review flag) may wrap. */
.pill.pill-wrap, .pill-warn { white-space: normal; }
.pill.is-good, .pill.is-info, .pill.is-warn, .pill.is-bad,
.pill-done, .pill-running, .pill-warn, .pill-error { color: var(--ink); }
.pill.is-good::before, .pill.is-info::before, .pill.is-warn::before,
.pill.is-bad::before, .pill.is-neutral::before,
.pill-done::before, .pill-running::before, .pill-warn::before,
.pill-error::before, .pill-queued::before {
  content: ""; flex: none; width: 7px; height: 7px; border-radius: 50%;
  background: var(--st, var(--ink-faint));
}
/* Tint and dot strength per theme: a dark surface needs more of the
   state color to show, and a lighter dot to read against it. */
:root { --pill-tint: 14%; --pill-dot-lift: 0%; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --pill-tint: 26%; --pill-dot-lift: 30%; }
}
:root[data-theme="dark"] { --pill-tint: 26%; --pill-dot-lift: 30%; }
.pill.is-good::before, .pill.is-info::before, .pill.is-warn::before,
.pill.is-bad::before, .pill-done::before, .pill-running::before,
.pill-warn::before, .pill-error::before {
  background: color-mix(in srgb, var(--st) calc(100% - var(--pill-dot-lift)), var(--ink));
}
.pill.is-good, .pill-done {
  --st: var(--sev-low); background: color-mix(in srgb, var(--sev-low) var(--pill-tint), var(--surface));
}
.pill.is-info, .pill-running { --st: var(--accent); background: var(--accent-soft); }
.pill.is-warn, .pill-warn {
  --st: var(--sev-medium); background: color-mix(in srgb, var(--sev-medium) var(--pill-tint), var(--surface));
}
.pill.is-bad, .pill-error {
  --st: var(--bad); background: color-mix(in srgb, var(--bad) var(--pill-tint), var(--surface));
}
.pill.is-neutral, .pill-queued { --st: var(--ink-faint); background: var(--surface-2); color: var(--ink-soft); }
.diff-h .pill { margin-left: 6px; font-variant-numeric: tabular-nums; }
.posture-h .pill, h2 .pill { margin-left: 8px; }

/* A domain's actions (Check now, Remove) on one row. */
.set-section > .act-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* ---- posture: change since the previous score ---- */
.posture-delta { margin: 0; font-size: 14px; font-weight: 600; white-space: nowrap; color: var(--ink-soft); }
.posture-top .posture-blurb { flex-basis: 100%; margin-top: 6px; font-size: 14px; }
.posture-delta.is-up { color: var(--accent-ink); }
.posture-delta.is-down { color: var(--bad); }

/* Phone gutters. The house-style .wrap padding above comes after the
   880px rule that set 16px, so it is restated here, last. */
@media (max-width: 880px) {
  body.site > main.wrap { padding: 24px 16px 72px; }
  .site-foot-in, .site-foot-base { padding-left: 16px; padding-right: 16px; }
}
@media (max-width: 560px) {
  .page-head { flex-direction: column; align-items: flex-start; margin-bottom: 26px; }
  .empty-state { padding: 18px 16px; gap: 12px; }
  .empty-state-icon { width: 34px; height: 34px; }
}

/* ------------------------------------------- portal polish, part two ---
   Tables, forms, success toasts, focus, spacing and phones, building on
   the portal components block above. Same house style: tone steps, no
   shadows at rest (only what floats), sentence case. Kept last so it
   reads as one decision. */

/* ---- spacing scale ----
   Page header to first section 32, section to section 48, an alert or a
   notice to what follows 24, field to field 20. */
:root {
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;
}
.page-head { margin-bottom: var(--sp-6); }
.set-section { margin-bottom: var(--sp-7); }
.set-section > h2:first-child { margin-top: 0; }
.set-section .set-section { margin-bottom: var(--sp-6); }
.cards { margin-bottom: var(--sp-7); }
/* One h3 size: .set-sub and .diff-h are h3s by another name. */
.set-sub, .diff-h { font-size: 1.05rem; font-weight: 620; letter-spacing: -.01em; }
.who { font-size: 13.5px; }

/* ---- skip link and focus ---- */
/* Read by screen readers, not drawn: the heading of the row-actions
   column, for one. */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 12px; top: -200px; z-index: 100;
  padding: 10px 16px; border-radius: var(--r-sm);
  background: var(--accent); color: var(--on-accent);
  font-size: 14.5px; font-weight: 600; text-decoration: none;
}
.skip-link:focus { top: 10px; }
main.wrap:focus { outline: none; }
/* The sidebar scrolls, so a ring drawn outside a link is clipped at its
   left edge. Drawn inside instead. */
.sidenav a:focus-visible { outline-offset: -2px; }
.btn-primary:focus-visible, .btn-secondary:focus-visible { outline-offset: 3px; }

/* ---- tables ----
   A quiet header that stays put while a long table scrolls, a light
   hover, numbers right-aligned in tabular figures, and the row actions
   last and flush right. The corners are rounded on the cells, not by
   clipping the table, because a clipped table cannot have a sticky
   header. */
table.grid { overflow: visible; }
table.grid thead th {
  position: sticky; top: 0; z-index: 2;
  padding: 12px 16px; vertical-align: bottom; white-space: nowrap;
  font-size: 13px; font-weight: 600; color: var(--ink-soft);
  background: var(--surface);
  border-bottom: 0; box-shadow: inset 0 -1px 0 var(--line-strong);
}
table.grid thead th:first-child { border-top-left-radius: 8px; }
table.grid thead th:last-child { border-top-right-radius: 8px; }
table.grid tbody tr:last-child > td:first-child { border-bottom-left-radius: 8px; }
table.grid tbody tr:last-child > td:last-child { border-bottom-right-radius: 8px; }
table.grid td { padding: 13px 16px; overflow-wrap: break-word; }
table.grid tbody tr:hover { background: none; }
table.grid tbody tr > td { transition: background-color var(--ease); }
table.grid tbody tr:hover > td { background: color-mix(in srgb, var(--surface-2) 65%, var(--surface)); }
table.grid th.num, table.grid td.num {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
}
table.grid .tnum { font-variant-numeric: tabular-nums; }
table.grid th.row-actions, table.grid td.row-actions { width: 1%; text-align: right; white-space: nowrap; }
table.grid td.row-actions.user-actions { width: auto; white-space: normal; }
/* A long value in a narrow column: one line, cut with an ellipsis, the
   whole value in the title attribute. */
.cell-clip {
  display: block; max-width: 32ch; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}

/* The scroll box. A long table scrolls inside it under its own sticky
   header; a wide one scrolls sideways, and console.js marks the side
   that has more so the edge fades out there. */
.table-scroll { position: relative; border-radius: 8px; }
@media (min-width: 641px) {
  .table-scroll { max-height: max(420px, calc(100vh - 160px)); overflow: auto; overscroll-behavior-x: contain; }
}
.table-scroll.can-scroll-right {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent);
}
.table-scroll.can-scroll-left {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 48px), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 48px), transparent);
}
.table-scroll.can-scroll-left.can-scroll-right {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 48px, #000 calc(100% - 48px), transparent);
}
[data-density="compact"] table.grid thead th { padding: 8px 10px; }
[data-density="compact"] table.grid td { padding: 7px 10px; }

/* ---- forms ----
   Label above the field in the body color, help text under it, 20px
   between fields, every control the same height and full width inside
   the form box. The longer forms take two columns on a wide screen:
   fields and fieldsets sit side by side, and anything else (the button,
   a note, a checkbox line) spans the row. .f-full makes a field span,
   .f-new starts a new row. */
button, input, select, textarea { font-family: inherit; }
.scan-form label, .pw-reset > form label { margin-bottom: 20px; font-size: 14px; font-weight: 500; color: var(--ink); }
.scan-form label .dim, .pw-reset > form label .dim { font-weight: 400; }
.scan-form label.radio, .scan-form label.consent { font-weight: 400; margin-bottom: 0; }
.scan-form label.consent { margin: 4px 0 20px; font-size: 14px; color: var(--ink-soft); }
.scan-form label.radio { margin: 8px 0; color: var(--ink); }
.scan-form input:not([type=checkbox]):not([type=radio]):not([type=hidden]),
.scan-form select, .scan-form textarea {
  display: block; width: 100%; margin-top: 6px;
  min-height: 40px; padding: 9px 12px; border-radius: 6px;
  font-size: 14.5px; font-weight: 400;
}
.scan-form small, .pw-reset > form small {
  display: block; margin-top: 6px; font-size: 13px; font-weight: 400;
  line-height: 1.5; color: var(--ink-faint);
}
.scan-form > small { margin-top: 12px; }
.scan-form > button, .scan-form > .btn-primary { margin-top: 4px; }
fieldset.scan-type { margin: 0 0 20px; padding: 12px 16px 10px; border-color: var(--line-strong); min-width: 0; }
fieldset.scan-type legend { padding: 0 6px; font-size: 14px; font-weight: 500; color: var(--ink); }
fieldset.scan-type > small { margin: 8px 0 4px; }
.form-stack { min-width: 0; }

@media (min-width: 960px) {
  .scan-form.form-grid {
    max-width: 880px;
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 28px; align-items: start;
  }
  .form-grid > * { grid-column: 1 / -1; }
  .form-grid > label:not(.consent):not(.f-full),
  .form-grid > fieldset:not(.f-full),
  .form-grid > .form-stack { grid-column: auto; }
  .scan-form.form-grid > .f-new:not(.f-full) { grid-column: 1; }
  .form-grid > button, .form-grid > .btn-primary { justify-self: start; }
  .form-grid > fieldset.scan-type { align-self: stretch; }
}

/* An error is an alert at the top of the form or the page: a red rule
   at the left on a faint red ground, never a toast. */
p.form-error, div.form-error {
  margin: 0 0 var(--sp-5); padding: 12px 16px;
  border: 0; border-left: 3px solid var(--bad); border-radius: 8px;
  background: color-mix(in srgb, var(--bad) 9%, var(--surface));
  color: var(--ink); font-size: 14.5px; line-height: 1.55;
}
p.form-error a { color: var(--ink); font-weight: 600; }

/* ---- success toast ----
   _ui.html toast(), driven by console.js. Pinned below the top bar at
   the right; the <noscript> block in base.html puts it back in the flow
   when there is no script to fade it. */
.toast {
  position: fixed; z-index: 60;
  top: calc(var(--topbar-h) + 12px); right: 24px;
  display: flex; align-items: flex-start; gap: 10px;
  width: max-content; max-width: min(420px, calc(100vw - 32px)); margin: 0;
  padding: 12px 12px 12px 16px; border-radius: 8px;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-strong); box-shadow: var(--shadow-lg);
  font-size: 14.5px; line-height: 1.5;
  animation: toast-in 220ms cubic-bezier(.2, .8, .2, 1);
  transition: opacity 240ms ease, transform 240ms ease;
}
.toast::before {
  content: ""; flex: none; width: 8px; height: 8px; margin-top: 7px; border-radius: 50%;
  background: var(--sev-low);
}
.toast-text { min-width: 0; padding-right: 4px; }
.toast[hidden] { display: none; }
.toast.is-leaving { opacity: 0; transform: translateY(-6px); }
.toast-close {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin: -3px 0 -3px 2px; padding: 0;
  border: 0; border-radius: 6px; background: none; cursor: pointer;
  color: var(--ink-soft); font-size: 18px; line-height: 1;
}
.toast-close:hover { background: var(--surface-2); color: var(--ink); }
@keyframes toast-in { from { opacity: 0; transform: translateY(-8px); } }
@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; transition: none; }
}
@media (max-width: 880px) {
  .toast { left: 16px; right: 16px; width: auto; max-width: none; top: calc(var(--topbar-h) + 8px); }
}

/* ---- phones: tables as stacked cards ----
   The main customer tables (findings, targets, scheduled scans, emailed
   reports, team, recent scans) carry a data-label on each cell and the
   .table-stack box. Under 640px each row becomes a card with every value
   labeled; the cell without a label is the card's title, and the row
   actions sit along the bottom. Other tables keep scrolling sideways in
   their box, with the fade above. */
@media (max-width: 640px) {
  .table-stack { overflow: visible; max-height: none; border-radius: 0; }
  .table-stack.can-scroll-left, .table-stack.can-scroll-right { -webkit-mask-image: none; mask-image: none; }
  .table-stack > table.grid { display: block; min-width: 0; background: none; border: 0; font-size: 14.5px; }
  .table-stack > table.grid > thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;
  }
  .table-stack > table.grid > tbody { display: flex; flex-direction: column; gap: 10px; }
  .table-stack > table.grid > tbody > tr {
    display: flex; flex-direction: column;
    padding: 4px 16px; border-radius: 8px; background: var(--surface);
  }
  /* The title leads the card even where it is not the first column. */
  .table-stack > table.grid > tbody > tr > td.cell-primary { order: -1; }
  .table-stack > table.grid > tbody > tr.row-self { box-shadow: inset 3px 0 0 var(--accent); }
  .table-stack > table.grid > tbody > tr > td {
    display: block; position: relative; min-height: 40px;
    padding: 10px 0 10px calc(36% + 12px);
    border-bottom: 1px solid var(--line); border-radius: 0 !important;
    background: none !important; text-align: left; white-space: normal; width: auto;
    overflow-wrap: anywhere;
  }
  .table-stack > table.grid td::before {
    content: attr(data-label);
    position: absolute; left: 0; top: 12px; width: 36%; line-height: 1.4;
    font-size: 13px; font-weight: 500; color: var(--ink-soft); overflow-wrap: break-word;
  }
  .table-stack > table.grid > tbody > tr > td:not([data-label]) { padding-left: 0; min-height: 0; }
  .table-stack > table.grid td:not([data-label])::before { content: none; }
  .table-stack > table.grid > tbody > tr > td.cell-primary { padding-top: 14px; font-size: 15.5px; font-weight: 600; }
  .table-stack > table.grid td.cell-primary a { font-weight: 600; }
  .table-stack > table.grid > tbody > tr > td:last-child { border-bottom: 0; }
  .table-stack > table.grid > tbody > tr > td.row-actions { padding: 12px 0 14px; }
  .table-stack > table.grid td.row-actions:empty { display: none; }
  .table-stack .row-actions-list { justify-content: flex-start; flex-wrap: wrap; }
  .table-stack td.row-actions > .inline-form + .inline-form { margin-left: 6px; }
  .table-stack .an-nowrap { white-space: normal; }

  /* Filter bars: two even columns rather than a ragged run of selects. */
  .filter-bar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .filter-bar select { width: 100%; min-width: 0; }
  .filter-bar > .btn-primary, .filter-bar > .link-btn, .filter-bar > button { justify-self: stretch; }
}
@media (pointer: coarse), (max-width: 560px) {
  .btn-primary.btn-sm { min-height: 44px; }
}

/* ---- scrollbars ----------------------------------------------------
   A thin, rounded thumb in the theme's faint ink on a clear track, so
   the page, tables and the sidebar scroll without a gray system bar.
   Tokens are built from --ink-faint, so light and dark follow the theme.
   Chrome, Edge and Firefox use the standard properties; Safari uses the
   ::-webkit-scrollbar rules (Chrome ignores those once the standard ones
   are set). */
:root {
  --scroll-thumb: color-mix(in srgb, var(--ink-faint) 45%, transparent);
  --scroll-thumb-hover: color-mix(in srgb, var(--ink-faint) 80%, transparent);
}
html { scrollbar-color: var(--scroll-thumb) transparent; }
* { scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb); border-radius: 999px;
  border: 2px solid transparent; background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }
::-webkit-scrollbar-corner { background: transparent; }
/* The sidebar's own bar shows only while the pointer is over it, so a
   short window does not draw a second bar beside the page's. */
#sidenav { scrollbar-color: transparent transparent; }
#sidenav:hover, #sidenav:focus-within { scrollbar-color: var(--scroll-thumb) transparent; }
#sidenav::-webkit-scrollbar-thumb { background: transparent; }
#sidenav:hover::-webkit-scrollbar-thumb { background: var(--scroll-thumb); background-clip: padding-box; }

/* ---- QA fixes: auth-public ---- */
/* Phone-safe request-access form: a long Country name must not widen the
   column, and every input type gets the same box (tel was unstyled). */
.reg-grid > * { min-width: 0; }
form select { max-width: 100%; }
form input[type=tel], form input[type=url], form input[type=number], form input[type=search] {
  display: block; width: 100%; margin-top: 5px;
  padding: 9px 11px; font-size: 14px; font-family: inherit; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 6px;
}
form .reg-grid select, .reg-form select { width: 100%; }
@media (max-width: 620px) {
  .reg-grid { grid-template-columns: minmax(0, 1fr); }
}
/* A long organization name or address in a heading wraps instead of
   pushing the page sideways. */
h1, h2, h3, .page-head-main { overflow-wrap: anywhere; }
.page-head > :first-child { min-width: 0; }

/* Notices on the sign-in family of pages. */
.form-notice {
  margin: 0 0 16px; padding: 10px 12px; font-size: 13.5px; line-height: 1.5;
  color: var(--ink); background: var(--accent-soft, var(--surface-2, var(--surface)));
  border: 1px solid var(--line-strong); border-radius: 6px;
}
.form-notice p { margin: 0 0 8px; }
.form-notice form { margin: 0; }
.form-notice a { color: var(--accent-ink, var(--accent)); font-weight: 600; }
.reg-intro { margin: 0 0 18px; padding: 14px 16px; border: 1px solid var(--line-strong);
  border-radius: 8px; background: var(--surface-2, var(--surface)); }
.reg-intro p { margin: 0 0 8px; font-size: 14px; color: var(--ink-soft); }
.reg-intro p:last-child { margin-bottom: 0; }
.reg-intro strong { color: var(--ink); }

/* The error page (app/templates/error.html). */
.error-card { max-width: 520px; margin: 40px auto; }
.error-code { margin: 0 0 6px; font-size: 12.5px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-faint); }
.error-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 22px 0 0; }
.error-actions .btn-primary, .error-actions .btn-secondary {
  width: auto; text-decoration: none; display: inline-block; }

/* Settings: one column width for every card. */
.settings-page .set-lead,
.settings-page .kv,
.settings-page .scan-form,
.settings-page .two-up,
.settings-page .recovery-panel,
.settings-page .enrol,
.settings-page .code-block { max-width: 720px; }
.settings-page .scan-form.form-grid { max-width: 720px; width: auto; }
.settings-page .two-up .scan-form { max-width: none; }
.settings-page .set-required { padding: 12px 14px; border: 1px solid var(--line-strong);
  border-radius: 8px; color: var(--ink); background: var(--surface-2, var(--surface)); }

/* The compact footer inside the portal: legal links and the copyright. */
.site-foot-compact { padding-top: 0; }
.site-foot-compact .site-foot-base { margin-top: 0; display: flex; flex-wrap: wrap;
  justify-content: space-between; gap: 8px 24px; }
.site-foot-links { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.site-foot-links a { color: var(--ink-soft); text-decoration: none; }
.site-foot-links a:hover { color: var(--accent); text-decoration: underline; }

/* ---- QA fixes: staff-jobs ---- */
.pending-panel { margin: 0; padding: 0; background: none; border: 0; box-shadow: none; }
.pending-panel .table-scroll { margin: 0; }
label.org-admin-pick { display: block; flex: none; margin: 8px 0 10px; font-weight: 400; }
label.org-admin-pick input { margin-right: 6px; }
label.org-admin-pick small { display: block; margin: 2px 0 0 22px; max-width: 46ch; }
.user-actions { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; justify-content: flex-end; }
.user-actions .act-line { display: inline-flex; gap: 6px; }
.user-actions details.pw-reset { margin: 0; }
.user-actions details.pw-reset > summary { cursor: pointer; font-size: 13px; color: var(--accent); }
.audit-detail { margin: 0; display: grid; gap: 2px; }
.audit-detail div { display: flex; gap: 6px; flex-wrap: wrap; }
.audit-detail dt { color: var(--ink-faint); }
.audit-detail dt::after { content: ":"; }
.audit-detail dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
td.detail { max-width: 420px; overflow: visible; }
.scan-form fieldset.scan-type label.radio { margin: 0; padding: 0; min-height: 34px; align-items: center; }

/* ---- QA fixes: portal ---- */
[data-only-state][hidden] { display: none !important; }

/* Alerts: the choices sit in a quiet group, and the help text has room. */
fieldset.cf-radio { border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); padding: 14px 18px 16px; margin: 14px 0 18px; min-width: 0; max-width: 640px; }
fieldset.cf-radio legend { padding: 0 6px; font-size: 13.5px; }
fieldset.cf-radio label { padding: 4px 0; }
.alerts-help { margin-top: 20px; max-width: 64ch; }

/* New or edited emailed report: the note and the form are one column. */
.scan-form.form-grid { max-width: 880px; }
.page-head ~ p.empty[role="note"] { max-width: 880px; margin-bottom: 16px; }
.scan-form.form-grid > small { display: block; margin: 0 0 4px; line-height: 1.5; }
.scan-form.form-grid > small + label { margin-top: 12px; }
.scan-form.form-grid > button + small { margin-top: 4px; }

/* Scan page */
.age-headline { margin: 6px 0 0; font-size: 14.5px; color: var(--ink-soft); }
.finding-age { font-size: 14.5px; margin: -2px 0 10px; }
.page-actions .rescan-form { margin: 0; display: flex; }
.page-head-main .dim { overflow-wrap: anywhere; }
.partial-note.held-note { margin-top: 14px; }
details.sev-group { margin: 0 0 18px; }
details.sev-group > summary { display: flex; align-items: center; gap: 10px; cursor: pointer; padding: 8px 0; list-style: none; }
details.sev-group > summary::-webkit-details-marker { display: none; }
details.sev-group > summary::before { content: ""; width: 0; height: 0; border-left: 6px solid var(--ink-faint); border-top: 4px solid transparent; border-bottom: 4px solid transparent; margin-right: 2px; }
details.sev-group[open] > summary::before { border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 6px solid var(--ink-faint); border-bottom: 0; }
details.sev-group > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sev-group-n { color: var(--ink-soft); font-size: 14px; }
details.sev-group > .findings { margin-top: 6px; }
.triage-where { overflow-wrap: anywhere; }

/* Filters: one "Apply" style; Sort by travels with its buttons. */
.filter-bar .filter-last { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.filter-bar .btn-secondary.btn-sm, .filter-bar .link-btn { align-self: flex-end; }

/* Assets: the status control is one line. */
.row-actions form.inline-form { flex-wrap: nowrap; align-items: center; gap: 8px; }
.row-actions form.inline-form select { width: auto; min-width: 9rem; }

/* Domains: the TXT record as a small table with copy buttons. */
table.dns-record { min-width: 0; width: auto; max-width: 100%; margin: 4px 0 10px; }
table.dns-record td { vertical-align: middle; }
table.dns-record td code { overflow-wrap: anywhere; }
/* The record type is one short word: never let it wrap letter by letter. */
table.dns-record td[data-label="Type"] { white-space: nowrap; min-width: 4.5ch; }
table.dns-record td[data-label="Type"] code { overflow-wrap: normal; }
table.dns-record td .btn-secondary { margin-left: 8px; vertical-align: middle; }
.dns-help { max-width: 70ch; font-size: inherit; color: var(--ink-soft); }
.act-line .btn-primary.btn-sm, .act-line .link-btn { height: 34px; }
.card.next-step { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-bottom: 18px; }
.field-error { margin-top: 6px; font-size: 13px; }

@media (max-width: 640px) {
  /* A finding card on a phone: the title gets the full width. */
  .finding > header { flex-wrap: wrap; row-gap: 6px; }
  .finding > header h3 { flex: 1 1 100%; order: 3; }
  .finding > header .finding-cat { margin-left: auto; }
  .finding { padding: 16px 16px; }
  .page-head { flex-wrap: wrap; }
  table.dns-record td code { font-size: 12px; }
  table.dns-record td .btn-secondary { display: block; margin: 6px 0 0; }
  fieldset.cf-radio { padding: 12px 14px; }
}
table.dns-record .btn-secondary.btn-sm { height: 34px; font-size: 12.5px; padding: 0 12px; }
.set-section p > a.link-btn { margin-left: 10px; }

/* ---- QA fixes: leftovers (October 21) ---- */

/* Domains: a field error is red like every other (the small-print rule
   above made it grey), and the help under the TXT record reads as help. */
.scan-form small.field-error { color: var(--bad); font-weight: 500; }
.dns-help { font-size: 14.5px; margin-top: 14px; }
.act-line .btn-secondary.btn-sm {
  display: inline-flex; align-items: center; height: 34px; padding: 0 13px; font-size: 13px;
}

/* Domains on a phone: the TXT record stacks as Type, Name and Value rows,
   each with its label, instead of a table wider than the screen. */
@media (max-width: 640px) {
  .table-scroll > table.grid.dns-record { min-width: 0; }
  table.dns-record, table.dns-record tbody, table.dns-record tr, table.dns-record td {
    display: block; width: 100%;
  }
  table.dns-record thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0);
  }
  table.dns-record td { padding: 10px 14px; border-bottom: 1px solid var(--line); }
  table.dns-record tr > td:last-child { border-bottom: 0; }
  table.dns-record td::before {
    content: attr(data-label); display: block; margin-bottom: 4px;
    font-size: 12px; font-weight: 600; color: var(--ink-faint);
  }
  table.dns-record td code { word-break: break-all; }
  table.dns-record td .btn-secondary { display: inline-flex; margin: 8px 0 0; }
}

/* Two-factor setup: the manual key in blocks of four that never split. */
.enrol-secret { word-break: normal; overflow-wrap: normal; }
.enrol-secret span { white-space: nowrap; }

/* Staff users: the approve form lines its fields up (role and organization
   side by side, the button under them on the left), the "You" row's
   highlight reaches the last cell, and every row action looks the same
   (small outlined buttons, the open one taking the full width below). */
form.approve-form {
  display: grid; grid-template-columns: minmax(10rem, 13rem) minmax(12rem, 18rem);
  gap: 8px 12px; align-items: end; justify-content: start;
}
form.approve-form > label select { width: 100%; }
form.approve-form > label.org-admin-pick { grid-column: 1 / -1; margin: 4px 0 2px; }
form.approve-form > button { grid-column: 1; justify-self: start; }
table.grid td.row-actions.user-actions { display: table-cell; }
.user-actions-in {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center; justify-content: flex-end;
}
.user-actions-in .act-line { display: inline-flex; gap: 6px; }
.user-actions-in .act-line > small { white-space: normal; text-align: right; }
.user-actions .pw-reset:not([open]) { margin-right: 0; }
.user-actions-in details.pw-reset[open] { flex-basis: 100%; text-align: right; }
.user-actions-in details.pw-reset > summary {
  display: inline-flex; align-items: center; height: 28px; padding: 0 10px;
  font-size: 12.5px; font-weight: 500; line-height: 1; white-space: nowrap;
  color: var(--ink); text-decoration: none; background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: 6px;
}
.user-actions-in details.pw-reset > summary:hover {
  background: var(--surface-2); color: var(--accent-ink);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line-strong));
}

/* Staff schedules: When and Next run read on one line each, the cron
   string never breaks, and the advanced cron field is quiet and spaced. */
table.sched-table td.sched-when, table.sched-table td.sched-next { white-space: nowrap; }
table.sched-table td.sched-when .mono { white-space: nowrap; }
table.sched-table td.sched-kind { min-width: 9rem; }
table.sched-table td.row-actions { white-space: normal; min-width: 10.5rem; }
table.sched-table td.row-actions > form, table.sched-table td.row-actions > a { margin: 2px 0; }
details.cron-advanced { margin: 8px 0 24px; }
details.cron-advanced > summary {
  cursor: pointer; font-size: 14px; font-weight: 500; color: var(--ink-soft);
}
details.cron-advanced[open] > summary { margin-bottom: 12px; }

/* Settings, Appearance: each choice's name on one line with its
   description under it, so the descriptions line up. */
.settings-page form.form-grid fieldset.scan-type label.radio {
  display: grid; grid-template-columns: auto 1fr; column-gap: 8px; align-items: baseline;
  white-space: nowrap; margin: 6px 0 12px;
}
.settings-page form.form-grid fieldset.scan-type label.radio > small {
  grid-column: 2; display: block; white-space: normal; margin-top: 0; line-height: 1.4;
}

/* New scan: "Verified" and its expiry stay on one line. */
td.scope-status { white-space: nowrap; }

/* Scan page: Re-scan sits level with the target name, not halfway down
   the header (the back link above the name pushes the title down). */
@media (min-width: 641px) {
  .page-head.scan-head { align-items: flex-start; }
  .page-head.scan-head > .page-actions { margin-top: 39px; }
}

/* Filter bars (findings, audit and the rest): Apply and Reset are the
   height of the selects beside them. */
.filter-bar select { height: 38px; }
.filter-bar button[type="submit"], .filter-bar .link-btn, .filter-bar .btn-secondary.btn-sm {
  display: inline-flex; align-items: center; height: 38px; padding: 0 14px; font-size: 13px;
}

/* Alerts: the notes are as wide as the choices under them. */
.partial-note.alerts-note { max-width: 640px; box-sizing: border-box; }
@media (pointer: coarse), (max-width: 560px) {
  .filter-bar button[type="submit"], .filter-bar .link-btn, .filter-bar .btn-secondary.btn-sm { min-height: 44px; }
}

/* ---- Domains: verification by email ---- */
.domain-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
               padding: 18px 20px; margin-bottom: 16px; box-shadow: var(--shadow-sm); }
.domain-card:last-child { margin-bottom: 0; }
.domain-card > h3 { margin: 0 0 8px; overflow-wrap: anywhere; }
.domain-state { margin: 0 0 14px; line-height: 1.6; }
.domain-state .pill { margin-right: 6px; }
.verify-block { margin: 6px 0 14px; padding: 14px 16px; border: 1px solid var(--line);
                border-radius: 8px; background: var(--surface-2); }
.verify-block h4 { margin: 0 0 4px; font-size: 14.5px; }
.verify-block .set-lead { margin-bottom: 10px; }
.verify-form { align-items: flex-end; }
.verify-form label { flex: 1 1 260px; min-width: 0; }
.verify-form input[type="email"] { width: 100%; }
.verify-pending { margin: 0 0 10px; max-width: 62ch; }
.verify-other { margin-top: 10px; font-size: 13.5px; }
.verify-other > summary, .dns-details > summary { cursor: pointer; color: var(--accent); padding: 4px 0; }
.verify-other > summary:focus-visible, .dns-details > summary:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
.verify-other[open] > summary { margin-bottom: 8px; }
.dns-details { margin: 4px 0 14px; }
.dns-details > summary { font-weight: 600; }
.dns-details[open] > summary { margin-bottom: 8px; }
.it-form { margin-top: 14px; }
.domain-card .field-error { margin: 6px 0 0; }
.domain-card .act-line { margin: 6px 0 0; }
.domain-card .act-line + .it-form { margin-top: 16px; }

/* The public confirmation page. */
.confirm-facts { margin: 0 0 18px; padding: 14px 16px; border: 1px solid var(--line);
                 border-radius: 8px; background: var(--surface-2); font-size: 14px; }
.confirm-facts dl { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 4px 14px; margin: 0; }
.confirm-facts dt { color: var(--ink-faint); }
.confirm-facts dd { margin: 0; overflow-wrap: anywhere; font-weight: 600; }
.confirm-statement { display: flex; gap: 10px; align-items: flex-start; margin: 0 0 18px;
                     padding: 14px 16px; border: 1px solid var(--line); border-radius: 8px; }
.confirm-statement input { margin-top: 4px; flex: none; }
.confirm-statement span { overflow-wrap: anywhere; }
.confirm-done { text-align: left; }
.confirm-note { font-size: 13px; color: var(--ink-faint); margin: 14px 0 0; }

@media (max-width: 640px) {
  .domain-card { padding: 16px 14px; }
  .verify-block { padding: 12px 12px; }
  .verify-form label { flex-basis: 100%; }
  .verify-form .btn-primary, .verify-form .btn-secondary { width: 100%; justify-content: center; }
  .confirm-facts dl { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .confirm-facts dd { margin-bottom: 8px; }
}

.confirm-terms { margin: 0 0 18px; font-size: 14px; }
.confirm-terms h2 { margin: 0 0 6px; font-size: 14px; }
.confirm-terms ul { margin: 0; padding-left: 18px; color: var(--ink-soft); }
.confirm-terms li { margin: 0 0 6px; overflow-wrap: anywhere; }
.verify-waiting { margin: 0 0 12px; padding: 12px 14px; border-radius: 8px;
                  background: var(--accent-soft); color: var(--ink); max-width: 62ch; }
.mailbox-notice { margin-bottom: 18px; }
.review-note { font-size: 12.5px; color: var(--ink-faint); }
.add-statement { display: flex; gap: 8px; align-items: flex-start; margin: 10px 0 4px;
                 font-weight: 400; color: var(--ink); }
.add-statement input { margin-top: 3px; flex: none; }
.review-notes { margin: 0; padding-left: 16px; font-size: 13px; color: var(--ink-soft); }
.review-notes li { margin: 0 0 3px; }
.review-notes .review-strong { font-weight: 600; color: var(--ink); }

/* ---- known vulnerabilities: the CVE table inside a finding card ----
   (reporting/templates/_finding_card.html.j2, scanner/vuln_findings.py) */
.finding dd.vuln-detail { min-width: 0; }
.vuln-label {
  display: inline-block; margin-left: 6px; padding: 1px 8px; border-radius: 999px; vertical-align: 1px;
  font-size: 11px; font-weight: 600; letter-spacing: .03em; white-space: nowrap;
  color: var(--sev-critical); border: 1px solid color-mix(in srgb, var(--sev-critical) 55%, transparent);
  background: color-mix(in srgb, var(--sev-critical) 10%, var(--surface));
}
.vuln-meta { margin: 0 0 6px; }
.vuln-note { margin: 4px 0; font-size: 12.5px; }
.conf-pill {
  display: inline-block; padding: 1px 8px; border-radius: 999px; margin-right: 4px;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; white-space: nowrap;
  background: var(--surface-2); color: var(--ink-soft);
}
.conf-pill.conf-confirmed { background: color-mix(in srgb, var(--sev-low, #3f7488) 20%, var(--surface)); color: var(--ink); }
.conf-pill.conf-banner { border: 1px dashed var(--line-strong); }
.kev-badge {
  display: inline-block; padding: 0 6px; border-radius: 4px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .06em; white-space: nowrap; color: var(--bad);
  background: color-mix(in srgb, var(--bad) 14%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--bad) 45%, transparent);
}
.cve-scroll { margin: 8px 0 4px; border: 1px solid var(--line); border-radius: 6px; }
.cve-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.cve-table th {
  text-align: left; padding: 6px 8px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); background: var(--surface-2); border-bottom: 1px solid var(--line); white-space: nowrap;
}
.cve-table td { padding: 6px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.cve-table tbody tr:last-child td { border-bottom: 0; }
.cve-table td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.cve-table td.cve-id { font-family: var(--font-mono); font-size: 12px; white-space: nowrap; }
.cve-table td.cve-sum { min-width: 220px; }
/* On a phone each CVE is a small card: id, scores and badge on one line,
   the summary under them, so nothing hides behind a sideways scroll. */
@media (max-width: 640px) {
  .cve-table thead { display: none; }
  .cve-table tr { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px;
                  padding: 8px 10px; border-bottom: 1px solid var(--line); }
  .cve-table tbody tr:last-child { border-bottom: 0; }
  .cve-table td { padding: 0; border: 0; }
  .cve-table td[data-label]::before { content: attr(data-label) " "; color: var(--ink-faint);
                                       font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; }
  .cve-table td.cve-sum { flex-basis: 100%; min-width: 0; }
  .vuln-label { margin-left: 0; margin-top: 4px; }
}

/* ---- Onboarding checklist (app/onboarding.py, _onboarding.html, getting_started.html) ---- */
.ob-progress { display: flex; align-items: center; gap: 14px; min-width: 0; }
.ob-progress-text { margin: 0; font-size: 14px; color: var(--ink-soft); white-space: nowrap; }
.ob-progress-text strong { color: var(--ink); font-weight: 650; font-variant-numeric: tabular-nums; }
.ob-bar {
  flex: 1 1 140px; min-width: 96px; height: 8px; border-radius: 999px; overflow: hidden;
  background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line);
}
.ob-bar-fill { display: block; height: 100%; border-radius: 999px; background: var(--accent); }

.ob-mark {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; margin-top: 1px;
  font-size: 12.5px; font-weight: 650; line-height: 1; font-variant-numeric: tabular-nums;
  color: var(--ink-faint); box-shadow: inset 0 0 0 1.5px var(--line-strong);
}
.ob-mark.is-done { color: var(--ink); box-shadow: none;
  background: color-mix(in srgb, var(--sev-low, #3f7488) var(--pill-tint, 14%), var(--surface)); }
.ob-mark.is-next { color: var(--on-accent); background: var(--accent); box-shadow: none; }

.ob-step-title { margin: 0; font-size: 15px; font-weight: 620; line-height: 1.5; color: var(--ink); }
.ob-step-title .pill { margin-left: 8px; }
.ob-step-text { margin: 3px 0 0; font-size: 14px; line-height: 1.55; color: var(--ink-soft); max-width: 62ch; }
.ob-step-note, .ob-aside { margin: 6px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); max-width: 62ch; }
.ob-aside { color: var(--ink-faint); }
.ob-step-body { min-width: 0; }
.ob-step-act { align-self: center; display: flex; flex-wrap: wrap; gap: 8px; }
.ob-step-act:empty { display: none; }

.ob-summary { margin-bottom: var(--sp-6, 32px); }
.ob-lead { margin: 12px 0 0; font-size: 14.5px; color: var(--ink-soft); }
.ob-lead strong { color: var(--ink); }
.ob-sect-lead { margin: -4px 0 14px; font-size: 14px; }

.ob-steps {
  list-style: none; margin: 0; padding: 0; overflow: hidden;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
}
.ob-step {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; column-gap: 14px; align-items: start;
  padding: 16px 18px;
}
.ob-step + .ob-step { border-top: 1px solid var(--line); }
.ob-step.is-next { background: var(--accent-soft); }
.ob-step.is-done .ob-step-title { color: var(--ink-soft); font-weight: 560; }
.ob-step.is-blocked .ob-step-title { color: var(--ink-soft); }

.ob-card { margin-bottom: var(--sp-6, 32px); }
.ob-card-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 24px; }
.ob-card-head h2 { margin: 0; font-size: 17px; font-weight: 650; border: 0; padding: 0; }
.ob-card-head .ob-progress { flex: 1 1 260px; max-width: 420px; }
.ob-next {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; column-gap: 14px; align-items: start;
  margin-top: 16px; padding: 14px 16px; border-radius: var(--r-sm); background: var(--accent-soft);
}
.ob-mini {
  list-style: none; margin: 14px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 8px 28px;
}
.ob-mini li { display: flex; align-items: center; gap: 10px; min-width: 0; font-size: 13.5px; color: var(--ink-soft); }
.ob-mini .ob-mark { width: 20px; height: 20px; margin-top: 0; font-size: 11px; }
.ob-mini li.is-done .ob-mini-title { color: var(--ink-faint); }
.ob-mini-title { min-width: 0; overflow-wrap: anywhere; }
.ob-mini-state { margin-left: auto; padding-left: 8px; font-size: 12.5px; color: var(--ink-faint); white-space: nowrap; }
.ob-more { margin: 12px 0 0; font-size: 13.5px; }
.ob-foot { margin: 28px 0 0; font-size: 13.5px; }

.sidenav a .nav-count {
  display: inline-block; margin-left: 6px; padding: 0 7px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; line-height: 1.6; font-variant-numeric: tabular-nums;
  color: var(--ink-soft); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--line);
}
.sidenav a.active .nav-count { color: var(--accent-ink); background: var(--surface); }

@media (max-width: 640px) {
  .ob-step, .ob-next { grid-template-columns: 26px minmax(0, 1fr); padding: 14px; }
  .ob-step-act { grid-column: 2; margin-top: 12px; align-self: start; }
  .ob-step-act .btn-primary, .ob-step-act .btn-secondary { min-height: 44px; display: inline-flex; align-items: center; }
  .ob-progress { gap: 10px; }
  .ob-mini { grid-template-columns: 1fr; }
}
/* ---- end onboarding checklist ---- */

/* ---- About page and portal footer logo (/about, _site_footer.html) ---- */
.site-foot-id { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; }
.site-foot-id .brand { margin: 0; }
.site-foot-id .brand-label { font-size: 15px; }
@media (max-width: 640px) {
  .site-foot-id { flex-direction: column; align-items: flex-start; gap: 6px; }
  .site-foot-compact .site-foot-base { flex-direction: column; align-items: flex-start; }
}
.about-page { max-width: 760px; }
.about-page p, .about-page li, .about-page dd { max-width: 70ch; }
.about-page h3 { font-size: .95rem; margin: 22px 0 8px; }
.about-page .set-section > h2 { scroll-margin-top: 72px; }
.about-toc { padding: 16px 20px; margin-bottom: 32px; }
.about-toc h2 { margin: 0 0 10px; font-size: 14px; }
.about-toc ol { margin: 0; padding-left: 20px; columns: 2; column-gap: 32px; }
.about-toc li { padding: 2px 0; break-inside: avoid; }
.about-defs { margin: 0; }
.about-defs dt { margin-top: 14px; font-weight: 600; }
.about-defs dd { margin: 2px 0 0; color: var(--ink-soft); }
.about-defs .pill { margin-left: 6px; font-size: 11.5px; vertical-align: 1px; }
.about-page .table-scroll > table.grid { min-width: 0; }
.about-table th[scope="row"] { text-align: left; font-weight: 600; white-space: nowrap; vertical-align: top; }
.about-table td { vertical-align: top; }
.about-more { margin-top: 14px; }
.about-more summary { cursor: pointer; font-weight: 600; }
.about-more summary:focus-visible, .about-page a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 640px) {
  .about-toc ol { columns: 1; }
  .about-table th[scope="row"] { white-space: normal; }
}
/* ---- end About page ---- */

/* Side-nav section headings. Small capitals in the full text color, with a
   faint rule above each group that stops short of both edges, so a heading
   reads as the label for the links under it and not as one more page. This
   is last in the file so it wins over the earlier .sidenav-group rules. */
.sidenav-group {
  margin: 20px 12px 6px; padding: 16px 0 0;
  border-top: 1px solid var(--line);
  font-size: 11.5px; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink);
}
.sidenav-group:first-of-type { margin-top: 14px; padding-top: 0; border-top: 0; }

/* Alert channels (Slack, Teams, webhook) on /alerts. */
.chan { max-width: 640px; margin: 18px 0 0; padding: 16px 18px 18px; border: 1px solid var(--line);
  border-radius: var(--r); background: var(--surface); }
.chan h3 { margin: 0 0 8px; font-size: 16px; display: flex; gap: 10px; align-items: center; }
.chan .set-lead { margin: 6px 0 10px; }
.chan-url { width: 100%; max-width: 560px; }
.chan-actions { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.chan-secret { display: block; margin: 6px 0; word-break: break-all; }
.chan-form p { margin: 0 0 12px; }
.chan-form label.dim { display: block; margin-bottom: 4px; }

/* monitor declutter: list directly under a panel heading */
.an-panel > .an-h + .an-cats { margin-top: 14px; }

/* Public guides (/guides): the legal-page article styling plus a few extras. */
.guide pre { margin: 12px 0 16px; padding: 12px 14px; overflow-x: auto; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--surface); font-size: 13.5px; line-height: 1.5; }
.guide code { font-size: .92em; }
.guide-cta { margin: 36px 0 8px; padding: 18px 20px; border: 1px solid var(--line);
  border-radius: var(--r); background: var(--surface); }
.guide-cta h2 { margin: 0 0 6px; font-size: 18px; }
.guide-more ul, .guide-list { list-style: none; padding: 0; margin: 8px 0 0; }
.guide-list li { padding: 14px 0; border-top: 1px solid var(--line); }
.guide-list h2 { margin: 0 0 4px; font-size: 19px; }
.guide-list p { margin: 0; }

/* The organization-wide pause switch on /domains. */
.scan-switch { margin-bottom: 16px; }
.scan-switch h2 { margin: 0 0 6px; font-size: 18px; }
.scan-switch p { margin: 0 0 12px; max-width: 64ch; }

/* ---- business dashboard (/admin/business) ------------------------------ */
.bz-svg { width: 100%; height: auto; display: block; }
.bz-grid { stroke: var(--line); stroke-width: 1; }
.bz-tick { fill: var(--ink-faint); font-size: 9px; }
.bz-bar { fill: var(--accent); }
.bz-bar:hover { opacity: .75; }
.bz-hbar { width: 100%; height: 8px; display: block; }
.bz-hbar-bg { fill: var(--line); }
.bz-hbar-fg { fill: var(--accent); }
.bz-bar-cell { width: 45%; }
.bz-two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 14px; }
.bz-three { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.bz-attn { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.bz-attn li { padding: 10px 14px; border: 1px solid var(--line); border-left-width: 4px; border-radius: 8px; }
.bz-attn li.is-warn { border-left-color: var(--bad); }
.bz-attn li.is-info { border-left-color: var(--accent); }
.set-section .card h3 { margin: 0 0 8px; font-size: 14px; }
@media (max-width: 880px) { .bz-two, .bz-three { grid-template-columns: 1fr; } }
.bz-bar.is-neg { fill: var(--bad); }
