/* Application styles. Pico (vendor/pico.min.css) provides the base; this file dresses it in
   the Myriad360 look (colours and type taken from myriad360.com) and adds the few components
   Pico has no class for. No inline styles anywhere (CSP): everything the templates need is here.
   Light and dark follow the OS (prefers-color-scheme); <html> carries no data-theme. */

/* --- Poppins, self-hosted (vendor/poppins). Latin only; other characters fall back to Arial. -- */

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("vendor/poppins/poppins-latin-400-normal.9212f6f9860f.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("vendor/poppins/poppins-latin-500-normal.a09f2fccfee3.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Poppins";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("vendor/poppins/poppins-latin-600-normal.72993dddf88a.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Tokens -----------------------------------------------------------------------------------
   Brand colours (taken from myriad360.com) are the same in light and dark. What changes with the
   OS colour scheme is the second set, the page/surface/text tokens, and the network and status
   colours; they are set again in the dark block below. */

:root {
  /* Myriad360 brand tokens */
  --m360-navy: #0a3971; /* primary: deep navy */
  --m360-blue: #2287fd; /* primary: dodger blue */
  --m360-amber: #fec234; /* primary: amber */
  --m360-midnight: #0a2546; /* secondary: midnight navy */
  --m360-alice: #f3f8ff; /* secondary: alice blue */
  --m360-steel: #48709f; /* secondary: steel blue */
  --m360-azure: #a7cffe; /* secondary: soft azure */
  --m360-n50: #f8fafb;
  --m360-n100: #f0f3f6;
  --m360-n200: #e8ecf0;
  --m360-n300: #dfe4e9;
  --m360-n400: #bbc3ce;
  --m360-n500: #96a1b2;
  --m360-n600: #728097;
  --m360-n700: #4d5e7b;
  --m360-n800: #293d60;
  --m360-n900: #041b45;
  --m360-blue-600: #1d4ed8;
  --m360-blue-700: #1e40af;
  /* States that are not brand colours: approved, and errors in forms. */
  --m360-green: #15803d;
  --m360-green-tint: #dcfce7;
  --m360-error: #b42318;
  --m360-error-tint: #fef3f2;
  /* Destructive buttons (Delete): 6.5:1 on white, so it reads as red without being a warning. */
  --m360-danger: #b91c1c;
  --m360-danger-hover: #991b1b;
  --m360-danger-tint: rgba(185, 28, 28, 0.1);
  --m360-danger-focus: var(--m360-danger);
}

/* --- Theme: Pico's variables, overridden ------------------------------------------------------
   <html> carries no data-theme, so Pico follows the OS: its light values sit on
   `:root:not([data-theme=dark])` and its dark ones on `:root:not([data-theme])` inside a
   prefers-color-scheme query, both of specificity 0,2,0. These blocks use `:root:not([data-theme])`,
   which matches both and wins by coming later. The light block states everything in the
   page/surface/text tokens, so the dark block only has to give those tokens (and the few
   colours that cannot follow them) their dark values. */

:root:not([data-theme]) {
  /* Page, surface and text */
  --m360-page: var(--m360-alice);
  --m360-surface: #fff;
  --m360-surface-alt: var(--m360-n50);
  --m360-text: var(--m360-n800);
  --m360-ink: var(--m360-n900);
  --m360-muted: var(--m360-n700);
  --m360-heading: var(--m360-navy);
  --m360-line: var(--m360-n200);
  --m360-line-strong: var(--m360-n300);
  --m360-field-border: var(--m360-n500);
  /* The edge of a box that only groups (a node group in the topology diagram): 3:1 or better
     against the surface in both schemes (4.0:1 on white, 4.4:1 on the dark surface). */
  --m360-edge: var(--m360-n600);
  /* Focus rings are solid: WCAG 1.4.11 asks 3:1 of a ring against what the control sits on, and a
     translucent one is under 2:1 on either page. The ring of buttons, links and summaries is navy
     (11.7:1 on white, 3.2:1 on the dodger blue of a filled button); a field's is dodger blue
     (3.5:1 on white, 3.3:1 on the alice page). tests/e2e measures every kind of control. */
  --m360-ring: var(--m360-navy);
  --m360-ring-field: var(--m360-blue);
  /* The edge of a selected pill (a tab, the current step), whose fill is navy: navy too in light,
     where navy is 10.7:1 on the page. */
  --m360-selected-edge: var(--m360-navy);
  /* Link text is blue-600 rather than dodger blue: dodger on white is only 3.5:1, blue-600 is
     6.7:1. */
  --m360-link: var(--m360-blue-600);
  --m360-link-hover: var(--m360-navy);

  /* Network and status colours. Every network colour is shown with a text label and every
     status with an icon and a word: colour never carries the meaning alone. --oob fails 3:1
     on the light surface, so management lines are always dashed as well. */
  --ew: #2a78d6; /* compute network */
  --ns: #eb6834; /* frontend network */
  --oob: #1baf7a; /* management network */
  --st: #8a5cd1; /* storage network */
  --good: #0ca30c;
  --warning: #fab219;
  --serious: #ec835a;
  --critical: #d03b3b;

  /* Rack diagram: what a slot holds, as a fill and an edge, in hues the network and status
     colours above do not use (magenta, cyan, sand, slate), and the dashed edge of reserved space.
     The model on a fill is 7:1 or better, an edge 3:1 or better on the rack's inside, and each is
     at least 8 apart in OKLab (x100) from every network and status colour. The key names them. */
  --slot-compute-fill: #f4c4e6;
  --slot-compute-edge: #a8368a;
  --slot-general-fill: #98d9e9;
  --slot-general-edge: #0f6174;
  --slot-storage-fill: #e8d49a;
  --slot-storage-edge: #7a5c10;
  --slot-network-fill: #e3e5e9;
  --slot-network-edge: #5d6470;
  --slot-reserved-edge: #6b6f78;

  /* Type. Pico grows the root size with the window (up to 131%), which is too big for Poppins,
     so it stays at 16px. */
  --pico-font-family: "Poppins", Arial, sans-serif;
  --pico-font-weight: 400;
  --pico-font-size: 100%;
  --pico-border-radius: 0.5rem;

  /* Page, text and cards */
  --pico-background-color: var(--m360-page);
  --pico-color: var(--m360-text);
  --pico-muted-color: var(--m360-muted);
  --pico-muted-border-color: var(--m360-line);
  --pico-text-selection-color: rgba(34, 135, 253, 0.25);
  --pico-h1-color: var(--m360-heading);
  --pico-h2-color: var(--m360-heading);
  --pico-h3-color: var(--m360-text);
  --pico-h4-color: var(--m360-text);
  --pico-h5-color: var(--m360-muted);
  --pico-h6-color: var(--m360-muted);
  --pico-card-background-color: var(--m360-surface);
  --pico-card-border-color: var(--m360-line);
  --pico-card-sectioning-background-color: var(--m360-surface-alt);
  --pico-card-box-shadow: 0 1px 3px rgba(10, 37, 70, 0.08);
  /* A sheet over the page (a picker's panel), lifted higher than a card. */
  --m360-panel-shadow: 0 8px 24px rgba(10, 37, 70, 0.18), 0 1px 3px rgba(10, 37, 70, 0.12);
  --pico-table-border-color: var(--m360-line);

  /* Links and filled buttons. Button fills are dodger blue and go deep navy on hover. */
  --pico-primary: var(--m360-link);
  --pico-primary-hover: var(--m360-link-hover);
  --pico-primary-underline: rgba(29, 78, 216, 0.45);
  --pico-primary-hover-underline: var(--m360-link-hover);
  --pico-primary-focus: var(--m360-ring);
  --pico-primary-background: var(--m360-blue);
  --pico-primary-hover-background: var(--m360-navy);
  --pico-primary-inverse: #fff;

  /* Outline buttons: .outline.secondary is navy, .outline.contrast (Delete, Remove) midnight. */
  --pico-secondary: var(--m360-navy);
  --pico-secondary-background: var(--m360-navy);
  --pico-secondary-hover: var(--m360-midnight);
  --pico-secondary-hover-background: var(--m360-midnight);
  --pico-secondary-underline: rgba(10, 57, 113, 0.45);
  --pico-secondary-focus: var(--m360-ring);
  --pico-contrast: var(--m360-midnight);
  --pico-contrast-background: var(--m360-midnight);
  --pico-contrast-hover: #000;
  --pico-contrast-hover-background: #000;
  --pico-contrast-focus: var(--m360-ring);

  /* Form fields: a visible border, and a dodger blue edge and ring on focus. */
  --pico-form-element-background-color: var(--m360-surface);
  --pico-form-element-border-color: var(--m360-field-border);
  --pico-form-element-color: var(--m360-ink);
  --pico-form-element-placeholder-color: var(--m360-muted);
  --pico-form-element-active-background-color: var(--m360-surface);
  --pico-form-element-active-border-color: var(--m360-blue);
  --pico-form-element-focus-color: var(--m360-ring-field);
  --pico-form-element-invalid-border-color: var(--m360-error);
  --pico-form-element-invalid-active-border-color: var(--m360-error);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --m360-page: #0d0d0d;
    --m360-surface: #1a1a19;
    --m360-surface-alt: #232322;
    --m360-text: #ffffff;
    --m360-ink: #ffffff;
    --m360-muted: #b8bcc4;
    --m360-heading: var(--m360-azure);
    --m360-line: #333332;
    --m360-line-strong: #454544;
    --m360-field-border: #6b6b69;
    --m360-link: var(--m360-blue);
    --m360-link-hover: var(--m360-azure);
    /* Soft azure is 9.8:1 or better on the dark page, surface and cards, and 4.7:1 on the blue of
       a filled button. */
    --m360-ring: var(--m360-azure);
    --m360-ring-field: var(--m360-azure);
    /* Navy is 1.7:1 on the dark page (1.5:1 on the surface), too faint to mark the selection
       (WCAG 1.4.11 asks 3:1): the selected pill's edge is soft azure, 12.0:1 and 10.8:1. */
    --m360-selected-edge: var(--m360-azure);
    /* The state colours, lightened to read on the dark page. */
    --m360-green: #86efac;
    --m360-green-tint: #10301a;
    --m360-error: #ff8b7e;
    --m360-error-tint: #3a1512;
    --m360-danger: #f87171;
    --m360-danger-hover: #fca5a5;
    --m360-danger-tint: rgba(248, 113, 113, 0.14);

    --ew: #3987e5;
    --ns: #d95926;
    --oob: #199e70;
    --st: #9b72e0;
    --good: #0ca30c;
    --warning: #fab219;
    --serious: #ec835a;
    --critical: #d03b3b;

    --slot-compute-fill: #6b2159;
    --slot-compute-edge: #ee8fd0;
    --slot-general-fill: #0b5f75;
    --slot-general-edge: #62cbe3;
    --slot-storage-fill: #5c4713;
    --slot-storage-edge: #c9a54a;
    --slot-network-fill: #3b404a;
    --slot-network-edge: #a3adbf;
    --slot-reserved-edge: #a0a09c;

    /* The colours the light block cannot state in tokens. */
    --pico-card-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
    --m360-panel-shadow: 0 8px 24px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(255, 255, 255, 0.04);
    --pico-primary-underline: rgba(34, 135, 253, 0.5);
    --pico-primary-background: var(--m360-blue-600);
    --pico-primary-hover-background: var(--m360-blue-700);
    --pico-secondary: var(--m360-azure);
    --pico-secondary-background: var(--m360-navy);
    --pico-secondary-hover: #fff;
    --pico-secondary-hover-background: var(--m360-blue-700);
    --pico-secondary-underline: rgba(167, 207, 254, 0.45);
    --pico-contrast: #fff;
    --pico-contrast-background: #fff;
    --pico-contrast-hover: var(--m360-azure);
    --pico-contrast-hover-background: var(--m360-azure);
  }
}

