/* Component library: icon, button, field, card, badge, callout, table, chip, swatch. */
.icon {
  width: 1.25em;
  height: 1.25em;
  flex: none;
  fill: none;
  stroke: currentcolor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -0.25em;
}

/* Buttons: every control is at least 2.25rem (36 px), 24 px is the WCAG 2.2 minimum */
button,
.btn,
input[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--control-height);
  max-width: 100%;
  white-space: normal;
  text-align: center;
  padding: 0 var(--space-4);
  font: inherit;
  font-weight: 600;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
  /* No `white-space: nowrap` here: it used to sit below and silently undo the `normal` above,
     so a long label overflowed its button at narrow widths (found again on 2026-10-18). */
}

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

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

.btn-primary:hover {
  filter: brightness(1.08);
}

.btn-danger {
  background: transparent;
  color: var(--danger);
  border-color: var(--danger);
}

.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--text-muted);
}

/* Form fields */
label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-1);
}

input:not([type="radio"], [type="checkbox"], [type="hidden"], [type="submit"]),
select,
textarea {
  width: 100%;
  max-width: 26rem;
  min-height: var(--control-height);
  padding: var(--space-1) var(--space-3);
  font: inherit;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
}

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

.field-inline {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-3);
}

.field-inline .field {
  margin: 0;
}

.errorlist {
  list-style: none;
  margin: 0 0 var(--space-2);
  padding: 0;
  color: var(--danger);
  font-weight: 600;
}

fieldset {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-4);
  margin: 0 0 var(--space-6);
}

legend {
  padding: 0 var(--space-2);
  font-weight: 600;
}

/* Card, section */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: var(--space-6);
  margin-bottom: var(--space-6);
  box-shadow: inset 0 1px 0 0 var(--glow);
}

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

.card-narrow {
  max-width: 26rem;
  margin-inline: auto;
}

/* Modal: HTMX loads a dialog into #modal; empty means hidden (Web UI redesign, D-49). */
.modalroot {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: var(--space-4);
}

.modalroot:empty {
  display: none;
}

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgb(0 0 0 / 55%);
}

.modal {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 42rem;
  max-height: 90vh;
  overflow: auto;
  padding: var(--space-6);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-card);
  box-shadow: 0 1.25rem 3rem rgb(0 0 0 / 45%);
}

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

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

.modal .modal-x {
  min-height: auto;
  padding: var(--space-1);
}

/* Coachmark tour stop (D-49 slice 4): a non-modal panel pinned to the corner, plus a spotlight
   ring around the explained element. The ring ignores the pointer so the page stays usable. */
.coachmark {
  position: fixed;
  z-index: 45;
  right: var(--space-4);
  bottom: var(--space-4);
  left: var(--space-4);
  max-width: 26rem;
  max-height: 70vh;
  margin-left: auto;
  overflow: auto;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--accent);
  border-radius: var(--radius-card);
  box-shadow: 0 1rem 2.5rem rgb(0 0 0 / 45%), 0 0 0 1px var(--glow);
}

.coachmark h2 {
  margin-bottom: var(--space-2);
}

.coachmark-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  color: var(--text-muted);
  font-size: 0.875rem;
}

.coachmark-meta p {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
}

.coachmark .coachmark-toggle {
  min-height: auto;
  padding: var(--space-1) var(--space-2);
}

.coachmark.is-collapsed .coachmark-meta {
  margin: 0;
}

.coachmark-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.spotlight {
  position: absolute;
  z-index: 40;
  pointer-events: none;
  border-radius: var(--radius);
  box-shadow:
    0 0 0 3px var(--accent),
    0 0 0 100vmax rgb(0 0 0 / 55%);
}

/* A tour scrolls its anchor near the top, clear of the sticky bar and of the panel below. */
[data-tour] {
  scroll-margin-top: 6rem;
}

.spotlight[hidden],
.coachmark [hidden] {
  display: none;
}

