/* 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);
  --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);
    --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. */
.totals {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.5rem;
  margin-block: 1rem var(--pico-spacing);
  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);
}

.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: 1.5rem;
  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: var(--pico-spacing);
  padding: 1rem 1.25rem;
  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;
}

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

.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.75rem;
  padding: 0;
}

.builder-checks li {
  margin-bottom: 0.5rem;
  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: 1rem 1.25rem;
}

.pool-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0 0 1rem;
  padding: 0;
  background: none;
  border: 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: 1rem;
}

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

.part-now {
  margin-bottom: 0.5rem;
  font-weight: 500;
}

/* 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);
}

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

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

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

/* A product list: its filters in a row, then a table that scrolls inside its own card rather
   than running the page down past every product. */
.list-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 1.5rem;
  margin-bottom: 0.5rem;
}

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

.list-filters select {
  width: auto;
  margin-bottom: 0;
}

.list-tools label {
  font-size: 0.875rem;
}

.product-list figure {
  max-height: 24rem;
  overflow-y: auto;
}

/* The step's column is narrower than a page's tables: a list's columns wrap to fit it. */
.product-list figure table {
  min-width: 0;
}

.product-list th,
.product-list td {
  padding-inline: 0.5rem;
}

.product-list thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}

.product-list th small,
.product-list .reason {
  color: var(--pico-muted-color);
}

.product-list .reason {
  display: block;
  font-size: 0.8125rem;
}

/* A badge in a list can be a sentence ("needs an Open Rack v3 (ORv3) rack"). Kept on one line it
   made the table wider than the step, and the Choose button scrolled out of sight. */
.product-list .badge {
  border-radius: 0.875rem;
  white-space: normal;
}

.product-list td button {
  margin-bottom: 0;
  padding: 0.125rem 0.75rem;
  font-size: 0.8125rem;
}

/* A row the engine refuses: muted, its reason under the model. */
.product-list tr.greyed th,
.product-list tr.greyed td {
  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;
}

/* --- 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;
}