h1,
h2,
h3,
h4,
h5,
h6 {
  --pico-font-weight: 600;
}

strong,
b,
th {
  font-weight: 600;
}

h1 {
  --pico-font-size: 1.75rem;
}

h2 {
  --pico-font-size: 1.375rem;
}

/* Buttons and nav are Poppins 500. */
:is(button, [type="submit"], [type="button"], [role="button"]) {
  --pico-font-weight: 500;
}

/* Outline buttons tint on hover instead of staying see-through. Pico writes its hover rules
   as :is(..., [aria-current]:not(...), :hover, ...), which counts for as much as its most
   specific argument, so this repeats that form: equal weight, and later, so it wins. */
:is(button, [type="submit"], [type="button"], [role="button"]).outline:is(
    [aria-current]:not([aria-current="false"]),
    :hover,
    :active,
    :focus
  ) {
  --pico-background-color: rgba(34, 135, 253, 0.1);
}

/* A wider ring that stays visible on a white card. */
:where(select, textarea),
input:not([type="checkbox"], [type="radio"], [type="range"], [type="file"]) {
  --pico-outline-width: 0.1875rem;
}

/* --- Page frame: header, main, footer -------------------------------------------------------- */

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* `body > main` because Pico's own padding rule is `body > main` and must be out-ranked. */
body > main {
  flex: 1 0 auto;
  padding-top: 2.5rem;
  padding-bottom: 3rem;
}