/* An inline "create on the spot" affordance next to a field. */
.field-with-action {
  display: flex;
  align-items: end;
  gap: var(--space-2);
  flex-wrap: wrap;
}

.field-with-action > .field {
  flex: 1 1 14rem;
  margin: 0;
}

.modal .table-wrap {
  margin-bottom: var(--space-4);
}

/* Summary cards (Integrations, D-49): a responsive grid that never forces a sideways scroll.
   The state stripe repeats the state badge; the badge text carries the meaning, not the color. */
.statline,
.icards,
.pchips,
.cell-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Several values inside one table cell (the DNS answers table): one per line, no bullets. */
.cell-list > li + li {
  margin-top: var(--space-1);
}

.statline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin-bottom: var(--space-3);
}

.icards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.icard {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  height: 100%;
  min-width: 0;
  padding: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-inline-start: 4px solid var(--border-strong);
  border-radius: var(--radius-card);
  box-shadow: inset 0 1px 0 0 var(--glow);
}

/* data-state is an integration's state; data-tone is the generic form other card pages use.
   Either way the stripe only repeats a badge whose text carries the meaning. */
.icard[data-state="available"],
.icard[data-tone="success"] {
  border-inline-start-color: var(--success);
}

.icard[data-state="limited"],
.icard[data-tone="warning"] {
  border-inline-start-color: var(--warning);
}

.icard[data-state="unknown"],
.icard[data-tone="info"] {
  border-inline-start-color: var(--info);
}

.icard[data-state="unavailable"],
.icard[data-tone="danger"] {
  border-inline-start-color: var(--danger);
}

/* A section heading with its main action beside it (wraps under it on narrow screens). */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  margin-bottom: var(--space-3);
}

.section-head > h2 {
  margin: 0;
}

.icard > * {
  margin: 0;
}

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

.icard-title {
  min-width: 0;
}

.icard-title h3 {
  margin: 0;
  overflow-wrap: anywhere;
}

.icard-id,
.icard-facts {
  color: var(--text-muted);
  font-size: 0.875rem;
}

.pchips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.pchip {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  min-height: 1.75rem;
  max-width: 100%;
  padding: 0 var(--space-2);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--bg);
  font-size: 0.8rem;
}

.pchip-here {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

/* The platform preview (D-52 slice 6): a dashed ring says "this is the one being previewed",
   never on its own - every chip also carries the words in .pchip-tag. */
.pchip-preview {
  border-style: dashed;
  border-color: var(--info);
  box-shadow: 0 0 0 1px var(--info);
}

.preview-limits summary {
  cursor: pointer;
  font-weight: 600;
}

.pchip-declared {
  font-weight: 700;
}

.pchip-tag {
  font-weight: 600;
}

.pchip-ok,
.pchip-bad {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}

.pchip-ok {
  color: var(--success);
}

.pchip-bad {
  color: var(--danger);
}

.icard-more summary {
  cursor: pointer;
  font-weight: 600;
}

.icard-more .facts {
  margin: var(--space-2) 0 0;
}

.icard-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
}

/* Callouts and badges: always icon + text, never color alone */
.callout {
  display: flex;
  gap: var(--space-3);
  align-items: flex-start;
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
  border: 1px solid var(--border-strong);
  border-inline-start-width: 4px;
  border-radius: var(--radius);
  background: var(--surface);
}

.callout-error {
  border-color: var(--danger);
}

.callout-success {
  border-color: var(--success);
}

.callout-info {
  border-color: var(--info);
}

.callout-warning {
  border-color: var(--warning);
}

.messages {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
}

.badge,
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 1.75rem;
  padding: 0 var(--space-3);
  border: 1px solid currentcolor;
  border-radius: 999px;
  font-size: 0.875rem;
  font-weight: 600;
  text-decoration: none;
  background: var(--bg);
}

.badge-success,
.chip[data-state="protected"] {
  color: var(--success);
}

.badge-warning,
.chip[data-state="pending"],
.chip[data-state="alert"] {
  color: var(--warning);
}