.site-header {
  padding-block: 0.625rem;
  background: var(--m360-navy);
  /* The bar is dark, so its links, hover underline and focus ring are redefined for it. */
  --pico-color: #fff;
  --pico-primary: #fff;
  --pico-primary-hover: #fff;
  --pico-primary-underline: transparent;
  --pico-primary-hover-underline: var(--m360-amber);
  --pico-primary-focus: var(--m360-amber);
  --pico-secondary-focus: var(--m360-amber);
  /* Buttons in the bar (Sign out) are light outline buttons: white text and border. */
  --pico-secondary: #fff;
  --pico-secondary-hover: #fff;
  color: #fff;
}

.site-header nav {
  flex-wrap: wrap;
  row-gap: 0.25rem;
}

.site-header nav ul {
  flex-wrap: wrap;
}

.site-header nav li {
  padding-block: 0.25rem;
}

.site-header nav a {
  font-weight: 500;
  text-underline-offset: 0.4em;
  text-decoration-thickness: 2px;
}

.site-header .brand-logo {
  display: block;
  margin: 0;
  padding: 0;
  line-height: 0;
}

.site-header .brand-logo img {
  display: block;
  width: auto;
  height: 36px;
}

.site-header .product-name {
  margin-left: 0.5rem;
  padding-left: 1rem;
  border-left: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  font-weight: 500;
  line-height: 1.2;
}

.site-header button.outline.secondary {
  --pico-border-color: rgba(255, 255, 255, 0.7);
  padding: 0.375rem 1rem;
}

.site-header
  :is(button, [type="submit"], [type="button"], [role="button"]).outline:is(
    [aria-current]:not([aria-current="false"]),
    :hover,
    :active,
    :focus
  ) {
  --pico-background-color: rgba(255, 255, 255, 0.14);
}

@media (max-width: 575px) {
  /* "AI Infrastructure Configurator" is too long to sit beside the logo on a phone (390px), so
     the name takes its own row under it, flush with the logo and without the divider that
     belongs beside it, and the links wrap beneath that. */
  .site-header .brand-logo img {
    height: 30px;
  }

  .site-header .product-name {
    flex-basis: 100%;
    margin-left: 0;
    padding-left: 0.5rem;
    border-left: 0;
    font-size: 0.875rem;
  }
}

.site-footer {
  padding-block: 1.25rem;
  background: var(--m360-midnight);
  color: var(--m360-n300);
}

.site-footer small {
  color: inherit;
}

/* A form in the nav (Sign out) sits next to links, so it must not carry form spacing. */
nav form.logout,
nav form.logout button {
  margin-bottom: 0;
}

/* --- Cards and tables ------------------------------------------------------------------------ */

article {
  border: 1px solid var(--m360-line);
  border-radius: 0.75rem;
}

article > header {
  border-top-left-radius: calc(0.75rem - 1px);
  border-top-right-radius: calc(0.75rem - 1px);
}

article > footer {
  border-bottom-left-radius: calc(0.75rem - 1px);
  border-bottom-right-radius: calc(0.75rem - 1px);
}

/* Tables sit on a surface card; the card scrolls sideways on a narrow screen. */
figure {
  margin-bottom: var(--pico-spacing);
  overflow-x: auto;
  border: 1px solid var(--m360-line);
  border-radius: 0.75rem;
  background: var(--m360-surface);
  box-shadow: var(--pico-card-box-shadow);
}

figure table {
  /* Narrower than this the columns crush each other, so the card scrolls instead. */
  min-width: 46rem;
  margin-bottom: 0;
  --pico-background-color: var(--m360-surface);
}

thead th {
  background: var(--m360-surface-alt);
  color: var(--m360-muted);
  font-size: 0.875rem;
  white-space: nowrap;
}

tbody tr:last-child > * {
  border-bottom: 0;
}

/* Small text under a name, in a bold row header, stays regular weight. */
th small {
  font-weight: 400;
}

/* A date, a choice or a link that should not break across lines inside a table cell. Without it
   a cell shrinks to one word per line when the table is wider than its card. */
.nowrap {
  white-space: nowrap;
}

/* --- Sign-in, welcome, 403 and 404: one centred card ------------------------------------------ */

.centered-card {
  max-width: 28rem;
  margin: 1rem auto 2rem;
  padding: 2rem;
}

.centered-card h1 {
  font-size: 1.5rem;
  text-align: center;
}

/* The sign-in cards open with the logo for dark backgrounds on a navy band, which reads on the
   light page and on the dark one alike (the other logo is dark text and vanishes on a dark
   surface). The band runs to the card's edges, so it takes the padding back. */
.centered-card .card-brand {
  margin: -2rem -2rem 1.5rem;
  padding: 1.25rem 2rem;
  border-radius: calc(0.75rem - 1px) calc(0.75rem - 1px) 0 0;
  background: var(--m360-navy);
}

.centered-card .card-logo {
  display: block;
  width: 180px;
  height: 40px;
  margin: 0 auto;
}

.centered-card p:last-child,
.centered-card form:last-child {
  margin-bottom: 0;
}

/* --- Small helpers ----------------------------------------------------------------------------
   .badge is a neutral pill (a product's lifecycle, "verified"); .muted and .greyed are quiet
   text, the second for a row that cannot be chosen (it also shows why). */

.badge {
  display: inline-block;
  padding: 0.125rem 0.75rem;
  border-radius: 999px;
  background: var(--m360-line);
  color: var(--m360-muted);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
}

.muted,
.greyed {
  color: var(--pico-muted-color);
}

/* --- Messages and form errors ---------------------------------------------------------------- */

.message,
p[role="alert"] {
  margin-bottom: var(--pico-spacing);
  padding: 0.75rem 1rem;
  border: 1px solid var(--m360-azure);
  border-left-width: 4px;
  border-radius: var(--pico-border-radius);
  background: var(--m360-surface);
  color: var(--m360-text);
}

.message.success {
  border-color: var(--m360-green);
  background: var(--m360-green-tint);
}

.message.error,
p[role="alert"] {
  border-color: var(--m360-error);
  background: var(--m360-error-tint);
  color: var(--m360-error);
}

small[role="alert"] {
  color: var(--m360-error);
  font-weight: 500;
}

small[role="status"] {
  color: var(--m360-green);
  font-weight: 500;
}

/* --- Row actions: buttons side by side, without the form and button spacing Pico adds -------- */

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.actions form,
.actions form button,
.actions a[role="button"] {
  margin-bottom: 0;
}

/* Pico makes every submit button full width. Wherever one is not wrapped in a shrink-to-fit
   form it keeps to its label, and buttons side by side drop the stacked button margin. Only the
   buttons of the centred cards (sign in, welcome) stay full width. */
button[type="submit"] {
  width: auto;
}

.centered-card button[type="submit"] {
  width: 100%;
}

.actions > button {
  margin-bottom: 0;
}

/* --- Destructive buttons: Delete wears .outline.contrast.danger ------------------------------
   Pico builds an outline contrast button from --pico-contrast and --pico-contrast-hover, so
   redefining those two (and the focus ring) on the element is enough to turn it red. The hover
   tint repeats the form of the app's blue one above, equal weight and later, so it wins. */

:is(button, [type="submit"], [type="button"], [role="button"]).danger {
  --pico-contrast: var(--m360-danger);
  --pico-contrast-hover: var(--m360-danger-hover);
  --pico-contrast-focus: var(--m360-danger-focus);
  white-space: nowrap;
}

:is(button, [type="submit"], [type="button"], [role="button"]).danger:is(
    [aria-current]:not([aria-current="false"]),
    :hover,
    :active,
    :focus
  ) {
  --pico-background-color: var(--m360-danger-tint);
}

/* --- Admins page: one card per group, a row per admin ---------------------------------------- */

.admin-list {
  margin: 0 0 var(--pico-spacing);
  padding: 0;
  list-style: none;
  border: 1px solid var(--m360-line);
  border-radius: 0.75rem;
  background: var(--m360-surface);
  box-shadow: var(--pico-card-box-shadow);
}

.admin-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 0;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--m360-line);
}

.admin-list li:last-child {
  border-bottom: 0;
}

/* The address and its note take what the Remove button leaves, and a long address wraps in
   its own column instead of pushing the button down or off a narrow screen. */
.admin-list li > :first-child {
  flex: 1 1 auto;
  min-width: 0;
}

.admin-list .admin-email {
  font-weight: 500;
  overflow-wrap: anywhere;
}

.admin-list form {
  flex: none;
}

.admin-list form,
.admin-list form button {
  margin-bottom: 0;
}

/* --- Tabs: small pill links, left to right, with the current one filled navy ----------------- */

/* Pico spreads a <nav> across the row like a menu bar. */
nav.tabs {
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 0.5rem;
  margin-bottom: var(--pico-spacing);
}

.tabs a {
  padding: 0.25rem 0.875rem;
  border: 1px solid var(--m360-line-strong);
  border-radius: 999px;
  background: var(--m360-surface);
  font-weight: 500;
  text-decoration: none;
}

.tabs a:hover {
  border-color: var(--m360-blue);
}

.tabs a[aria-current="page"] {
  border-color: var(--m360-selected-edge);
  background: var(--m360-navy);
  color: #fff;
}

/* --- Networks: the line colour of a diagram's tiers and links -----------------------------------
   Management is dashed as well as green, because --oob alone is under 3:1 on the light surface.
   A network's label is always text beside the line. */

.net-compute {
  stroke: var(--ew);
}

.net-frontend {
  stroke: var(--ns);
}

.net-storage {
  stroke: var(--st);
}

.net-management {
  stroke: var(--oob);
  stroke-dasharray: 6 4;
}

/* --- Check levels: a coloured bar at the left. The icon and the level's word are in the markup --- */

.level-blocking,
.level-warning,
.level-assumption,
.level-added,
.level-note {
  padding-left: 0.75rem;
  border-left: 4px solid var(--level);
}

.level-blocking {
  --level: var(--critical);
}

.level-warning {
  --level: var(--warning);
}

.level-assumption {
  --level: var(--m360-steel);
}

.level-added {
  --level: var(--good);
}

.level-note {
  --level: var(--m360-n500);
}

/* The glyph of a check level, in the level's colour (--level, set by the .level-* class of an
   element around it). The word is always beside it; the glyph is decoration. Amber and grey
   take a dark glyph, which white would not read on. */
.level-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  background: var(--level);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 1;
  vertical-align: 0.1em;
}

.level-warning .level-icon,
.level-note .level-icon {
  color: #0b0b0b;
}

/* --- Builder: header, sticky totals, steps | step and tabs | checks --------------------------- */

.builder-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.builder-head h1,
.builder-head p {
  margin-bottom: 0.25rem;
}

.builder-head .read-only {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.read-only p,
.read-only form,
.read-only button {
  margin-bottom: 0;
}

/* The totals stay in view while the page scrolls under them, in a window wide enough to spare
   the room (see the media query below). */
.totals {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1.25rem;
  margin-block: 0.5rem 0.75rem;
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--m360-line);
  border-radius: 0.75rem;
  background: var(--m360-surface);
  box-shadow: var(--pico-card-box-shadow);
}

/* Below 48rem the bar wraps to a third of the window or more (a budgetary design's lines of badges
   make it taller still), so there it scrolls with the page. */
@media (min-width: 48rem) {
  .totals {
    position: sticky;
    top: 0;
    z-index: 2;
  }
}