.badge-danger,
.chip[data-state="lockdown"],
.chip[data-state="failed"] {
  color: var(--danger);
}

.badge-info {
  color: var(--info);
}

/* Data tables scroll sideways inside their wrapper so the page itself reflows at 320 px */
.table-wrap {
  position: relative; /* contains visually-hidden text so it cannot widen the page */
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.95rem;
}

.data th,
.data td {
  padding: var(--space-2) var(--space-3);
  text-align: start;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.data thead th {
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  position: sticky;
  top: 0;
}

.data tbody tr:last-child td {
  border-bottom: 0;
}

.data .num,
.data .mono {
  white-space: nowrap;
}

/* Appearance page: a preview swatch carries data-theme, so it uses that theme's own tokens */
.choices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--space-3);
}

.choice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg);
  font-weight: 400;
  cursor: pointer;
}

.choice:has(input:checked) {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

.choice:has(input:focus-visible) {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.choice input {
  margin-top: 0.35rem;
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--accent);
}

.choice strong {
  display: block;
}

.swatch {
  display: block;
  width: 100%;
  min-width: 7rem;
  margin-top: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text);
  font-size: 0.8rem;
}

.swatch i {
  display: inline-block;
  width: 0.9rem;
  height: 0.9rem;
  margin-inline-end: 0.2rem;
  border-radius: 50%;
  vertical-align: middle;
}

.swatch .s-accent {
  background: var(--accent);
}

.swatch .s-surface {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
}

.swatch .s-danger {
  background: var(--danger);
}

.sample-text {
  margin-top: var(--space-2);
  font-size: 1.1rem;
}

.font-sample[data-font="inter"] {
  font-family: "Inter Variable", sans-serif;
}

.font-sample[data-font="plex"] {
  font-family: "IBM Plex Sans Variable", sans-serif;
}

.font-sample[data-font="atkinson"] {
  font-family: "Atkinson Hyperlegible Next Variable", sans-serif;
}

.font-sample[data-font="system"] {
  font-family: system-ui, "Segoe UI", Roboto, Arial, sans-serif;
}

.stack > * + * {
  margin-top: var(--space-4);
}

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

/* Forced colors (Windows high contrast): let the system palette win, keep shapes visible */
@media (forced-colors: active) {
  button,
  .btn,
  .badge,
  .chip,
  .pchip,
  .card,
  .icard,
  .callout,
  .choice,
  .lockdown-link,
  .navbadge,
  .journey,
  .launcher a,
  .axis,
  .table-wrap {
    border: 1px solid CanvasText;
  }

  .sidenav a[aria-current="page"] {
    border-color: Highlight;
    color: Highlight;
  }

  :focus-visible {
    outline-color: Highlight;
  }

  .icon {
    stroke: currentcolor;
  }
}

/* Reduced motion: no transitions or smooth scrolling anywhere */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* Job detail: facts list and captured output (untrusted text, wrapped, scrollable by keyboard) */
.facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--space-2) var(--space-4);
  margin: 0 0 var(--space-4);
}

.facts dt {
  color: var(--text-muted);
}

.facts dd {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.output {
  max-height: 24rem;
  overflow: auto;
  margin: 0 0 var(--space-4);
  padding: var(--space-3);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

/* Contextual help: a collapsed "What is this?" block on a page. */
.help {
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: var(--space-2) var(--space-3);
  margin-block: var(--space-3);
}

.help summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 600;
}

.help-body > :first-child {
  margin-top: var(--space-2);
}

.inline-form {
  display: inline;
}

/* --- Dashboard furniture (D-52 slice 1): page head, tabs, attention strip, charts -------------
   All of it is layout only: every state still reads as text in a badge, and the greyed rows keep
   a contrast ratio above 4.5:1 because --text-muted is a verified token, not an opacity trick. */
.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.page-head > h1 {
  margin: 0;
}

.page-head-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-2);
}