.totals p {
  margin: 0;
}

.totals dl {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  margin: 0;
}

.totals dl > div {
  display: flex;
  flex-direction: column;
}

.totals dt {
  color: var(--m360-muted);
  font-size: 0.75rem;
  font-weight: 500;
}

.totals dd {
  margin: 0;
  color: var(--m360-ink);
  font-size: 1.125rem;
  font-weight: 600;
}

.level-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  font-size: 0.875rem;
}

/* A count sits in a row of counts: its icon carries the colour, so no bar at its left. */
.level-counts .level-count {
  padding-left: 0;
  border-left: 0;
}

.badge.budgetary {
  border: 1px solid var(--warning);
  background: var(--m360-surface-alt);
  color: var(--m360-text);
  white-space: normal;
}

.builder-grid {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr) 20rem;
  gap: 1rem;
  align-items: start;
}

@media (max-width: 1199px) {
  .builder-grid {
    grid-template-columns: 13rem minmax(0, 1fr);
  }

  .builder-checks {
    grid-column: 1 / -1;
  }
}

@media (max-width: 767px) {
  .builder-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.builder-step,
.builder-tab,
.builder-checks {
  margin-bottom: 0.75rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--m360-line);
  border-radius: 0.75rem;
  background: var(--m360-surface);
  box-shadow: var(--pico-card-box-shadow);
}

.builder-step h2,
.builder-checks h2 {
  --pico-font-size: 1.125rem;
}

/* --- Builder density ---------------------------------------------------------------------------
   The builder is a working page: an engineer sets a dozen choices and a few numbers and reads the
   totals as they change. So inside it (`.builder`, the main region of builder.html) the form
   fields are about 34px tall rather than Pico's 50px, labels are small and values are not, the
   gaps between fields are about half, and the cards and headings are smaller. Pico's spacing
   variables do it: they are set here, on the builder alone, so the sign-in pages, the
   configurations list, the details page and the admin keep Pico's. A value stays at 0.9rem or more
   (below, and in the picker's lists); the focus rings are left as they are (3:1, Task 21). */

.builder {
  --pico-form-element-spacing-vertical: 0.35rem;
  --pico-form-element-spacing-horizontal: 0.6rem;
}

.builder label {
  margin-bottom: 0.125rem;
  font-size: 0.8rem;
}

/* The words of a checkbox are its value, not a caption over one (where :has is not understood,
   the rule is dropped and they are as small as the others). */
.builder label:has(> input[type="checkbox"]) {
  margin-bottom: 0;
  font-size: 0.9rem;
}

/* The step: half Pico's gaps between its fields, paragraphs and grids. The variables are set on the
   step, so they are not those of the tabs (whose tables use Pico's cell padding). Pico gives a
   field a height of its own, from a line of 1rem: it is worked out again for the 0.9rem a value
   is set in, which makes a field 34.8px and a select the same. */
.builder-step {
  --pico-spacing: 0.5rem;
  --pico-typography-spacing-vertical: 0.5rem;
  --pico-grid-column-gap: 0.75rem;
  --pico-grid-row-gap: 0.5rem;
}

.builder-step input[type="text"],
.builder-step input[type="number"] {
  height: calc(
    0.9rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 +
      var(--pico-border-width) * 2
  );
  font-size: 0.9rem;
}

.builder-step select {
  font-size: 0.9rem;
}

/* A term over its value (the storage step's summary) is as large as the value. */
.builder-step dt {
  font-size: 0.9rem;
}

.builder-step h3 {
  --pico-font-size: 1.0625rem;
}

/* Two fields side by side: one column in a narrow window, two from 40rem. `minmax(0, 1fr)` lets a
   column shrink below what its field would like, so that a long word wraps rather than push the
   row wider than the step. */
.field-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0 var(--pico-grid-column-gap);
}

@media (min-width: 40rem) {
  .field-pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* A choice line beside its count (a build part, a NIC): the line has words and buttons to hold,
     so it takes twice the room, and the count sits level with it. */
  .field-pair.has-line {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    align-items: end;
  }
}

/* A level's checks under its word and count; Pico draws <details> with a chevron. */
.builder-checks details.check-group {
  margin-bottom: 0.25rem;
}

.builder-checks summary.check-level {
  font-size: 0.875rem;
  font-weight: 600;
}

/* A fieldset that only groups (and disables, for a read-only viewer) what is in it. */
fieldset.bare {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* Pico lays a <nav> out as a bar; the steps are a column of links, the current one filled. */
nav.builder-steps {
  display: block;
}

.builder-steps ol {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  margin: 0;
  padding: 0;
  list-style: none;
}

.builder-steps li {
  display: block;
  padding: 0;
}

/* Every step has an edge, clear until it is the current one (the padding gives back its width). */
.builder-steps a {
  display: block;
  margin: 0;
  padding: calc(0.375rem - 1px) calc(0.75rem - 1px);
  border: 1px solid transparent;
  border-radius: 0.5rem;
  text-decoration: none;
}

.builder-steps a[aria-current="step"] {
  border-color: var(--m360-selected-edge);
  background: var(--m360-navy);
  color: #fff;
  font-weight: 600;
}

.builder-checks ul {
  margin: 0 0 0.5rem;
  padding: 0;
}

.builder-checks li {
  margin-bottom: 0.375rem;
  list-style: none;
  font-size: 0.875rem;
}

.builder-checks li p {
  margin-bottom: 0.25rem;
}

.level-word {
  font-weight: 600;
}

.builder-checks form,
.builder-checks button {
  margin-bottom: 0;
}

.builder-checks button {
  padding: 0.25rem 0.75rem;
  font-size: 0.8125rem;
}

.builder-checks .deviations li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

/* --- Builder: GPU pools and product lists ----------------------------------------------------- */

/* Read by assistive technology, not drawn: a column heading a button column needs. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.pool-card {
  margin-bottom: var(--pico-spacing);
  padding: 0.75rem 1rem;
}

.pool-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  margin: 0 0 0.5rem;
  padding: 0;
  background: none;
  border: 0;
}

/* The card's words take the room there is, so that its buttons are at the right of them rather
   than under. */
.pool-head > :first-child {
  flex: 1 1 16rem;
  min-width: 0;
}

.pool-head h3,
.pool-head p {
  margin-bottom: 0.25rem;
}

.pool-card .actions a[role="button"],
.pool-card button {
  margin-bottom: 0;
  padding: 0.25rem 0.75rem;
  font-size: 0.875rem;
}

.pool-part {
  margin-bottom: 0.75rem;
}

.pool-part h4,
.pool-part h5 {
  margin-bottom: 0.25rem;
  font-size: 0.95rem;
}

/* A choice line (configs/_choice.html): what the slot holds now, then the button that takes it out
   ("Use the default"), then the picker's button, on one line. The words take the room there is, so
   the buttons are at the right; where there is not room for both they wrap, the buttons under the
   words. The picker's panel is in the line but out of the flow (a closed popover is not drawn, an
   open one is in the top layer). The summaries of the steps are `part-now` too, with words alone. */
.part-now {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.5rem;
  margin-bottom: 0.5rem;
  font-size: 0.9rem;
  font-weight: 500;
}

.part-now > :first-child {
  flex: 1 1 14rem;
  min-width: 0;
}

/* The compute network step's profile settings: as many columns as fit, not one row of all. */
.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 0 var(--pico-grid-column-gap);
}

/* A pair has a row of the grid to itself, the width of both columns. */
.settings-grid > .field-pair {
  grid-column: 1 / -1;
}

.drive-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 0.75rem;
}

.drive-row > div {
  flex: 1 1 16rem;
}

.drive-row button {
  margin-bottom: var(--pico-spacing);
}

/* --- Pickers: a Change button, and its list in a pop-over -------------------------------------
   configs/_picker.html: a button with `popovertarget` and, beside it, the panel, a `[popover]`
   div that holds "Loading…" until the browser first opens it and htmx fetches the list into it.
   Pico does not style `[popover]`, so the panel is dressed here from the surface tokens (light and
   dark alike): it reads as a floating sheet, over the page rather than in it, and it scrolls
   inside itself rather than running past the window. Esc and a click outside close it (the
   browser's light dismiss); a choice renders the step again, which puts in a new, closed panel. */

.picker-button {
  margin-bottom: 0;
  padding: 0.25rem 0.75rem;
  font-size: 0.875rem;
  white-space: nowrap;
}

/* The browser's own `[popover]` style centres the panel in the window (fixed, inset 0, margin
   auto): that is where it opens when anchor positioning is not there. The panel is as wide as its
   rows want, between 22rem and 40rem and never wider than the window less a margin, and at most
   60vh tall. */
.picker-panel {
  box-sizing: border-box;
  width: max-content;
  min-width: min(22rem, 100vw - 2rem);
  max-width: min(40rem, 100vw - 2rem);
  max-height: 60vh;
  overflow-y: auto;
  padding: 0;
  border: 1px solid var(--m360-line-strong);
  border-radius: var(--pico-border-radius);
  background: var(--m360-surface);
  color: var(--m360-text);
  box-shadow: var(--m360-panel-shadow);
}

/* While it is open the panel does not scroll itself: the filters stay where they are at the top and
   the list under them is what scrolls, so a button the keyboard focuses is scrolled into the list
   and never under the filters (WCAG 2.4.11). `display: flex` is for the open panel only: on the
   panel itself it would override the browser's hiding of a closed popover. */
.picker-panel:popover-open {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.picker-panel .product-list {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

/* Where the browser can anchor a box to the button that opened it (a popover's invoker is its
   implicit anchor, so no `anchor-name` is needed, which would take an inline style), the panel
   opens under the button, and above it only where it does not fit below but does above. Where it
   fits on neither side it stays below, held to the room there is (--picker-clamped). In a narrow
   window it is centred across the window; in a wide one it runs right from the button's left edge,
   or left from its right edge where it would not fit that way. */
@position-try --picker-clamped {
  max-height: calc(100% - 0.5rem);
}

@supports (position-area: bottom) {
  .picker-panel {
    margin-block: 0.25rem;
    justify-self: center;
    position-area: bottom span-all;
    position-try-fallbacks: flip-block, --picker-clamped;
  }

  @media (min-width: 70rem) {
    .picker-panel {
      justify-self: normal;
      position-area: bottom span-right;
      position-try-fallbacks:
        flip-inline, flip-block, flip-block flip-inline, --picker-clamped,
        flip-inline --picker-clamped;
    }
  }
}

.picker-panel > [aria-busy="true"] {
  display: block;
  padding: 0.75rem 1rem;
}

.picker-panel .product-list > p {
  margin: 0;
  padding: 0.75rem 1rem;
}

/* The filters, above the list. */
.list-tools {
  display: flex;
  flex: none;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 1.5rem;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--m360-line);
  background: var(--m360-surface);
}

.list-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}

.list-filters select {
  width: auto;
  margin-bottom: 0;
  font-size: 0.9rem;
}

.list-tools label {
  margin-bottom: 0;
}

.list-tools :where(select, input) {
  margin-bottom: 0;
}

/* A list: one row for each option. The text is at the left: the model, its maker small beside it,
   then the key specs and the badges as chips, on the same line where they fit (a short list:
   NICs, switches) and on the next where they do not (a GPU server with two long badges), and under
   them, for a row the engine refuses, why. The button is at the right, in a column of its own. */
.pick-list {
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.pick-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  padding: 0.375rem 0.75rem;
  border-bottom: 1px solid var(--m360-line);
  list-style: none;
}

.pick-row:last-child {
  border-bottom: 0;
}

/* The row the slot holds now: a tint and a bar at its edge, besides the word "Chosen". */
.pick-row[aria-current="true"] {
  background: rgba(34, 135, 253, 0.1);
  box-shadow: inset 3px 0 0 var(--m360-blue);
}

.pick-text {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.125rem 0.75rem;
  min-width: 0;
}

.pick-name {
  min-width: 0;
}

.pick-name small,
.pick-specs,
.pick-row .reason {
  color: var(--pico-muted-color);
}

.pick-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.125rem 0.5rem;
  min-width: 0;
}

.pick-specs {
  font-size: 0.875rem;
}

.pick-action {
  flex: none;
  white-space: nowrap;
}