/* What needs a decision, pinned above the tabs so it is never scrolled to. */
.attention {
  padding: var(--space-4);
  margin-block: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--warning);
  border-radius: var(--radius-card);
  box-shadow: inset 0 1px 0 0 var(--glow);
}

.attention-quiet {
  border-color: var(--border);
}

.attention > .section-head > h2 {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 1.1rem;
}

.attention-sub {
  margin: var(--space-3) 0 var(--space-2);
  font-size: 0.95rem;
  color: var(--text-muted);
}

.attention .icards {
  margin-bottom: 0;
}

/* Tabs are ordinary links: the server renders the panel, so they work without JavaScript. */
.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border);
  padding-bottom: var(--space-2);
}

.tab {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius) var(--radius) 0 0;
  color: var(--text-muted);
  text-decoration: none;
  font-weight: 600;
}

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

.tab-current {
  background: var(--surface-2);
  color: var(--accent);
  border-color: var(--border-strong);
  box-shadow: inset 0 -2px 0 0 var(--accent);
}

/* Denser card grid: four to five across on a wide screen, one on a phone. */
.icards.compact {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-3);
}

.icards.compact .icard {
  padding: var(--space-3);
  gap: var(--space-2);
}

.icards.compact .icard-title h3,
.icards.compact .icard-title h4 {
  margin: 0;
  font-size: 1rem;
  overflow-wrap: anywhere;
}

.who {
  margin: 0;
  overflow-wrap: anywhere;
}

/* Charts: a canvas the script draws on, with the same numbers in a table under it. */
.chartgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.chart {
  margin: 0;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
}

.chart figcaption {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
  margin-bottom: var(--space-3);
}

.chart-title {
  font-weight: 600;
}

.chart-canvas {
  position: relative;
  height: 14rem;
}

.chart-data summary,
.tablefold > summary {
  cursor: pointer;
  color: var(--text-muted);
  font-size: 0.9rem;
  padding-block: var(--space-2);
}

.chart-data[open] summary,
.tablefold[open] > summary {
  color: var(--text);
}

.chart-empty {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
}

/* Local traffic: Codia talking to itself, or your own browser. Still readable, clearly lesser. */
.row-local > td,
.row-local > th {
  color: var(--text-muted);
  background: color-mix(in srgb, var(--surface-2) 45%, transparent);
}

.data.dense th,
.data.dense td {
  padding: var(--space-1) var(--space-3);
  font-size: 0.9rem;
}

/* The shared table component (D-52 slice 2): one theme, one toolbar, one set of behaviours for
   every table. Sorting and paging are links and the search and column chooser are GET forms, so
   this styling only has to make them legible - none of it carries meaning on its own. */
.dtable {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.dtable-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.dtable-search {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-2);
}

.dtable-search .field {
  margin: 0;
}

.dtable-search input[type="search"] {
  max-width: 18rem;
}

.dtable-cols > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--control-height);
  padding: 0 var(--space-3);
  font-weight: 600;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  cursor: pointer;
}

.dtable-cols > form {
  padding: var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface-2);
  margin-top: var(--space-2);
}

.dtable-cols fieldset {
  margin: 0 0 var(--space-3);
}

.colchoice {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--space-1) var(--space-3);
}

.colchoice label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 400;
  margin: 0;
  min-height: 1.75rem;
}

.dtable-colactions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.dtable-status {
  margin: 0;
  color: var(--text-muted);
  font-size: 0.9rem;
}

/* A heading row can only stick to something: the component's scroll container gets a bounded
   height, so a long page of rows scrolls inside it while the headings stay in view. The scroll
   padding keeps a focused cell from ending up underneath them (WCAG 2.4.11). */
.dtable .table-wrap {
  max-height: min(34rem, 75vh);
  overflow: auto;
  scroll-padding-block-start: 2.75rem;
}

/* A sorted column's arrow points down for descending and is turned over for ascending. The
   direction is in aria-sort and in the link's own hidden text as well: never only in the arrow. */
.data thead th:has(.sortlink) {
  padding: 0;
}

.sortlink {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-decoration: none;
}

.sortlink:hover {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

.sortlink.sorted {
  color: var(--text);
}

.sortlink.sorted-asc .icon {
  transform: rotate(180deg);
}

.pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.pager-back .icon {
  transform: rotate(180deg);
}

/* The refusal card (D-52 slice 3): what was refused, what did not run, and the two buttons that
   answer it. It is a panel rather than a callout because it holds forms, but it keeps the danger
   edge so it reads as a refusal, and its meaning is in its words, never in the colour. */
.refusal {
  border: 1px solid var(--border-strong);
  border-inline-start: 3px solid var(--danger);
  border-radius: var(--radius-card);
  background: var(--surface);
  padding: var(--space-4);
  margin-block: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.refusal > * {
  margin: 0;
}

.refusal-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 1.05rem;
  color: var(--danger);
}

.refusal-actions {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.refusal-actions > li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.refusal-actions form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  width: 100%;
}

.refusal-what {
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.refusal-retry {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

/* Why a match exists and what nobody checked: short sentences, one per line, in a cell or a
   definition list. They carry the meaning of a match, so they are never truncated. */
.reasons {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.reasons > li {
  font-size: 0.9rem;
  text-wrap: pretty;
}

td > .reasons {
  min-width: 12rem;
}

/* ------------------------------------------------------------------------------------------------
   The shared form component (D-52 slice 4, core/forms.py + core/_form.html).

   Compact by construction: a two-column grid that becomes one column long before 400 px, labels
   and controls close together, and the suggestions and the help folded away until asked for. The
   control itself keeps the sizes the rest of the library uses, so a field is still a 40 px target
   (WCAG 2.2 2.5.8) and still takes the focus ring every other control takes.
   ------------------------------------------------------------------------------------------------ */
.form-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
}

@media (width >= 44rem) {
  .form-grid-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .form-grid-2 > .f-span-2 {
    grid-column: 1 / -1;
  }
}

.form-grid > .field {
  margin: 0;
  min-width: 0;
}

/* A field inside the grid owns its column, so the 26rem cap of a lone input would leave a gap. */
.form-grid input:not([type="radio"], [type="checkbox"], [type="hidden"], [type="submit"]),
.form-grid select,
.form-grid textarea {
  max-width: 100%;
}

.form-grid label {
  margin-bottom: var(--space-1);
  font-size: 0.95rem;
}

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

/* The shape of a value, the help and an error: small, quiet, and tied to the control by
   aria-describedby (set in core/forms.py, never guessed in the template). */
.field-shape,
.field-help,
.hint {
  margin: var(--space-1) 0 0;
  font-size: 0.85rem;
  color: var(--text-muted);
  text-wrap: pretty;
}

.field-error {
  margin: var(--space-1) 0 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--danger);
}

/* An error is never carried by color alone: the field also gets a thicker edge and the message
   above says what is wrong in words. */
.field-bad input:not([type="checkbox"]),
.field-bad select,
.field-bad textarea {
  border-color: var(--danger);
  border-width: 2px;
}

/* Stored values offered for one field. Collapsed, so a form with eight fields is still compact. */
.hints {
  margin-top: var(--space-1);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

.hints > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--control-height);
  padding: 0 var(--space-3);
  font-size: 0.85rem;
  color: var(--text-muted);
  cursor: pointer;
}

.hints > summary:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.hints-body {
  padding: 0 var(--space-3) var(--space-3);
}

.hints-body > p {
  margin: 0 0 var(--space-2);
  font-size: 0.85rem;
}

.hintlist {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  max-height: 14rem;
  overflow: auto;
  font-size: 0.85rem;
}

.hintlist > li {
  overflow-wrap: anywhere;
  text-wrap: pretty;
}

/* The row of buttons under a form: the primary action first, never squeezed into the grid. */
.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

/* The "create the other thing on the spot" button of a field (a closed list in core/forms.py). */
.field-action {
  margin-top: var(--space-2);
}

.field-action > button {
  min-height: var(--control-height);
  font-size: 0.85rem;
}

/* Reports (D-75): one finding per block, the three count tables side by side when they fit. */
.report-counts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.report-counts .data {
  width: auto;
  min-width: 14rem;
  flex: 1 1 14rem;
}

.data caption {
  text-align: start;
  font-weight: 600;
  padding-bottom: var(--space-2);
}

.report-finding {
  border-top: 1px solid var(--border);
  padding-top: var(--space-4);
  margin-top: var(--space-4);
}

.report-label {
  margin: var(--space-3) 0 var(--space-2);
  color: var(--text-muted);
  font-size: 0.9rem;
}

.break {
  overflow-wrap: anywhere;
}

.report-delete {
  margin-top: var(--space-4);
}

/* Printing any page, a report above all: no navigation, no controls, no clipped boxes. The
   browser's own Save as PDF is the PDF route (D-75c). */
@media print {
  .topbar,
  .sidenav,
  .skip,
  .help,
  .messages,
  .no-print,
  form {
    display: none !important;
  }

  .shell,
  main {
    display: block;
    margin: 0;
    padding: 0;
  }

  .card {
    box-shadow: none;
    break-inside: auto;
  }

  .report-finding {
    break-inside: avoid;
  }

  .table-wrap,
  .output {
    overflow: visible;
    max-height: none;
  }

  .data thead th {
    position: static;
  }
}

/* ------------------------------------------------------------------------------------------------
   Workbench additions (redesign D-81): the context column, the journey strip, the launcher
   tiles and the four-axis cards. All layout: every state keeps its text and icon.
   ------------------------------------------------------------------------------------------------ */

/* A workspace with a context column: main content left, related context and evidence right.
   Below the breakpoint the context stacks after the content; nothing is hidden. */
.layout-inspector {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4) var(--space-6);
  align-items: start;
}