.pick-action button {
  margin-bottom: 0;
  padding: 0.125rem 0.75rem;
  font-size: 0.8125rem;
}

.pick-row .reason {
  flex: 1 1 100%;
  font-size: 0.8125rem;
}

/* A badge of a list row: a small pill. It can be a sentence ("needs an Open Rack v3 (ORv3)
   rack"), so it wraps rather than make the row wider than its panel. */
.chip {
  display: inline-block;
  padding: 0 0.5rem;
  border-radius: 0.875rem;
  background: var(--m360-line);
  color: var(--m360-muted);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.5;
}

/* A row the engine refuses: muted, its reason under the line. */
.pick-row.greyed .pick-name strong {
  color: var(--pico-muted-color);
}

/* The engine's assumptions a step shows beside its fields (the storage step's): each in its
   level's bar, with the icon and the word in the markup. */
.step-notes {
  margin: 0 0 0.75rem;
  padding: 0;
}

.step-notes li {
  margin-bottom: 0.5rem;
  list-style: none;
  font-size: 0.875rem;
}

.step-notes li p {
  margin-bottom: 0.25rem;
}

/* A refusal's message takes the focus (configs/_step.html, core/_banner.html): when the browser
   scrolls it into view it keeps it clear of the totals bar stuck to the top of the window. The bar
   sticks only from 48rem, where it is at most about 153px tall (a budgetary design's, which has the
   most badges); this margin is more. */
.step-error,
.builder-banner p {
  scroll-margin-top: 12rem;
}

/* --- Topology diagram ---------------------------------------------------------------------------
   Drawn by configs/diagrams/topology.py: a column for each network, its tiers as boxes with the
   network's colour (a .net-* class on the tier's group and on each line), its links as 2px lines.
   Marks are thin and the labels are text: the .net-* rules above set `stroke`, which SVG text
   would inherit from its group, so text is drawn without a stroke, in the page's text colours, and
   the mark beside it carries the network. The figure scales with its box, but between about
   three quarters and one and a quarter times the size it is drawn at: smaller, its text is
   illegible and the box scrolls; larger, one column fills the page. Its width class
   (`topology-w<n>`, one for each 300 units of its viewBox, set by the code that draws it) is how
   this stylesheet knows its size, as no attribute can carry it: 300 units at 0.75 is 14rem. */

.topology-scroll {
  overflow-x: auto;
}

.topology {
  --topology-w: 1;
  display: block;
  width: 100%;
  min-width: calc(var(--topology-w) * 14rem);
  max-width: calc(var(--topology-w) * 23.5rem);
  height: auto;
}

.topology-w2 {
  --topology-w: 2;
}

.topology-w3 {
  --topology-w: 3;
}

.topology-w4 {
  --topology-w: 4;
}

.topology-w5 {
  --topology-w: 5;
}

.topology-w6 {
  --topology-w: 6;
}

.topology-w7 {
  --topology-w: 7;
}

.topology-w8 {
  --topology-w: 8;
}

.topology-w9 {
  --topology-w: 9;
}

.topology text {
  stroke: none;
  fill: var(--m360-text);
  font-size: 12px;
  text-rendering: geometricPrecision;
}

.topology .column-title {
  fill: var(--m360-ink);
  font-weight: 600;
}

.topology .tier-count {
  fill: var(--m360-ink);
  font-size: 13px;
  font-weight: 500;
}

.topology .tier-role,
.topology .node-count {
  fill: var(--m360-muted);
  font-size: 11px;
}

.topology .link-label {
  font-size: 11.5px;
}

.topology .label-bg {
  fill: var(--m360-surface);
  stroke: none;
}

.topology .node-name {
  font-weight: 500;
}

.topology .box {
  fill: var(--m360-surface);
  stroke-width: 2px;
}

/* A node group is not equipment of a network: neutral, with a thin edge. */
.topology .node .box {
  fill: var(--m360-surface-alt);
  stroke: var(--m360-edge);
  stroke-width: 1px;
}

.topology .link,
.topology .swatch {
  fill: none;
  stroke-width: 2px;
}

.topology a {
  cursor: pointer;
  text-decoration: none;
}

.topology a:is(:hover, :focus-visible) .box {
  fill: var(--m360-surface-alt);
}

.topology a:focus-visible {
  outline: none;
}

.topology a:focus-visible .box {
  stroke-width: 4px;
}

.topology-hint {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
}

/* --- Rack diagram -------------------------------------------------------------------------------
   Drawn by configs/diagrams/racks.py: an elevation (an <svg>) for each rack type, side by side and
   wrapping, each the same width: 256 units of viewBox at 256px, so that its text is the size it
   was set at. A slot's rectangle is coloured by what it holds (a kind-<kind> class; the tokens are
   with the network colours above), its label is the model, and the key below names each colour.
   Text is drawn without a stroke in the page's text colours, and lets the pointer through to the
   rectangle under it, which has the hover. A figure over its limit has a mark in its check level's
   colour (.level-<level> sets --level) beside the level's word. */

.racks-diagram {
  --slot-fill: var(--m360-surface-alt);
  --slot-edge: var(--m360-edge);
}

.racks-grid {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1rem 0.75rem;
}

.racks-diagram .rack-elevation {
  display: block;
  flex: 0 0 auto;
  width: 256px;
  max-width: 100%;
  height: auto;
}

.racks-diagram text {
  stroke: none;
  fill: var(--m360-text);
  font-size: 11px;
  text-rendering: geometricPrecision;
  pointer-events: none;
}

.racks-diagram .rack-title {
  fill: var(--m360-ink);
  font-size: 13px;
  font-weight: 600;
}

.racks-diagram .rack-model {
  fill: var(--m360-muted);
}

.racks-diagram .rack-figure {
  font-size: 12px;
}

.racks-diagram .status-word {
  fill: var(--m360-ink);
  font-size: 11px;
  font-weight: 600;
}

.racks-diagram .status-dot {
  fill: var(--level);
  stroke: none;
}

.racks-diagram .status-glyph {
  fill: #fff;
  font-size: 10px;
  font-weight: 700;
}

.racks-diagram .level-warning .status-glyph {
  fill: #0b0b0b;
}

.racks-diagram .ruler-label {
  fill: var(--m360-muted);
  font-size: 10px;
}