@media (min-width: 75rem) {
  .layout-inspector {
    grid-template-columns: minmax(0, 1fr) var(--inspector-width);
  }
}

.inspector {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-width: 0;
}

.inspector > .card {
  margin-bottom: 0;
  padding: var(--space-4);
}

.inspector h2 {
  font-size: 1rem;
}

/* The journey strip: where this work stands in configure -> review -> authorize -> run ->
   results. Passive and honest: the state words come from the page's own data. */
.journey {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
}

.journey li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
}

.jdot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  flex: none;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  font-size: 0.85rem;
  font-weight: 700;
}

.journey li[data-state="done"] .jdot {
  border-color: var(--success);
  color: var(--success);
}

.journey li[data-state="current"] {
  color: var(--text);
}

.journey li[data-state="current"] .jdot {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

.journey li[data-state="failed"] .jdot {
  border-color: var(--danger);
  color: var(--danger);
}

.jlabel {
  display: flex;
  flex-direction: column;
}

.jlabel > strong {
  font-weight: 600;
}

.jlabel > small {
  font-size: 0.8rem;
  color: var(--text-muted);
}

/* Launcher tiles (Overview): the two or three places to start, as large link cards. */
.launcher {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: var(--space-4);
}

.launcher a {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  height: 100%;
  padding: var(--space-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  color: var(--text);
  text-decoration: none;
}

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

.launcher a:first-child .launch-title,
.launcher .launch-title {
  color: var(--accent);
  font-weight: 600;
}

.launcher .icon {
  width: 1.5rem;
  height: 1.5rem;
  color: var(--accent);
  margin-top: 0.1rem;
}

.launch-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.launch-text > small {
  color: var(--text-muted);
  font-size: 0.875rem;
}

/* The four axes of a finding, each its own labelled cell (text + icon, never color alone). */
.axisgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
}

.axis {
  margin: 0;
  padding: var(--space-3);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
}

.axis > dt {
  color: var(--text-muted);
  font-size: 0.85rem;
  margin-bottom: var(--space-1);
}

.axis > dd {
  margin: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* The guide runner's two panes (D-81 slice 7): the step rail beside the current step. The rail
   is the same list as before - every state is a worded badge - laid out as a column. */
.guide-run {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4) var(--space-6);
  align-items: start;
}

@media (min-width: 60rem) {
  .guide-run {
    grid-template-columns: 17rem minmax(0, 1fr);
  }

  .steprail {
    position: sticky;
    top: 4.5rem;
  }
}

.steprail ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.steprail li {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-3);
  border-inline-start: 3px solid var(--border);
}

.steprail li[aria-current="step"] {
  border-inline-start-color: var(--accent);
  background: var(--surface);
  border-radius: 0 var(--radius) var(--radius) 0;
}

.steprail a {
  color: var(--text);
  text-decoration: none;
  font-weight: 500;
}

.steprail a:hover {
  text-decoration: underline;
}

.steprail .badge {
  align-self: flex-start;
}

/* The sign-in page's small identity line (D-81 slice 7). */
.kicker {
  margin: 0 0 var(--space-1);
  color: var(--text-muted);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* ------------------------------------------------------------------------------------------------
   Row cards: a list row as a compact card that opens in place (the error log, the stored
   vulnerability records). The summary is the whole compact view and the native <details> is the
   expander, so it opens with the keyboard and works without JavaScript. Long values wrap inside
   the card instead of squeezing a column.
   ------------------------------------------------------------------------------------------------ */
.rowcards {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

.rowcard {
  min-width: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-inline-start: 4px solid var(--border-strong);
  border-radius: var(--radius-card);
}

.rowcard[data-tone="success"] {
  border-inline-start-color: var(--success);
}

.rowcard[data-tone="warning"] {
  border-inline-start-color: var(--warning);
}

.rowcard[data-tone="info"] {
  border-inline-start-color: var(--info);
}

.rowcard[data-tone="danger"] {
  border-inline-start-color: var(--danger);
}

.rowcard > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-4);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  list-style-position: inside;
}

.rowcard > summary:hover {
  background: var(--surface-2);
}

.rowcard-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 16rem;
}

.rowcard-title {
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* The compact view shows two lines of the sentence; the open card shows all of it. */
.rowcard-sub {
  color: var(--text-muted);
  font-size: 0.9rem;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.rowcard[open] .rowcard-sub {
  display: block;
  overflow: visible;
}

.rowcard-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-size: 0.85rem;
}

.rowcard > :not(summary) {
  margin: 0;
  padding: var(--space-2) var(--space-3) var(--space-3);
  border-top: 1px solid var(--border);
}

.rowcard .facts {
  margin: 0;
}

.trace {
  max-height: 32rem;
  overflow: auto;
  white-space: pre;
  padding: var(--space-3);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 0.85rem;
}

/* ------------------------------------------------------------------------------------------------
   Notification area (header bell) and the install progress rows. The count is also in the bell's
   hidden text, the busy dot is decoration next to words, and nothing here is colour alone.
   ------------------------------------------------------------------------------------------------ */
.notify {
  position: relative;
}

.notify-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2.25rem;
  min-width: 2.25rem;
  justify-content: center;
  padding: 0 var(--space-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  list-style: none;
}

.notify-btn::-webkit-details-marker {
  display: none;
}

.notify[open] > .notify-btn {
  background: var(--surface-2);
}

.notify-count {
  min-width: 1.25rem;
  padding: 0 var(--space-1);
  border-radius: 999px;
  background: var(--warning);
  color: var(--bg);
  font-size: 0.75rem;
  font-weight: 700;
  text-align: center;
}

.notify-busy {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--info);
  animation: notify-pulse 1.4s ease-in-out infinite;
}

@keyframes notify-pulse {
  50% {
    opacity: 0.3;
  }
}

.npanel {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-card);
  padding: var(--space-3);
}

.notify-panel {
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + var(--space-1));
  z-index: 40;
  width: min(34rem, calc(100vw - 2 * var(--space-4)));
  max-height: min(42rem, 80vh);
  overflow: auto;
  box-shadow: 0 12px 32px rgb(0 0 0 / 35%);
}