.racks-diagram .rack-basis {
  fill: var(--m360-muted);
  font-size: 10px;
}

/* The header's hover is its group's; text lets the pointer through, so this is what is hit. */
.racks-diagram .rack-head-hit {
  fill: transparent;
  stroke: none;
  pointer-events: all;
}

.racks-diagram .slot-label.tight {
  font-size: 8px;
}

.racks-diagram .rack-frame {
  fill: var(--m360-surface-alt);
  stroke: var(--m360-edge);
  stroke-width: 1px;
}

.racks-diagram .slot,
.racks-diagram .swatch {
  fill: var(--slot-fill);
  stroke: var(--slot-edge);
  stroke-width: 1px;
}

.racks-diagram .kind-gpu_server,
.racks-diagram .kind-rack_scale {
  --slot-fill: var(--slot-compute-fill);
  --slot-edge: var(--slot-compute-edge);
}

.racks-diagram .kind-general_server {
  --slot-fill: var(--slot-general-fill);
  --slot-edge: var(--slot-general-edge);
}

.racks-diagram .kind-storage {
  --slot-fill: var(--slot-storage-fill);
  --slot-edge: var(--slot-storage-edge);
}

.racks-diagram .kind-switch,
.racks-diagram .kind-appliance {
  --slot-fill: var(--slot-network-fill);
  --slot-edge: var(--slot-network-edge);
}

/* Reserved space is empty until the equipment it is kept for is: a dashed edge, no fill. */
.racks-diagram .kind-reserved,
.racks-diagram .kind-pdu,
.racks-diagram .kind-cdu {
  --slot-fill: transparent;
  --slot-edge: var(--slot-reserved-edge);
  stroke-dasharray: 4 3;
}

/* Equipment with no height in the catalog is drawn a nominal size: dotted, not as measured. */
.racks-diagram .slot.unsized {
  stroke-dasharray: 1 3;
  stroke-width: 2px;
}

.racks-key {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  margin: 0.75rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.8125rem;
}

.racks-key li {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  margin: 0;
  padding: 0;
}

.racks-key .key-swatch {
  flex: none;
  width: 22px;
  height: 14px;
}

.racks-hint {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
}

#racks-list {
  margin-top: 1rem;
}

#racks-list p,
#racks-list table {
  margin-bottom: 0.5rem;
  font-size: 0.875rem;
}

/* --- Builder: the BOM tab and the Review step --------------------------------------------------
   The BOM is a table a section, with a row of words above each subsection. A line the engineer
   pinned is marked by its row (a bar at the left and a tint of the warning colour), by the word
   "overridden" in its flags and by "engine: N" beside the input, so colour never carries it alone.
   The overrides that match no line sit in a box of the same colour with the Warning word and
   glyph, as a check of that level does. */

.bom-section {
  margin-bottom: 1.5rem;
}

.bom-section h3,
.bom-orphans h3 {
  margin-bottom: 0.5rem;
  font-size: 1.0625rem;
}

.bom-table {
  margin-bottom: 0;
  font-size: 0.875rem;
  /* On the tab's surface, as a figure's table is (Pico fills cells with the page colour). */
  --pico-background-color: var(--m360-surface);
}

.bom-table th,
.bom-table td {
  padding: 0.375rem 0.5rem;
  vertical-align: top;
}

.bom-table .bom-subsection th {
  background: var(--m360-surface-alt);
  color: var(--m360-muted);
  font-size: 0.8125rem;
  text-align: left;
}

/* The quantity cell: the input, then the engine's figure and Clear beside it as the width allows. */
.bom-qty {
  min-width: 7.5rem;
}

.bom-qty input {
  --pico-form-element-spacing-vertical: 0.25rem;
  --pico-form-element-spacing-horizontal: 0.5rem;
  width: 6.5rem;
  margin-bottom: 0.25rem;
}

.bom-engine {
  display: inline-block;
  margin-right: 0.5rem;
  color: var(--pico-muted-color);
  white-space: nowrap;
}

.bom-qty button {
  margin-bottom: 0.25rem;
  padding: 0.125rem 0.625rem;
  font-size: 0.8125rem;
}

.bom-flags .badge {
  margin: 0 0.25rem 0.25rem 0;
}

.bom-table tr.overridden > td {
  background: color-mix(in srgb, var(--warning) 16%, var(--m360-surface));
}

.bom-table tr.overridden > td:first-child {
  box-shadow: inset 4px 0 0 var(--warning);
}

.bom-orphans {
  margin-top: 1.5rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--warning);
  border-radius: var(--pico-border-radius);
  background: color-mix(in srgb, var(--warning) 12%, var(--m360-surface));
}

.bom-orphans ul {
  margin: 0;
  padding: 0;
}

.bom-orphans li {
  margin-bottom: 0.5rem;
  list-style: none;
  font-size: 0.875rem;
}

.bom-orphans li:last-child {
  margin-bottom: 0;
}

.bom-orphans li p {
  margin-bottom: 0.25rem;
  overflow-wrap: anywhere;
}

.bom-orphans button {
  margin-bottom: 0;
  padding: 0.125rem 0.625rem;
  font-size: 0.8125rem;
}

/* The Review step: a part each for the manual items, Export and the snapshots, under the step's
   own title (which is smaller than Pico's h3, so these are smaller too). Its tables are the step
   column's width, not a page's: no minimum, and on the card's surface. */
.review-part {
  margin-bottom: 1.5rem;
}

.review-part h3 {
  margin-bottom: 0.5rem;
  font-size: 1.0625rem;
}

.manual-items,
.snapshots {
  margin-bottom: 0.5rem;
  font-size: 0.875rem;
  --pico-background-color: var(--m360-surface);
}

.manual-items th,
.manual-items td,
.snapshots th,
.snapshots td {
  padding: 0.375rem 0.5rem;
}

.manual-items button {
  margin-bottom: 0;
  padding: 0.125rem 0.625rem;
  font-size: 0.8125rem;
}

#add-manual {
  margin-top: 1rem;
}

#add-manual h4 {
  margin-bottom: 0.5rem;
  font-size: 1rem;
}

#export [role="group"] {
  max-width: 36rem;
}

#export input,
#export button {
  margin-bottom: 0;
}