.npanel-title {
  margin: 0 0 var(--space-2);
  font-size: 1.1rem;
}

.npanel-section {
  padding-block: var(--space-2);
  border-top: 1px solid var(--border);
}

.npanel-section h3 {
  margin: 0 0 var(--space-2);
  font-size: 0.95rem;
}

.npanel-list,
.npanel-tools {
  list-style: none;
  margin: 0 0 var(--space-2);
  padding: 0;
  display: grid;
  gap: var(--space-2);
}

.npanel-item {
  padding: var(--space-2);
  background: var(--bg);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--warning);
  border-radius: var(--radius);
}

.npanel p {
  margin: 0 0 var(--space-1);
  overflow-wrap: anywhere;
}

.npanel-what {
  font-weight: 600;
}

.tasks {
  display: grid;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.taskrow {
  padding: var(--space-2);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.taskrow p {
  margin: 0 0 var(--space-1);
  overflow-wrap: anywhere;
}

.taskrow-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.taskrow progress {
  flex: 1 1 8rem;
  max-width: 16rem;
  height: 0.75rem;
  accent-color: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
  .notify-busy {
    animation: none;
  }
}

@media (max-width: 40rem) {
  .notify {
    position: static;
  }

  .notify-panel {
    inset-inline: var(--space-3);
    width: auto;
  }
}

/* Expandable cards (cards.js): the head, a short lead and the actions stay; .icard-body opens.
   Without the script nothing is hidden. */
.icard-lead {
  color: var(--text-muted);
  font-size: 0.9rem;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.icard-open > .icard-lead {
  display: block;
  overflow: visible;
}

.icard-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.icard-body[hidden] {
  display: none;
}

.icard-body > * {
  margin: 0;
}

.fold-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 1.75rem;
  padding: 0 var(--space-2);
  font-size: 0.85rem;
}

.fold-toggle .icon {
  transition: transform 0.15s;
}

.icard-open .fold-toggle .icon {
  transform: rotate(180deg);
}

.icard-head:has(.fold-toggle) {
  cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .fold-toggle .icon {
    transition: none;
  }
}

/* The panel sits inside the top bar, whose rules make its forms inline and its buttons quiet:
   inside the panel they are ordinary forms and ordinary buttons again. */
.topbar .notify-panel form {
  display: block;
  margin: 0;
}

.topbar-tools .notify-panel button {
  background: var(--surface-2);
  border-color: var(--border-strong);
  color: var(--text);
}

.topbar-tools .notify-panel .btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.topbar-tools .notify-btn {
  color: var(--text-muted);
}

.field-note {
  margin: var(--space-1) 0 0;
  color: var(--text-muted);
  font-size: 0.85rem;
}

.field-examples {
  margin-top: var(--space-1);
  font-size: 0.875rem;
}

.field-examples summary {
  cursor: pointer;
  font-weight: 600;
}

.field-examples .facts {
  margin: var(--space-1) 0 0;
}

.dtable-sorts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1) var(--space-2);
  margin: 0;
  font-size: 0.9rem;
}

.sortchip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 1.75rem;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: inherit;
  text-decoration: none;
}

.sortchip:hover,
.sortchip.sorted {
  border-color: var(--accent);
}

.npanel h2 .icon,
.npanel h3 .icon {
  margin-inline-end: var(--space-2);
}

/* The two colour families of the managed host (README section 2.1, slice 2): a stripe and a
   badge for host surfaces and for container surfaces. Always paired with the word and the icon
   in the markup; the colour alone never carries the meaning. */
.family-host {
  border-inline-start: 4px solid var(--host);
}

.family-container {
  border-inline-start: 4px solid var(--container);
}

h1.family-host,
h1.family-container {
  padding-inline-start: 0.5rem;
}

.badge-host {
  border-color: var(--host);
}

.badge-container {
  border-color: var(--container);
}
