/* ---------------------------------------------------------------
   Tech9IQ Design System — sole theme for the whole portal (customer +
   admin). Base tokens live in /assets/tech9iq-tokens.css, vendored from
   the design system's own colors_and_type.css. The shared component
   layer below is kept byte-identical to public/styles.css so both apps
   stay in sync; admin-only widgets follow after the shared block.

   LIGHT ONLY — see public/styles.css for the full rationale, including
   why the four status text colours are darkened brand hues rather than
   verbatim tokens.
----------------------------------------------------------------- */
@import url('/assets/tech9iq-tokens.css');

:root {
  /* The console's own role tokens, pointed at the AWS module's palette (the
     t9 kit, /assets/tech9-ui.css) so every page and every JS-built widget that
     reads them moves with it. The names stay: reports-charts.js and inline
     JS styles read --good/--critical/--warn/--info/--accent/--hairline/--muted
     at draw time. */
  --bg: #ffffff;
  --canvas: var(--t9-bg-page);
  --panel: #ffffff;
  --panel-raised: var(--t9-slate-50);
  --hairline: var(--t9-border);
  --hairline-strong: var(--t9-border-control);
  --border-subtle: var(--t9-border);

  --text: var(--t9-text);
  --text-soft: var(--t9-text-body);
  --muted: var(--t9-text-secondary);
  --faint: var(--t9-text-faint);

  --accent: var(--t9-brand-600);
  --accent-strong: var(--t9-brand-800);
  --accent-soft: var(--t9-brand-50);
  --accent-soft-text: var(--t9-brand-700);
  --accent-interactive: var(--t9-accent-500);

  /* Status: the AWS badge tones. --warn keeps a darker text than warning-700,
     which is only 3.4:1 on its own tint; this passes AA. */
  --good: var(--t9-success-700);
  --good-soft: var(--t9-success-50);
  --critical: var(--t9-danger-700);
  --critical-soft: var(--t9-danger-50);
  --warn: #8a5b10;
  --warn-soft: var(--t9-warning-50);
  --info: var(--t9-info-700);
  --info-soft: var(--t9-info-50);
  --color-danger: var(--t9-red-600);
  --color-brand-green: var(--t9-success-500);

  --shadow: none;
  --shadow-md: var(--t9-shadow-card);
  --shadow-lg: var(--t9-shadow-lg);
  --shadow-xl: var(--t9-shadow-xl);
  --shadow-raised: var(--t9-shadow-card);
  --radius: var(--t9-radius-lg);
  --sans: var(--t9-font-sans);
  --mono: var(--t9-font-mono);
  --font-mono: var(--t9-font-mono);
  /* Solid, as in the AWS module: no gradient buttons or bars. */
  --brand-gradient: var(--t9-brand-600);
  --gradient-horizontal: var(--t9-brand-600);
  --gradient-cyan-green: var(--t9-brand-600);

  --card-bg: #ffffff;
  --card-border: 1px solid var(--t9-border);
  --card-radius: var(--t9-radius-lg);
  --card-shadow: none;
  --btn-radius: var(--t9-radius-md);
  --btn-transition: background var(--t9-dur) var(--t9-ease), color var(--t9-dur) var(--t9-ease), border-color var(--t9-dur) var(--t9-ease);
  --input-radius: var(--t9-radius-md);
  --input-border: 1px solid var(--t9-border-control);
  --input-focus-border: var(--t9-focus);

  --scrim: var(--t9-overlay);
  --scrim-strong: rgba(15, 23, 42, .7);
}

* { box-sizing: border-box; }
/* Every element class below sets its own `display`, which — per the
   cascade — beats the UA stylesheet's `[hidden] { display: none }` even
   at equal specificity, because author rules always win over UA ones
   regardless of source order. That silently defeated `el.hidden = true`
   on anything with a class of its own — a .btn, first hit on the
   onboarding Approve/Reject/Show-credentials buttons, stayed visible no
   matter what JS set. One rule here, ahead of every class that follows,
   fixes it file-wide instead of patching each class that happens to
   collide with `hidden` as it's found. */
[hidden] { display: none !important; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--sans);
  /* The design system's own 14px base, actually applied at the root —
     without this, anything that doesn't carry one of the font-size
     utility classes below (a bare <p>/<div>/<li> used for copy) fell
     back to the browser's 16px default with its own looser default line
     height, which is exactly the kind of gap that makes a page feel
     bigger than its own type scale says it should. */
  font-size: var(--t9-fs-sm);
  line-height: var(--t9-lh-sm);
  -webkit-font-smoothing: antialiased;
}
::selection { background: var(--accent-soft); color: var(--accent-soft-text); }
button, input { font-family: inherit; }
a { color: inherit; }
:focus-visible { outline: 2px solid var(--t9-focus); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* tabular-nums alone lines up each digit's own width, but never told the cell
   to actually sit at the right edge — every currency/quantity column in the
   app (Billing, Rate Card, Invoices, Insights, Compute capacity...) rendered
   flush left like ordinary text, so figures of different lengths started at
   the same left edge instead of lining up on the ones place. */
.num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; text-align: right; }
.mono { font-family: var(--mono); }

/* ---------------------------- AUTH ----------------------------
   The AWS module's sign-in: slate-50 page, logo and product name above a
   white card, 14px labels, 8px inputs with the cyan focus ring, one solid
   brand button. */
.auth-shell { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 16px; background: var(--t9-bg-page); }
.auth-wrap { width: 100%; max-width: 448px; }
.auth-brand { display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 24px; }
.auth-brand img { height: 56px; width: auto; display: block; }
.auth-brand-divider { height: 24px; width: 1px; background: var(--t9-border-control); }
.auth-brand h1 { margin: 0; font-size: var(--t9-fs-lg); line-height: var(--t9-lh-lg); font-weight: var(--t9-fw-semibold); color: var(--t9-text); }
.auth-card { background: #fff; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-xl); padding: 24px; box-shadow: var(--t9-shadow-card); }
.auth-form { display: flex; flex-direction: column; gap: 16px; }
.auth-label { display: block; margin-bottom: 4px; font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); font-weight: var(--t9-fw-medium); color: var(--t9-slate-700); }
.auth-input {
  display: block; width: 100%; border-radius: var(--t9-radius-lg); background: #fff; border: 1px solid var(--t9-border-control);
  padding: 8px 12px; font: inherit; font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); color: var(--t9-text);
}
.auth-input::placeholder { color: var(--t9-text-secondary); }
.auth-input:focus { outline: none; border-color: var(--t9-focus); box-shadow: var(--t9-ring-focus); }
.auth-submit {
  width: 100%; border: 0; border-radius: var(--t9-radius-lg); background: var(--t9-primary); color: #fff;
  font: inherit; font-size: var(--t9-fs-sm); font-weight: var(--t9-fw-medium); padding: 10px 12px; cursor: pointer;
  transition: background var(--t9-dur) var(--t9-ease);
}
.auth-submit:hover { background: var(--t9-primary-hover); }
.auth-submit:disabled { opacity: .5; cursor: default; }
.auth-error { margin: 0; font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); color: var(--t9-red-700); background: var(--t9-red-50); border: 1px solid var(--t9-red-200); border-radius: var(--t9-radius-lg); padding: 8px 12px; }
.auth-card .subtitle { margin: 0 0 16px; font-size: var(--t9-fs-sm); color: var(--t9-text-muted); }
.auth-foot { margin: 16px 0 0; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-text-secondary); text-align: center; }
/* The 404 page and older markup still use these. */
.brand-logo { display: inline-block; line-height: 0; }
.brand-logo img { display: block; height: 32px; width: auto; }
.error { color: var(--t9-red-700); font-size: var(--t9-fs-sm); margin-top: 12px; }

/* ---------------------------- SHELL ----------------------------
   The frame (sidebar, top bar, breadcrumbs, content column) is the UI kit's,
   /assets/tech9-ui.css, filled by sidebar.js. This is the console's own
   furniture inside it: identity, search, alerts, Refresh, and the pages. */
.sidebar { position: relative; z-index: 400; }
.sidebar__nav { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.sidebar__who-text { min-width: 0; }
.avatar {
  width: 28px; height: 28px; border-radius: var(--t9-radius-full); background: var(--t9-brand-50);
  display: grid; place-items: center; font-size: var(--t9-fs-11); font-weight: var(--t9-fw-semibold);
  color: var(--t9-brand-700); flex-shrink: 0;
}
button.hamburger-btn { display: none; }

.search-wrap { position: relative; width: 280px; }
.search {
  display: flex; align-items: center; gap: 6px; height: var(--t9-control-h); padding: 0 10px; margin: 0;
  background: #fff; border: 1px solid var(--t9-border-control); border-radius: var(--t9-radius-md);
  color: var(--t9-text-faint); cursor: text;
}
.search:focus-within { border-color: var(--t9-focus); box-shadow: var(--t9-ring-focus); }
.search input { flex: 1; min-width: 0; border: 0; background: none; color: var(--t9-text); font: inherit; font-size: var(--t9-fs-sm); outline: none; }
.search input::placeholder { color: var(--t9-text-faint); }
.search kbd { font-size: var(--t9-fs-11); background: var(--t9-slate-50); border: 1px solid var(--t9-border); border-radius: var(--t9-radius-sm); padding: 0 5px; color: var(--t9-text-secondary); }
.search-results {
  display: none; position: absolute; top: calc(100% + 4px); right: 0; width: 420px; max-width: calc(100vw - 32px);
  background: #fff; border: 1px solid var(--t9-border-control); border-radius: var(--t9-radius-md);
  box-shadow: var(--t9-shadow-lg); z-index: 150; max-height: 60vh; overflow-y: auto; padding: 4px 0;
}
.search-results.open { display: block; }
.search-group-label { padding: 6px 10px 2px; font-size: var(--t9-fs-10); font-weight: var(--t9-fw-semibold); text-transform: uppercase; letter-spacing: var(--t9-tracking-wide); color: var(--t9-text-faint); }
.search-result-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; cursor: pointer; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-text); }
.search-result-row:hover, .search-result-row.sel { background: var(--t9-slate-50); }
.search-result-row .sr-sub { color: var(--t9-text-secondary); margin-left: auto; }
.search-empty { padding: 12px; font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); }

.sync-age { font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); white-space: nowrap; }
.refresh-btn { color: var(--t9-text-muted); border-color: var(--t9-border); }
.refresh-btn.is-busy .i { animation: t9-spin 1s linear infinite; }
.notif-wrap { position: relative; }
.notif-wrap .dot { position: absolute; top: 4px; right: 4px; width: 8px; height: 8px; border-radius: var(--t9-radius-full); background: var(--t9-danger-500); border: 2px solid #fff; }
/* A bordered icon button, still used inside pages. */
.icon-btn {
  width: 34px; height: 34px; display: grid; place-items: center; border-radius: var(--t9-radius-md);
  border: 1px solid var(--t9-border-control); background: #fff; color: var(--t9-text-secondary); cursor: pointer; position: relative;
}
.icon-btn svg { width: 16px; height: 16px; }
.icon-btn:hover { background: var(--t9-slate-50); color: var(--t9-text); }

/* The pages: one at a time, in the AWS module's 1152px column. */
.canvas > .page { max-width: var(--t9-content-max); margin: 0 auto; }
.page { display: none; }
.page.active { display: block; }

/* flex-wrap: a heading plus a row of page actions has to be able to drop the
   actions to a second line on a narrow window rather than overflow. */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.page-head h1 { display: flex; align-items: center; gap: 8px; margin: 0; font-size: var(--t9-fs-lg); line-height: var(--t9-lh-lg); font-weight: var(--t9-fw-semibold); color: var(--t9-text); text-wrap: balance; }
/* 14px under the 18px title, as the AWS module's page and detail headers — and
   the same size Customer-Login and Billing use under theirs. */
.page-head p { margin: 4px 0 0; color: var(--t9-text-secondary); font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); max-width: 80ch; }
.stack-3 > * + * { margin-top: 12px; }
.stack-6 > * + * { margin-top: 24px; }
.section-title { display: flex; align-items: center; gap: 6px; margin: 0; }
.section-title .i { color: var(--t9-text-faint); }

/* ── "How this works" ─────────────────────────────────────────────────────
   Every page used to open with a paragraph explaining itself, and everyone read
   all of it, every time, before reaching the thing they came for. Several of
   those paragraphs record a real distinction worth keeping — a credit is not a
   discount, a run rate is not an invoice — so the text is demoted rather than
   deleted: closed by default, one click away, and out of the path of someone
   who already knows. */
.page-info { margin-top: var(--space-2); max-width: 62ch; }
.page-info summary {
  display: inline-flex; align-items: center; gap: 5px; cursor: pointer;
  font-size: var(--t9-fs-xs); font-weight: var(--t9-fw-medium); color: var(--t9-link);
  list-style: none; padding: 2px 0; width: fit-content;
}
.page-info summary::-webkit-details-marker { display: none; }
.page-info summary::before {
  content: "i"; display: grid; place-items: center;
  width: 14px; height: 14px; border-radius: var(--radius-full);
  border: 1.5px solid currentColor; font-size: 9px; font-weight: var(--fw-bold);
  font-style: italic; font-family: Georgia, serif;
}
.page-info summary:hover { color: var(--accent-strong); }
.page-info[open] summary { margin-bottom: var(--space-2); }
.page-info p {
  margin: 0; padding: var(--space-3) var(--space-4);
  background: var(--panel-raised); border-left: 2px solid var(--hairline-strong);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  font-size: var(--fs-xs); line-height: var(--lh-relaxed); color: var(--text-soft);
}

/* Buttons: the AWS module's. A plain .btn is its secondary (white, slate
   border), .btn.primary its solid brand button, .btn.danger its red one.
   Links wear .btn too (the AWS card, the 404 page), hence no underline. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: var(--t9-control-h);
  border-radius: var(--t9-radius-md); border: 1px solid var(--t9-border-control); background: #fff; color: var(--t9-slate-700);
  font: inherit; font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); font-weight: var(--t9-fw-medium); padding: 0 12px;
  cursor: pointer; white-space: nowrap; transition: var(--btn-transition); text-decoration: none;
}
.btn:hover { background: var(--t9-slate-50); color: var(--t9-text); }
/* A standalone toggle (not one of a .segmented group) still needs to show
   its own pressed state — "Locked only" on Compute is the first of these. */
.btn.active, .btn[aria-pressed="true"] { background: var(--t9-selected-bg); color: var(--t9-selected-text); border-color: var(--t9-brand-300); }
.btn.primary { background: var(--t9-primary); border-color: var(--t9-primary); color: #fff; }
.btn.primary:hover { background: var(--t9-primary-hover); border-color: var(--t9-primary-hover); color: #fff; }
.btn svg { width: 14px; height: 14px; }
/* Disabled stays still under the pointer, or it reads as clickable. */
.btn:disabled, .btn.danger:disabled, .btn.primary:disabled { opacity: .5; cursor: not-allowed; }
.btn:disabled:hover { background: #fff; color: var(--t9-slate-700); }
.btn.primary:disabled:hover { background: var(--t9-primary); color: #fff; }

.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; margin-bottom: 16px; }
.kpi { background: #fff; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-lg); padding: 16px; }
.kpi-label { font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-text-secondary); font-weight: var(--t9-fw-medium); display: flex; align-items: center; justify-content: space-between; }
.kpi-value { font-size: var(--t9-fs-2xl); line-height: var(--t9-lh-2xl); font-weight: var(--t9-fw-semibold); margin-top: 4px; color: var(--t9-text); }
.kpi-value small { font-size: var(--t9-fs-sm); font-weight: var(--t9-fw-medium); color: var(--t9-text-secondary); }
.kpi-delta { font-size: var(--fs-xs); margin-top: 3px; display: flex; align-items: center; gap: var(--space-1); font-weight: var(--fw-medium); }
.kpi-delta.up { color: var(--good); }
.kpi-delta.down { color: var(--critical); }
.spark { display: block; margin-top: var(--space-2); width: 100%; height: 30px; }

/* A panel is the AWS card: white, slate-200 border, 8px corners, no shadow. */
.panel { background: #fff; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-lg); box-shadow: none; }
.panel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--t9-border); }
.panel-head h2 { font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); margin: 0; font-weight: var(--t9-fw-semibold); color: var(--t9-text-title2); }
.panel-head .count { font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); }
.panel-head .spacer { flex: 1; }

.grid-2 { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--space-4); align-items: start; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }
@media (max-width: 980px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }
.stack { display: flex; flex-direction: column; gap: var(--space-4); }

/* Tables: the AWS DataTable. Sentence-case slate-500 headers on slate-50,
   white rows, slate-200 rules, slate-50 hover. */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); }
thead th {
  text-align: left; font-weight: var(--t9-fw-medium); color: var(--t9-text-secondary); padding: 8px 12px;
  border-bottom: 1px solid var(--t9-border); white-space: nowrap; background: var(--t9-slate-50);
}
tbody { background: #fff; }
tbody td { padding: 8px 12px; border-bottom: 1px solid var(--t9-border); vertical-align: middle; color: var(--t9-slate-700); }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--t9-slate-50); }
td.name { font-weight: var(--t9-fw-medium); color: var(--t9-text); }
td.sub, .sub { color: var(--t9-text-secondary); font-size: var(--t9-fs-xs); }

/* Status chips are the AWS StatusBadge: a pill in the tone's tint with a
   same-tint border, no dot. The class names stay (cloud-gate.js sorts MFA rows
   by the literal 'chip critical'). */
.chip { display: inline-flex; align-items: center; gap: 4px; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); font-weight: var(--t9-fw-medium); padding: 2px 8px; border-radius: var(--t9-radius-full); border: 1px solid transparent; white-space: nowrap; }
.chip.good { background: var(--t9-success-50); color: var(--t9-success-700); border-color: var(--t9-success-50); }
.chip.critical, .chip.bad { background: var(--t9-danger-50); color: var(--t9-danger-700); border-color: var(--t9-danger-50); }
.chip.warn { background: var(--t9-warning-50); color: var(--warn); border-color: var(--t9-warning-50); }
.chip.info { background: var(--t9-info-50); color: var(--t9-info-700); border-color: var(--t9-info-50); }
.chip.muted, .chip:not(.good):not(.critical):not(.bad):not(.warn):not(.info) { background: var(--t9-slate-100); color: var(--t9-slate-600); border-color: var(--t9-slate-100); }

.bar-track { width: 100%; height: 8px; border-radius: var(--t9-radius-full); background: var(--t9-slate-100); overflow: hidden; }
.bar-fill { height: 100%; border-radius: var(--t9-radius-full); background: var(--t9-brand-500); }
.bar-fill.good { background: var(--color-brand-green); }
.bar-fill.critical { background: var(--color-danger); }
.quota-cell { display: flex; flex-direction: column; gap: var(--space-1); min-width: 120px; }
.quota-cell .nums { display: flex; justify-content: space-between; font-size: var(--fs-xs); color: var(--muted); }

/* Row actions: the AWS compact buttons (12px, slate border). A destructive one
   is quiet until pointed at, then the AWS soft red. */
.row-actions { display: flex; gap: 4px; justify-content: flex-end; }
.row-actions button {
  border: 1px solid var(--t9-border-control); background: #fff; color: var(--t9-slate-700);
  border-radius: var(--t9-radius-md); padding: 4px 8px; font: inherit; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs);
  font-weight: var(--t9-fw-medium); cursor: pointer; transition: var(--btn-transition); white-space: nowrap;
}
.row-actions button:hover { background: var(--t9-slate-50); color: var(--t9-text); }
.row-actions button.danger { color: var(--t9-red-700); }
.row-actions button.danger:hover { background: var(--t9-red-50); color: var(--t9-red-700); border-color: var(--t9-red-200); }
/* In a table cell read left to right (a customer's user, an account). */
.row-actions--start { justify-content: flex-start; flex-wrap: wrap; align-items: center; }
.page-head > .row-actions { align-self: center; }
/* The customer portal's usage alerts (customer-ui.js). */
.cx-alerts { display: flex; flex-direction: column; gap: 10px; max-width: 640px; }
.cx-h2 { font-size: var(--t9-fs-md, 1rem); margin: 6px 0 0; }
.cx-people { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.cx-field { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cx-field input { width: 120px; }
.cx-actions-row { display: flex; gap: 8px; flex-wrap: wrap; }
.cx-invite { display: flex; gap: 16px; flex-wrap: wrap; }
.cx-invite input { width: 260px; max-width: 100%; }
.cx-mfa { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 20px; margin-top: 8px; }
.cx-qr svg { width: 200px; height: 200px; max-width: 100%; background: #fff; }
.cx-codes { columns: 2; margin: 6px 0 10px; padding-left: 20px; }
/* A customer's self-service quota cap (customers-ui.js). */
.bz-caps { display: flex; flex-wrap: wrap; gap: 12px; margin: 8px 0; }
.bz-cap { display: flex; flex-direction: column; gap: 4px; font-size: var(--t9-fs-sm); }
.bz-cap input { width: 120px; }

/* The customer portal (html.portal-customer, set by /admin/portal-mode.js):
   the staff-only chrome, and the actions the portal doesn't offer customers
   yet, are not shown. The server refuses them either way (customer-portal.js). */
.portal-customer .search-wrap, .portal-customer .notif-wrap,
.portal-customer #profile-menu [data-sidebar-panel],
.portal-customer #profile-menu .profile-menu__sep,
.portal-customer [data-open-modal="create-subnet"],
.portal-customer [data-open-modal="create-tenant"], .portal-customer [data-open-modal="create-volume-group"],
.portal-customer [data-act="save-template"], .portal-customer [data-vmact="gpu"],
.portal-customer [data-assign-pip], .portal-customer [data-edit-pip], .portal-customer [data-release-pip],
.portal-customer [data-vmtab="flow"], .portal-customer [data-vmtab="categories"],
.portal-customer [data-qr-approve], .portal-customer [data-qr-reject], .portal-customer #quota-request-new {
  display: none !important;
}
/* The Nutanix account switcher, under the cloud's name in the sidebar. */
.sidebar__account { display: flex; flex-direction: column; gap: 4px; margin: 0 12px 8px; }
.sidebar__account select { width: 100%; padding: 6px 8px; border: 1px solid var(--t9-border-control); border-radius: var(--t9-radius-md); background: #fff; font: inherit; font-size: var(--t9-fs-sm); color: var(--t9-text); }

.toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 16px; border-bottom: 1px solid var(--t9-border); flex-wrap: wrap; }
/* Filter chips: the AWS chip button (slate-100, 12px); on is the selected tint. */
.filter-chip {
  border: 0; background: var(--t9-slate-100); color: var(--t9-text-muted);
  padding: 6px 10px; border-radius: var(--t9-radius-md); font: inherit; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); font-weight: var(--t9-fw-medium); cursor: pointer;
}
.filter-chip:hover { background: var(--t9-slate-200); color: var(--t9-text); }
.filter-chip.active { background: var(--t9-selected-bg); color: var(--t9-selected-text); }
.toolbar .search { max-width: 240px; height: 30px; margin-left: auto; }

/* DS "Information Card": light gray fill with a Tech Blue left accent border */
.empty-note {
  display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-5);
  background: var(--panel-raised); color: var(--text-soft); border-left: 3px solid var(--accent);
  border-bottom: 1px solid var(--hairline); font-size: var(--fs-sm);
}
.empty-note svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--accent); }

.feed { list-style: none; margin: 0; padding: var(--space-1) 0; }
.feed li { display: flex; gap: var(--space-3); padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--border-subtle); font-size: var(--fs-sm); }
.feed li:last-child { border-bottom: none; }
.feed .dot-icon { width: 24px; height: 24px; border-radius: var(--radius-md); flex-shrink: 0; display: grid; place-items: center; margin-top: 1px; }
.feed .dot-icon svg { width: 13px; height: 13px; }
.feed .dot-icon.good { background: var(--good-soft); color: var(--good); }
.feed .dot-icon.critical { background: var(--critical-soft); color: var(--critical); }
.feed .dot-icon.info { background: var(--info-soft); color: var(--info); }
.feed .dot-icon.warn { background: var(--warn-soft); color: var(--warn); }
.feed .feed-body { flex: 1; }
.feed .feed-title { color: var(--text-soft); }
.feed .feed-meta { color: var(--faint); font-size: var(--fs-xs); margin-top: 2px; }

.capacity-row { padding: var(--space-3) var(--space-5); border-bottom: 1px solid var(--border-subtle); }
.capacity-row:last-child { border-bottom: none; }
.capacity-row .top { display: flex; justify-content: space-between; font-size: var(--fs-sm); margin-bottom: var(--space-2); }
.capacity-row .top .label { color: var(--text-soft); font-weight: var(--fw-semibold); }
.capacity-row .top .val { color: var(--muted); }

.role-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-3); padding: var(--space-5); }
.role-card { border: 1px solid var(--hairline); border-radius: var(--radius-lg); padding: var(--space-4); background: var(--panel-raised); }
.role-card h3 { margin: 0 0 var(--space-1); font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text); }
.role-card p { margin: 0; font-size: var(--fs-xs); color: var(--text-soft); line-height: var(--lh-normal); }
.role-card .role-count { margin-top: var(--space-2); font-size: var(--fs-xs); color: var(--muted); }

/* The AWS empty/loading line: small slate-500 text, centred, 24px of air. */
.loading, .empty { color: var(--t9-text-secondary); font-size: var(--t9-fs-sm); padding: 24px 16px; text-align: center; }
.footer-note { margin-top: var(--space-8); font-size: var(--fs-xs); color: var(--faint); text-align: center; line-height: var(--lh-relaxed); }
.footer-note b { color: var(--text-soft); font-weight: var(--fw-semibold); }

/* ---------------------------- QUICK ACTIONS ---------------------------- */
.quick-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-6); }
.quick-action {
  display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start;
  background: var(--panel); border: var(--card-border); border-radius: var(--radius);
  padding: var(--space-4) var(--space-5); box-shadow: var(--shadow); cursor: pointer; text-align: left; width: 100%;
  transition: var(--btn-transition);
}
.quick-action:hover { border-color: var(--accent); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.quick-action .qa-icon {
  width: 32px; height: 32px; border-radius: var(--radius-md); background: var(--gradient-cyan-green);
  color: var(--fg-inverse); display: grid; place-items: center;
}
.quick-action .qa-icon svg { width: 17px; height: 17px; }
.quick-action .qa-label { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text); }
.quick-action .qa-sub { font-size: var(--fs-xs); color: var(--muted); }

/* ---------------------------- FORMS ---------------------------- */
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px; }
.form-grid.single { grid-template-columns: 1fr; }
.field { display: flex; flex-direction: column; gap: 4px; font-size: var(--t9-fs-sm); }

/* A form long enough to need grouping (Launch VM's is the case this was
   built for) reads as one undifferentiated grid of inputs without it — the
   same problem the detail view's own .detail-section-label already solved,
   given the same treatment here. The hairline above each (skipped on the
   first) is what actually reads as "a new group starts here" rather than
   just another label floating in the grid. */
.field-section-label {
  grid-column: 1 / -1;
  font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); text-transform: uppercase; letter-spacing: var(--t9-tracking-wide); font-weight: var(--t9-fw-semibold);
  color: var(--t9-text-secondary); padding-top: 12px; margin-top: 4px;
  border-top: 1px solid var(--t9-border);
}
.form-grid > .field-section-label:first-child { padding-top: 0; margin-top: 0; border-top: none; }

/* Launch VM outgrew the 560px every other form dialog is sized for — nine
   fields at that width was either two cramped columns or the orphaned-field
   gap this was written to fix. A little more room, not modal-wide's full
   viewport treatment (that one is sized for a machine's entire detail view,
   not a form). */
.modal.modal-form-wide { max-width: 640px; }
.field.span-2 { grid-column: 1 / -1; }
/* Labels and inputs: the AWS form controls (12px medium label, 34px input). */
.field label, .field > span { font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); font-weight: var(--t9-fw-medium); color: var(--t9-text-muted); }
.field .hint { font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); font-weight: var(--t9-fw-regular); }
.field input, .field select, .field textarea {
  background: #fff; border: 1px solid var(--t9-border-control); border-radius: var(--t9-radius-md);
  height: var(--t9-control-h); padding: 0 10px; font-size: var(--t9-fs-sm); color: var(--t9-text); font-family: inherit;
}
.field input[type="checkbox"], .field input[type="radio"] { height: auto; }
.field textarea { height: auto; padding: 6px 10px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--t9-focus); box-shadow: var(--t9-ring-focus);
}
.field textarea { resize: vertical; min-height: 64px; }
/* A checkbox reads wrong stacked under a bold heading label the way every
   other .field does — this is the inline "[x] Do the thing" row instead,
   first needed for Launch VM's "force password change at first logon". */
.checkbox-field {
  display: flex; align-items: center; gap: var(--space-2);
  font-weight: var(--fw-regular); color: var(--text); cursor: pointer;
}
.checkbox-field input { width: auto; }
.form-error {
  grid-column: 1 / -1; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-red-700); background: var(--t9-red-50);
  border: 1px solid var(--t9-red-200); border-radius: var(--t9-radius-md); padding: 6px 10px; display: none;
}
.form-error.visible { display: block; }
.form-actions { grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-1); }

/* ---------------------------- MODAL ---------------------------- */
/* A modal is meant to block everything behind it — but at z-index 100 it sat
   below the search dropdown (150), the notification dropdown (150), and a
   sidebar flyout (230): hover a category or leave a dropdown open while a
   modal is up, and that transient UI rendered on top of what was supposed to
   be the one surface blocking the whole page. Raised above the mobile nav
   drawer (600) too, so a modal always wins regardless of what else is open. */
.modal-overlay {
  position: fixed; inset: 0; background: var(--t9-overlay);
  display: none; align-items: flex-start; justify-content: center; padding: 6vh var(--space-5); z-index: 650; overflow-y: auto;
}
.modal-overlay.open { display: flex; }
/* Blur and scale animate together, so the dialogue reads as a surface arriving
   rather than a box that faded in. A flat opacity fade was the cheaper move,
   but it is exactly the difference between a material and a layer. */
.modal { animation: modal-rise 200ms cubic-bezier(.2,.7,.3,1); }
.modal {
  background: #fff; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-xl);
  width: 100%; max-width: 560px; box-shadow: var(--t9-shadow-2xl);
}
@keyframes modal-rise {
  from { opacity: 0; transform: translateY(10px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .modal-overlay { backdrop-filter: none; background: var(--scrim-strong); }
}
.modal-head { display: flex; align-items: flex-start; gap: 12px; padding: 16px; border-bottom: 1px solid var(--t9-border); }
.modal-head h3 { margin: 0; font-size: var(--t9-fs-base); line-height: var(--t9-lh-base); font-weight: var(--t9-fw-semibold); flex: 1; color: var(--t9-text); }
.modal-head p { margin: 2px 0 0; font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); }
.modal-close {
  width: 28px; height: 28px; border-radius: var(--t9-radius-md); border: 0; background: transparent;
  color: var(--t9-text-faint); cursor: pointer; display: grid; place-items: center; flex-shrink: 0;
}
.modal-close:hover { background: var(--t9-slate-100); color: var(--t9-text-muted); }
.modal-body { padding: 16px; }

/* ---------------------------- TOASTS ---------------------------- */
/* A surface card, not a coloured block. Colour carries the *kind* — on the icon
   and a 3px edge — while the text stays on the same background as every other
   panel in the console, so it is readable at the contrast the rest of the
   product is designed at. A saturated fill behind body copy is what made these
   look like a debug overlay. */
.toast {
  background: #fff; border: 1px solid var(--t9-border);
  border-left: 3px solid var(--t9-border-control);
  border-radius: var(--t9-radius-lg); box-shadow: var(--t9-shadow-lg);
  padding: 12px; display: flex; gap: 10px;
  align-items: flex-start; animation: toast-in 0.2s ease;
}
.toast.success { border-left-color: var(--good); }
.toast.error   { border-left-color: var(--critical); }
.toast.pending { border-left-color: var(--info); }
.toast.info    { border-left-color: var(--info); }
/* Wraps rather than truncating: a message worth interrupting someone for is
   worth showing in full. */
.toast .toast-title { overflow-wrap: anywhere; }
.toast .toast-close { margin-top: 1px; opacity: .6; transition: opacity 120ms ease; }
.toast .toast-close:hover { opacity: 1; }
@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.toast .toast-icon {
  width: 24px; height: 24px; border-radius: var(--radius-md); display: grid; place-items: center; flex-shrink: 0; margin-top: 1px;
}
.toast .toast-icon svg { width: 14px; height: 14px; }
.toast.pending .toast-icon { background: var(--info-soft); color: var(--info); }
.toast.success .toast-icon { background: var(--good-soft); color: var(--good); }
.toast.error .toast-icon { background: var(--critical-soft); color: var(--critical); }
.toast.info .toast-icon { background: var(--info-soft); color: var(--info); }
.toast .toast-body { flex: 1; min-width: 0; }
.toast .toast-title { font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); font-weight: var(--t9-fw-medium); color: var(--t9-text); }
.toast .toast-meta { font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-text-secondary); margin-top: 2px; }
.toast .toast-close { background: none; border: none; color: var(--faint); cursor: pointer; padding: 0; flex-shrink: 0; }
.toast .spinner {
  width: 13px; height: 13px; border-radius: var(--radius-full); border: 2px solid var(--info-soft); border-top-color: var(--info);
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .toast .spinner { animation: none; } }

/* ---------------------------- DETAIL VIEW ---------------------------- */
.detail-section { margin-bottom: var(--space-5); }
.detail-section:last-child { margin-bottom: 0; }
.detail-section-label {
  font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); text-transform: uppercase; letter-spacing: var(--t9-tracking-wide); font-weight: var(--t9-fw-semibold);
  color: var(--t9-text-secondary); margin-bottom: 8px;
}
.detail-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 16px; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-lg); padding: 16px; }
.detail-item { display: flex; flex-direction: column; gap: 2px; }
.detail-item .k { font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-text-secondary); font-weight: var(--t9-fw-regular); }
.detail-item .v { font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); color: var(--t9-text); font-weight: var(--t9-fw-regular); overflow-wrap: anywhere; }
.detail-item .v.mono { font-weight: var(--fw-regular); }
.detail-item .hint { font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-text-secondary); }
.category-chip {
  display: inline-flex; align-items: center; gap: 4px; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); padding: 2px 6px;
  border-radius: var(--t9-radius-sm); background: var(--t9-slate-100); border: 0;
  color: var(--t9-brand-700); margin: 0 8px 8px 0;
}

/* ================= ADMIN-ONLY: DASHBOARD WIDGET GRID ================= */
.dash-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
/* The common laptop range (1024-1400px) used to jump straight from 4 columns
   to 2 with nothing in between — every KPI widget was roughly twice as
   wide/tall as its content needed at exactly the width most people actually
   use this at. */
@media (max-width: 1400px) { .dash-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 1024px) { .dash-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 720px) { .dash-grid { grid-template-columns: 1fr; } }

/* Three chart panels, deliberately unequal (the donut's legend needs more
   room than a column strip or a ranked-bar list) — a fixed 3-up row down to
   tablet width, where it drops to the same 1-per-row every other dash-grid
   uses rather than fighting for space. */
.dash-grid-charts { grid-template-columns: 1.15fr 1fr 1fr; }
@media (max-width: 1400px) { .dash-grid-charts { grid-template-columns: 1.15fr 1fr 1fr; } }
@media (max-width: 1024px) { .dash-grid-charts { grid-template-columns: 1fr; } }

.widget { display: flex; flex-direction: column; min-height: 200px; }
.widget[data-goto] { cursor: pointer; }
.widget[data-goto]:hover { border-color: var(--accent); box-shadow: var(--shadow-md); }
/* Same affordance for cloud-gate.js's own delegated nav attributes
   (data-open-page/data-open-manage-users) — data-goto is dashboard.js's
   own Nutanix-only click handler (bound once at load, and gotoPage()
   only knows Nutanix page ids), so a cross-tenant panel like the
   Consolidated Dashboard's charts uses this pair instead, not data-goto. */
.widget[data-open-page], .widget[data-open-manage-users] { cursor: pointer; }
.widget[data-open-page]:hover, .widget[data-open-manage-users]:hover { border-color: var(--accent); box-shadow: var(--shadow-md); }

/* Insights panel — real, computed action items, not decoration. */
.insight-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; background: var(--hairline); border-radius: var(--radius, 8px); overflow: hidden; }
.insight-row {
  display: flex; align-items: center; gap: var(--space-3);
  background: var(--panel); padding: var(--space-3) var(--space-4);
  cursor: pointer; transition: background 120ms ease;
}
.insight-row:hover { background: var(--panel-raised); }
.insight-row .insight-icon { flex: none; width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; }
.insight-row .insight-icon svg { width: 16px; height: 16px; }
.insight-row.warn .insight-icon { background: var(--warn-soft); color: var(--warn); }
.insight-row.critical .insight-icon { background: var(--critical-soft); color: var(--critical); }
.insight-row.good .insight-icon { background: var(--good-soft); color: var(--good); }
.insight-row .insight-text { flex: 1; font-size: var(--fs-sm); }
.insight-row .insight-text b { font-weight: var(--fw-semibold); }
.insight-row .insight-arrow { color: var(--muted); flex: none; }
.card-stat-line { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--hairline); font-size: var(--fs-xs); color: var(--text-soft); }
.card-stat-line b { color: var(--text); font-size: var(--fs-sm); font-weight: var(--fw-semibold); }
.widget-body { padding: var(--space-4) var(--space-5); flex: 1; display: flex; flex-direction: column; gap: var(--space-2); }
.widget-empty {
  align-items: center; justify-content: center; text-align: center; gap: var(--space-3);
  color: var(--faint); padding: var(--space-5);
}
.widget-empty svg { opacity: 0.55; }
.widget-empty p { margin: 0; font-size: var(--fs-xs); line-height: var(--lh-relaxed); max-width: 32ch; }

.stat-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); font-size: var(--fs-sm); }
.stat-row .stat-name { font-weight: var(--fw-semibold); color: var(--text-soft); cursor: pointer; }
.stat-row .stat-name:hover { color: var(--accent); text-decoration: underline; }
.stat-row .stat-value { font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; color: var(--text); }
.stat-row-bar { display: flex; flex-direction: column; gap: 5px; }

.big-stat { display: flex; align-items: baseline; gap: 6px; }
.big-stat .n { font-size: var(--fs-2xl); font-weight: var(--fw-bold); letter-spacing: -0.025em; color: var(--text); }
.big-stat .u { font-size: var(--fs-xs); color: var(--muted); font-weight: var(--fw-medium); }
.severity-row { display: flex; gap: var(--space-4); margin-top: var(--space-1); }
.severity-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; flex: 1; }
.severity-cell .n { font-size: var(--fs-lg); font-weight: var(--fw-bold); }
.severity-cell .l { font-size: 10px; text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--muted); font-weight: var(--fw-semibold); }

/* Consolidated Dashboard (consolidated.js): Prism's main dashboard grid, one
   level up. dense packing lets the tall Quick Access card sit beside two rows
   of single cards instead of leaving a hole under it. */
.cx-grid { grid-auto-flow: row dense; margin-bottom: var(--space-5); }
/* min-width 0: without it the tasks table's width holds its column open and
   every card runs off the side of a phone. */
.cx-grid .widget { min-height: 0; min-width: 0; }
.cx-span-2 { grid-column: span 2; }
.cx-tall { grid-row: span 2; }
.cx-full { grid-column: 1 / -1; }
@media (max-width: 720px) { .cx-span-2 { grid-column: auto; } .cx-tall { grid-row: auto; } }
.widget-body.cx-flush { padding: 0; gap: 0; }
/* "IBM Power (AIX | Linux)" is the name, all of it: wrap onto a second line in
   the rail rather than cut it off beside its badge (the kit truncates). */
.sidebar__row-label .truncate { white-space: normal; overflow: visible; }
.sidebar__row .badge { flex: none; }
/* A panel's heading (sidebar.js renderPanel). */
.sidebar__conn-name .i { vertical-align: -2px; color: var(--t9-text-faint); }
/* The profile button and its menu: Settings, Platform configuration, Sign out. */
.sidebar__footer { position: relative; }
.sidebar__whoBtn { width: 100%; padding: 8px 12px; border: 0; border-radius: var(--t9-radius-md); background: none; font: inherit; text-align: left; cursor: pointer; }
.sidebar__whoBtn:hover, .sidebar__whoBtn[aria-expanded="true"] { background: var(--t9-slate-50); }
.sidebar__whoBtn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.sidebar__whoBtn .sidebar__who-text { display: flex; flex-direction: column; flex: 1; }
.sidebar__whoChev { flex: none; color: var(--t9-text-faint); transition: transform .15s ease; }
.sidebar__whoBtn[aria-expanded="true"] .sidebar__whoChev { transform: rotate(180deg); }
.profile-menu { position: absolute; left: 12px; right: 12px; bottom: calc(100% - 6px); z-index: 30; padding: 6px; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-lg); background: #fff; box-shadow: var(--t9-shadow-xl); }
.profile-menu__item { display: flex; width: 100%; align-items: center; gap: 10px; padding: 8px 10px; border: 0; border-radius: var(--t9-radius-md); background: none; font: inherit; font-size: var(--t9-fs-sm); color: var(--t9-text-muted); text-align: left; cursor: pointer; }
.profile-menu__item .i { color: var(--t9-text-faint); }
.profile-menu__item:hover, .profile-menu__item:focus-visible { background: var(--t9-slate-50); color: var(--t9-text); outline: none; }
.profile-menu__sep { height: 1px; margin: 4px 0; background: var(--t9-border); }
@media (prefers-reduced-motion: reduce) { .sidebar__whoChev { transition: none; } }
@media (min-width: 721px) { .sidebar-collapsed .sidebar:not(:hover):not(:focus-within) .sidebar__whoChev { display: none; } }
/* A cloud that isn't connected: its name and mark, greyed out. */
.sidebar__row.sidebar__row--off { color: var(--t9-text-faint) !important; }
.sidebar__row.sidebar__row--off .i-brand { filter: grayscale(1); opacity: .45; }
.nowrap { white-space: nowrap; }

/* Each account's share under a card's headline figure. */
.cx-lines { display: flex; flex-direction: column; gap: var(--space-3); margin-top: var(--space-2); padding-top: var(--space-3); border-top: 1px solid var(--hairline); }
.cx-lines-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-2) var(--space-5); }
.cx-line { display: flex; flex-direction: column; gap: 4px; }
.cx-line .stat-row { font-size: var(--t9-fs-xs); flex-wrap: wrap; row-gap: 2px; }
.cx-line .stat-row > * { white-space: nowrap; }
.cx-account { font-weight: var(--fw-semibold); color: var(--text-soft); font-size: var(--t9-fs-xs); text-align: left; }
.cx-note { white-space: normal !important; }
.cx-line .bar-track { height: 6px; }
.cx-detail { margin: 0; }
.cx-footnote { margin: 0; font-size: 11px; }
.cx-split { display: flex; }
.cx-split > div { height: 100%; }
.cx-pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.cx-pair .big-stat .n { font-size: var(--fs-lg); }

/* Alerts: severity counts beside a 24-hour stacked column chart. */
.cx-alerts { display: flex; gap: var(--space-5); align-items: stretch; flex-wrap: wrap; }
.cx-severity { flex: 0 0 auto; min-width: 200px; align-items: center; margin: 0; }
.cx-severity .n { font-size: var(--fs-2xl); font-variant-numeric: tabular-nums; }
.cx-hist-wrap { flex: 1 1 260px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cx-hist { display: flex; align-items: flex-end; gap: 2px; height: 72px; border-bottom: 1px solid var(--hairline); }
.cx-hist-col { flex: 1; height: 100%; display: flex; flex-direction: column-reverse; min-width: 0; }
.cx-hist-col span { display: block; width: 100%; min-height: 2px; }
.cx-hist-col span:last-child { border-radius: 2px 2px 0 0; }
.cx-hist-axis { display: flex; justify-content: space-between; font-size: 10px; color: var(--muted); }

/* Cloud Quick Access: one row per account, grouped as the rail groups them. */
.cx-access-group { padding: var(--space-3) var(--space-4) var(--space-1); font-size: 10px; font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--muted); }
.cx-access-list { list-style: none; margin: 0; padding: 0; }
.cx-access-row { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-top: 1px solid var(--hairline); }
.cx-access-icon { flex: none; width: 32px; height: 32px; border-radius: 8px; display: grid; place-items: center; background: var(--t9-slate-100); color: var(--t9-brand-700); }
.cx-access-icon svg { width: 17px; height: 17px; }
.cx-access-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.cx-access-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.cx-access-name { font-weight: var(--fw-semibold); color: var(--t9-text); font-size: var(--t9-fs-sm); }
.cx-access-side { flex: none; align-self: center; }
.btn.cx-btn { height: 26px; padding: 0 10px; font-size: var(--t9-fs-xs); gap: 4px; }
.btn.cx-btn .i { width: 12px; height: 12px; }

/* Security: each figure opens the page where it can be dealt with. */
.cx-sec { display: flex; flex-direction: column; margin-top: auto; border-top: 1px solid var(--hairline); }
.cx-sec-row { display: flex; justify-content: space-between; align-items: center; padding: 7px 0; background: none; border: 0; border-bottom: 1px solid var(--hairline); font: inherit; font-size: var(--t9-fs-xs); color: var(--text-soft); cursor: pointer; text-align: left; }
.cx-sec-row:last-child { border-bottom: 0; }
.cx-sec-row:hover span:first-child { color: var(--accent); text-decoration: underline; }
.cx-sec-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.cx-bad { color: var(--critical); }

.cx-tasks-table td.cx-task-text { max-width: 0; width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cx-tasks-table tr.cx-click { cursor: pointer; }
/* Settings → Cloud Accounts (cloud-accounts.js): one panel per cloud. */
.ca-list { display: flex; flex-direction: column; gap: var(--space-4); }
.ca-card .panel-head { gap: 10px; }
.ca-mark { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 8px; background: var(--t9-slate-100); }
.ca-mark .i { width: 20px; height: 20px; }
.ca-table td.ca-actions { text-align: right; white-space: nowrap; }
.ca-actions-row { display: inline-flex; gap: 4px; }
.ca-table td.ca-actions .btn-icon { width: 30px; height: 30px; }
/* Business figures (customers-ui.js): six tiles, the customer table, and a
   customer's page. */
.bz-kpis { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--space-3); }
@media (max-width: 1400px) { .bz-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 720px) { .bz-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
#customers-kpis .bz-kpis, #customer-body > .bz-kpis { margin-bottom: var(--space-4); }
.bz-tile { position: relative; display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--hairline); border-radius: var(--t9-radius-lg); background: var(--panel); }
.bz-tile--bad { border-color: var(--t9-red-200, #fecaca); background: var(--t9-red-50, #fef2f2); }
.bz-tile--warn { border-color: var(--t9-amber-200, #fde68a); background: var(--t9-amber-50, #fffbeb); }
.bz-label { font-size: 11px; font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--muted); }
.bz-value { font-size: var(--fs-xl, 1.5rem); font-weight: var(--fw-bold); letter-spacing: -0.02em; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bz-value small { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--muted); }
.bz-sub { font-size: var(--t9-fs-xs); color: var(--text-soft); }
.bz-trend { margin-top: 4px; color: var(--t9-brand-500); }
.bz-spark { width: 96px; height: 28px; display: block; }
.bz-trend-note { font-size: 10px; color: var(--muted); }
.bz-bad { color: var(--critical); }
.bz-table td { vertical-align: middle; }
.bz-table td.num, .bz-table td.bz-name, .bz-table .bz-name { white-space: nowrap; }
.bz-table .bz-name { font-weight: var(--fw-semibold); color: var(--t9-text); }
.bz-table .bz-id { display: block; font-size: 11px; }
.bz-row { cursor: pointer; }
.bz-row:hover td { background: var(--t9-slate-50); }
.bz-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.bz-quota { display: flex; align-items: center; gap: 6px; min-width: 110px; }
.bz-quota .bar-track { flex: 1; height: 6px; }
.bz-quota span { font-size: var(--t9-fs-xs); color: var(--text-soft); font-variant-numeric: tabular-nums; }
.bz-panel { margin-top: var(--space-4); }
.bz-panel .panel-head { flex-wrap: wrap; gap: var(--space-2); }
.bz-search { height: 32px; padding: 0 10px; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-md, 6px); font: inherit; font-size: var(--t9-fs-sm); min-width: 220px; }
.bz-check { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t9-fs-sm); color: var(--text-soft); }
.bz-cols { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: var(--space-4); margin-bottom: var(--space-4); align-items: start; }
@media (max-width: 1100px) { .bz-cols { grid-template-columns: 1fr; } }
.bz-side { display: flex; flex-direction: column; gap: var(--space-4); }
.bz-recs { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 8px; font-size: var(--t9-fs-sm); color: var(--text-soft); }
.bz-h3 { margin: var(--space-4) 0 var(--space-2); font-size: var(--t9-fs-sm); font-weight: var(--fw-semibold); color: var(--t9-text); }
.bz-links { list-style: none; margin: var(--space-3) 0; padding: 0; border: 1px solid var(--hairline); border-radius: var(--t9-radius-lg); max-height: 320px; overflow-y: auto; }
#customer-modules .bz-links { max-height: none; }
.bz-links li + li { border-top: 1px solid var(--hairline); }
.bz-links label { display: flex; align-items: center; gap: 10px; padding: 8px 12px; cursor: pointer; font-size: var(--t9-fs-sm); }
.bz-links label .bz-name { white-space: nowrap; }
.bz-links label .sub { margin-left: auto; text-align: right; }
.bz-links label.is-taken { cursor: not-allowed; opacity: .6; }
.bz-actions { display: flex; justify-content: flex-end; }
/* Access control (access-ui.js). */
.is-locked { opacity: .5; cursor: not-allowed !important; }
.access-tabs { margin-bottom: var(--space-3); }
.access-switch .widget-body > p { margin: 0 0 var(--space-2); }
.access-points { margin: 0 0 var(--space-3); padding-left: 18px; display: flex; flex-direction: column; gap: 4px; font-size: var(--t9-fs-sm); color: var(--text-soft); }
.access-policy-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.access-policy-list li { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: var(--t9-fs-sm); }
.access-select { height: 32px; padding: 0 8px; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-md, 6px); background: #fff; font: inherit; font-size: var(--t9-fs-sm); max-width: 100%; }
.access-add { display: flex; gap: var(--space-2); margin-top: var(--space-3); flex-wrap: wrap; }
.access-roles { display: flex; flex-wrap: wrap; gap: 4px; }
.access-policies { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--space-3); padding: var(--space-4); }
.access-policy { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3) var(--space-4); border: 1px solid var(--hairline); border-radius: var(--t9-radius-lg); }
.access-policy__head { display: flex; align-items: center; gap: 6px; }
.access-policy p { margin: 0; }
.access-policy__actions { display: flex; gap: 6px; margin-top: auto; }
.modal.access-policy-modal { max-width: 720px; }
/* Every module in view at once: the page scrolls, not a box inside the dialog. */
#access-policy-grid.table-wrap { max-height: none; }
.access-policy-fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); margin-bottom: var(--space-3); }
.access-policy-fields label { display: flex; flex-direction: column; gap: 4px; font-size: var(--t9-fs-sm); color: var(--text-soft); }
.access-policy-fields input { height: 34px; padding: 0 10px; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-md, 6px); font: inherit; }
@media (max-width: 560px) { .access-policy-fields { grid-template-columns: 1fr; } }
.access-grid { width: 100%; border-collapse: collapse; font-size: var(--t9-fs-sm); }
.access-grid th { text-align: center; font-weight: var(--fw-semibold); color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: var(--ls-wide); padding: 6px; }
.access-grid th:first-child, .access-grid td:first-child { text-align: left; }
.access-grid td { padding: 6px; border-top: 1px solid var(--hairline); text-align: center; }
.access-grid input[type="radio"] { width: 16px; height: 16px; accent-color: var(--t9-primary, #455a64); cursor: pointer; }
.access-grid__group td { padding-top: 12px; font-size: 11px; font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--muted); border-top: 0; }
.access-grid__na { color: var(--t9-text-faint); }
.cx-section-title { margin: var(--space-5) 0 var(--space-3); font-size: var(--t9-fs-base); font-weight: var(--t9-fw-semibold); color: var(--t9-text); }

/* A card's headline figure beside its gauge (Storage, Memory, CPU). */
.cx-gauge-row { display: flex; align-items: center; gap: var(--space-3); }
.cx-gauge { flex: none; width: 64px; height: 36px; }
/* Chart.js needs a sized box when maintainAspectRatio is off. */
.cx-chart { position: relative; width: 100%; min-width: 0; }
.cx-chart--vms { height: 112px; }
.cx-chart--spend { height: 150px; }
.cx-budgets { display: flex; flex-direction: column; gap: var(--space-2); }
.cx-sec--clouds { margin-top: var(--space-3); border-top: 0; }
.cx-sec-head { padding: 4px 0; font-size: 10px; font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--muted); border-bottom: 1px solid var(--hairline); }

/* Customize (consolidated.js): hidden cards and sections, and the dialog. */
.cx-off { display: none !important; }
.cx-grid .panel-head { cursor: grab; }
.modal.cx-customize { max-width: 620px; }
.cx-cust-group { margin: var(--space-3) 0 var(--space-1); font-size: 10px; font-weight: var(--fw-semibold); text-transform: uppercase; letter-spacing: var(--ls-wide); color: var(--muted); }
.cx-cust-group:first-child { margin-top: 0; }
.cx-cust-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--hairline); border-radius: var(--t9-radius-lg); }
.cx-cust-row { display: flex; align-items: center; gap: var(--space-2); padding: 6px var(--space-3); border-bottom: 1px solid var(--hairline); background: var(--panel, #fff); }
.cx-cust-row:first-child { border-radius: var(--t9-radius-lg) var(--t9-radius-lg) 0 0; }
.cx-cust-row:last-child { border-bottom: 0; border-radius: 0 0 var(--t9-radius-lg) var(--t9-radius-lg); }
.cx-cust-row.is-off .cx-cust-name { color: var(--muted); }
.cx-cust-row.dragging { opacity: .45; }
.cx-cust-row.drag-over { outline: 2px dashed var(--accent); outline-offset: -2px; }
.cx-cust-grip { display: grid; place-items: center; color: var(--muted); cursor: grab; }
.cx-cust-name { flex: 1; min-width: 0; font-size: var(--t9-fs-sm); font-weight: var(--fw-medium); color: var(--text-soft); }
.btn.cx-cust-size { min-width: 64px; justify-content: center; }
span.cx-cust-size { min-width: 64px; text-align: center; font-size: var(--t9-fs-xs); }
.btn.btn-icon.cx-cust-move { width: 26px; height: 26px; }
.btn.btn-icon.cx-cust-move .i { width: 14px; height: 14px; }
.cx-cust-foot { display: flex; justify-content: space-between; gap: var(--space-2); padding: 12px 16px; border-top: 1px solid var(--t9-border); }
@media (max-width: 480px) { .btn.cx-cust-size, span.cx-cust-size { display: none; } }

/* Was an inline style on the widget itself (flex-direction:row), which meant
   no media query could ever touch it without !important — moved here so the
   narrow-width rule below can override it normally. */
#w-top-consumers { display: flex; flex-direction: row; gap: 18px; }
@media (max-width: 900px) {
  /* Three columns side by side left rank/name/value crowding each other once
     the widget itself was down to ~250-300px (a 2-column .dash-grid on a
     narrow phone) — stacked, each column keeps its own full width instead. */
  #w-top-consumers { flex-direction: column; gap: var(--space-4); }
}
.tc-col { flex: 1; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.tc-col h4 { margin: 0 0 2px; font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--ls-wider); color: var(--faint); font-weight: var(--fw-semibold); }
.tc-row { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-sm); }
.tc-rank { width: 15px; flex-shrink: 0; color: var(--faint); font-weight: var(--fw-semibold); font-size: var(--fs-xs); }
.tc-name {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  cursor: pointer; font-weight: var(--fw-medium); color: var(--text-soft);
}
.tc-name:hover { color: var(--accent); text-decoration: underline; }
.tc-value { font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; flex-shrink: 0; color: var(--text); }

/* ---------------------------- HEALTH SCORE ---------------------------- */
.health-gauge { display: flex; align-items: center; gap: var(--space-4); }
.health-ring {
  width: 64px; height: 64px; border-radius: var(--radius-full); display: grid; place-items: center; flex-shrink: 0;
  font-size: var(--fs-lg); font-weight: var(--fw-bold);
}
.health-ring.good { background: var(--good-soft); color: var(--good); border: 3px solid var(--good); }
.health-ring.warn { background: var(--warn-soft); color: var(--warn); border: 3px solid var(--warn); }
.health-ring.critical { background: var(--critical-soft); color: var(--critical); border: 3px solid var(--critical); }
.health-label { font-size: var(--fs-sm); font-weight: var(--fw-semibold); color: var(--text); }
.health-factors { margin-top: 2px; font-size: var(--fs-xs); color: var(--muted); line-height: var(--lh-relaxed); }
.health-factors b { color: var(--text-soft); font-weight: var(--fw-semibold); }

/* ---------------------------- ALLOCATION / DISTRIBUTION ---------------------------- */
.alloc-row { display: flex; justify-content: space-between; align-items: baseline; font-size: var(--fs-sm); padding: 3px 0; }
.alloc-row .l { color: var(--muted); font-weight: var(--fw-medium); }
.alloc-row .v { font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; color: var(--text); }
.dist-legend { display: flex; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-2); font-size: var(--fs-xs); color: var(--text-soft); }
.dist-legend span { display: inline-flex; align-items: center; gap: 5px; }
.dist-dot { width: 8px; height: 8px; border-radius: var(--radius-full); display: inline-block; }

/* ---------------------------- DASHBOARD TOOLBAR ---------------------------- */
.dash-toolbar { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* Segmented control (data density) — same visual weight as .btn so the
   toolbar reads as one row of controls. */
.segmented { display: inline-flex; gap: 4px; padding: 4px; border-radius: var(--t9-radius-md); background: var(--t9-slate-100); width: fit-content; }
.segmented button {
  border: none; background: transparent; color: var(--t9-text-muted); padding: 4px 10px; border-radius: var(--t9-radius-sm);
  cursor: pointer; font: inherit; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); font-weight: var(--t9-fw-medium); white-space: nowrap;
}
.segmented button:hover { color: var(--t9-text); }
.segmented button.active { background: #fff; color: var(--t9-text); box-shadow: var(--t9-shadow-sm); }

/* ---------------------------- PER-WIDGET RANGE SELECT ---------------------------- */
.range-select {
  background: var(--panel-raised); border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm);
  color: var(--text-soft); font-size: var(--fs-xs); font-weight: var(--fw-medium); padding: 3px 6px; cursor: pointer;
}
.range-select:focus { border-color: var(--input-focus-border); outline: none; }

/* ---------------------------- NOTIFICATION BELL ---------------------------- */
.notif-wrap { position: relative; }
.notif-dropdown {
  /* #toast-host learned this lesson already (min(380px, calc(100vw - 32px)))
     — a fixed 330px sitting flush against the right edge of a narrow phone
     topbar has nothing stopping it running past the left edge of the screen
     too. */
  display: none; position: absolute; top: calc(100% + 8px); right: 0; width: min(330px, calc(100vw - 24px));
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid var(--hairline); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg); z-index: 150; overflow: hidden;
  transform-origin: top right;
  animation: menu-grow 160ms cubic-bezier(.2,.7,.3,1);
}
.notif-dropdown.open { display: block; }
@media (prefers-reduced-transparency: reduce) {
  .notif-dropdown { background: var(--panel); backdrop-filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .notif-dropdown { animation: rise 1ms linear; }
}
.notif-head { padding: var(--space-3) var(--space-4); font-size: var(--fs-sm); font-weight: var(--fw-semibold); border-bottom: 1px solid var(--hairline); color: var(--text); }
.notif-dropdown .feed { max-height: 320px; overflow-y: auto; }
.notif-viewall {
  width: 100%; padding: var(--space-3); border: none; border-top: 1px solid var(--hairline); background: var(--panel-raised);
  color: var(--accent); font-weight: var(--fw-semibold); font-size: var(--fs-sm); cursor: pointer;
}
.notif-viewall:hover { background: var(--accent-soft); color: var(--accent-soft-text); }

/* ---------------------------- WIDGET DRAG & DROP ---------------------------- */
.panel-head { cursor: grab; }
.panel-head select, .panel-head button { cursor: pointer; }
.widget.dragging { opacity: 0.4; }
.widget.drag-over { outline: 2px dashed var(--accent); outline-offset: 2px; }
.widget.widget-hidden { display: none !important; }

/* ---------------------------- WIDGET PICKER ---------------------------- */
.widget-picker-list { display: flex; flex-direction: column; gap: 2px; max-height: 50vh; overflow-y: auto; }
.widget-picker-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-2) var(--space-1); border-bottom: 1px solid var(--border-subtle); font-size: var(--fs-sm);
  font-weight: var(--fw-medium); color: var(--text-soft);
}
.widget-picker-row:last-child { border-bottom: none; }
.wp-toggle {
  position: relative; width: 36px; height: 20px; border-radius: var(--t9-radius-full); border: none;
  background: var(--t9-slate-300); cursor: pointer; flex-shrink: 0;
}
.wp-toggle::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: var(--radius-full); background: var(--color-white); transition: transform 0.15s ease;
}
.wp-toggle.on { background: var(--t9-primary); }
.wp-toggle.on::after { transform: translateX(16px); }
/* The same switch around a real checkbox (Sync Policy's per-connection
   toggle): the input covers the track, invisibly, and its state drives it. */
label.wp-toggle { display: inline-block; vertical-align: middle; }
label.wp-toggle input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
label.wp-toggle:has(input:checked) { background: var(--t9-primary); }
label.wp-toggle:has(input:checked)::after { transform: translateX(16px); }
label.wp-toggle:has(input:focus-visible) { box-shadow: var(--t9-ring-focus); }
label.wp-toggle:has(input:disabled) { opacity: .5; cursor: not-allowed; }
@media (prefers-reduced-motion: reduce) { .wp-toggle::after { transition: none; } }

/* ---------------------------- DATA DENSITY ---------------------------- */
.dash-grid.density-compact { gap: var(--space-2); }
.dash-grid.density-compact .widget { min-height: 0; }
.dash-grid.density-compact .panel-head { padding: var(--space-2) var(--space-3); }
.dash-grid.density-compact .widget-body { padding: var(--space-2) var(--space-3); gap: 5px; }
.dash-grid.density-compact .panel-head h2 { font-size: var(--fs-sm); }
.dash-grid.density-compact .big-stat .n { font-size: var(--fs-lg); }
.dash-grid.density-compact .health-ring { width: 48px; height: 48px; font-size: var(--fs-base); }

/* ---------------------------- DASHBOARD PROFILES ---------------------------- */
.dash-select-wrap { position: relative; }
.dash-profile-menu {
  display: none; position: absolute; top: calc(100% + 6px); left: 0; min-width: 210px;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid var(--hairline); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); z-index: 150; overflow: hidden;
  transform-origin: top left;
  animation: menu-grow 140ms cubic-bezier(.2,.7,.3,1);
}
.dash-profile-menu.open { display: block; }
@media (prefers-reduced-transparency: reduce) {
  .dash-profile-menu { background: var(--panel); backdrop-filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .dash-profile-menu { animation: rise 1ms linear; }
}
.dash-profile-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
  padding: var(--space-2) var(--space-3); font-size: var(--fs-sm); cursor: pointer; border-bottom: 1px solid var(--border-subtle);
  color: var(--text-soft);
}
.dash-profile-row:last-child { border-bottom: none; }
.dash-profile-row:hover { background: var(--panel-raised); }
.dash-profile-row.active { color: var(--accent-strong); font-weight: var(--fw-semibold); }
.dash-profile-row .dp-delete { color: var(--faint); font-size: var(--fs-xs); padding: 2px 6px; border-radius: var(--radius-sm); }
.dash-profile-row .dp-delete:hover { color: var(--critical); background: var(--critical-soft); }
.dash-profile-new {
  width: 100%; padding: var(--space-2) var(--space-3); border: none; background: var(--panel-raised); color: var(--accent);
  font-weight: var(--fw-semibold); font-size: var(--fs-sm); cursor: pointer;
}
.dash-profile-new:hover { background: var(--accent-soft); color: var(--accent-soft-text); }
.btn[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-soft-text); }

/* ---------------------------- SPARKLINE ---------------------------- */
.mini-spark { display: block; width: 64px; height: 20px; flex-shrink: 0; }

/* ── Metering & billing pages ────────────────────────────────────────────
   Added for Promotions, Invoices, Cost Insights and Collector Health. Every
   value comes from the token layer — no raw hex, per the engineering standard. */

.note-inline {
  margin: 0 var(--space-5) var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--color-tech-blue);
  border-radius: var(--radius);
  background: var(--panel-raised);
  font-size: var(--fs-sm);
  color: var(--muted);
}
.note-inline strong { color: var(--text); }
.note-inline.warn {
  border-left-color: var(--color-warning);
  color: var(--text);
}
.note-inline.error {
  border-left-color: var(--color-danger);
  color: var(--text);
}

.panel-foot {
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--hairline);
  font-size: var(--fs-sm);
  color: var(--muted);
}
.panel-foot strong { color: var(--text); }

/* A row that is present but not contributing — a discount line, a zeroed
   add-on. Dimmed rather than hidden, because "why is this zero" is a question
   people ask. */
tbody tr.off td { color: var(--muted); }

/* ── Narrow viewports ────────────────────────────────────────────────────
   The rail is a permanent 76px icon column by default now (see "Icon-rail
   categories" above), so there is no separate collapse step to make here —
   only the canvas gets a little breathing room back at this width. */
@media (max-width: 1100px) {
  .sync-age { display: none; }
}

@media (max-width: 720px) {
  .kpi-grid { grid-template-columns: 1fr 1fr; }
  .grid-2 { grid-template-columns: 1fr; }
}

/* ── Footer ──────────────────────────────────────────────────────────── */
.footer-note {
  color: var(--muted);
  font-size: var(--fs-xs);
}


/* ── Links inside tables ─────────────────────────────────────────────────
   Rows used to be dead ends: a tenant, a VM or an invoice was text you then
   had to go and find yourself. */
.linky {
  color: var(--t9-link); text-decoration: none; font-weight: var(--t9-fw-medium);
}
.linky:hover { text-decoration: underline; }
.linky:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* ── Toasts ──────────────────────────────────────────────────────────────
   alert() blocked the page and could only say one thing at a time. Sits
   above even a blocking modal (650) on purpose: a toast is transient system
   feedback ("saved", "failed") that should still reach you regardless of
   what dialog you're in the middle of. */
#toast-host, .toast-stack {
  position: fixed; right: var(--space-5); bottom: var(--space-5); z-index: 700;
  display: flex; flex-direction: column; gap: var(--space-2);
  width: min(380px, calc(100vw - 32px));
  /* The stack is only ever a few cards tall; the container must not swallow
     clicks on the page behind it. */
  pointer-events: none;
}
#toast-host > *, .toast-stack > * { pointer-events: auto; }
/* There is one toast skin, defined with .toast above, and two things that
   raise them: this simple host, and the action tracker's #toast-stack. They
   used to have separate rules that both matched .toast, and the later one —
   a solid red fill — won on cascade order, so an action toast rendered as a
   red block with a dark navy title sitting unreadably on top of it. */
.toast.leaving { opacity: 0; transform: translateY(4px); transition: 180ms ease-in; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }

/* ── Form dialog ─────────────────────────────────────────────────────────
   Replaces prompt() chains. Fields are shown together because four answers
   combine into one irreversible action, and you should see them as a set
   before committing. Same tier as .modal-overlay (650) — both are "the one
   blocking surface", so neither should ever be able to render under a
   dropdown, a sidebar flyout, or the other. */
.form-dialog-overlay {
  position: fixed; inset: 0; z-index: 650;
  background: var(--scrim);
  display: grid; place-items: center; padding: var(--space-4);
}
.form-dialog {
  background: #fff; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-xl);
  width: min(520px, 100%); max-height: min(86vh, 760px);
  display: flex; flex-direction: column; box-shadow: var(--t9-shadow-2xl);
}
.fd-head { padding: 16px; border-bottom: 1px solid var(--t9-border); }
.fd-head h3 { margin: 0; font-size: var(--t9-fs-base); line-height: var(--t9-lh-base); font-weight: var(--t9-fw-semibold); color: var(--t9-text); }
.fd-head p { margin: 4px 0 0; color: var(--t9-text-muted); font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); }

.fd-body { padding: 16px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.fd-field { display: flex; flex-direction: column; gap: 4px; }
.fd-field > span { font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); font-weight: var(--t9-fw-medium); color: var(--t9-text-muted); }
.fd-field .req { font-weight: var(--t9-fw-medium); color: var(--t9-text-secondary); font-size: var(--t9-fs-11); }
.fd-field input[type="text"], .fd-field input[type="number"], .fd-field input[type="date"], .fd-field input[type="month"], .fd-field input[type="password"], .fd-field input[type="email"], .fd-field select {
  font: inherit; font-size: var(--t9-fs-sm); color: var(--t9-text); background: #fff;
  border: 1px solid var(--t9-border-control); border-radius: var(--t9-radius-md);
  height: var(--t9-control-h); padding: 0 10px; width: 100%;
}
.fd-field input:focus-visible, .fd-field select:focus-visible, .fd-field input:focus, .fd-field select:focus {
  outline: none; border-color: var(--t9-focus); box-shadow: var(--t9-ring-focus);
}
.fd-field em { font-style: normal; font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); line-height: var(--t9-lh-xs); }
.fd-check { flex-direction: row; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.fd-check input { width: 17px; height: 17px; accent-color: var(--accent); }
.fd-check em { flex-basis: 100%; }

.fd-error {
  background: var(--t9-red-50); color: var(--t9-red-700);
  border: 1px solid var(--t9-red-200); border-radius: var(--t9-radius-md);
  padding: 6px 10px; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs);
}
.fd-foot {
  padding: 16px; border-top: 1px solid var(--t9-border);
  display: flex; justify-content: flex-end; gap: 8px;
}

/* ── Search ──────────────────────────────────────────────────────────── */
.search-result-row.sel { background: var(--accent-soft); }

/* Freshness, stated rather than implied. A spinner says "we are busy"; this
   says "what you are looking at is current", which is the question an operator
   actually has. */
.sync-age {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: var(--radius-full); cursor: default;
}
.sync-age::before {
  content: ""; width: 8px; height: 8px; border-radius: var(--radius-full);
  background: var(--good); flex-shrink: 0;
}
.sync-age.is-off::before { background: var(--t9-slate-400); }
.sync-age:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The words, as a tooltip under the dot. */
.sync-age__text {
  position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  padding: 4px 8px; border-radius: 6px; background: var(--t9-slate-900); color: #fff;
  font-size: var(--fs-xs); white-space: nowrap; box-shadow: var(--t9-shadow-md, 0 4px 12px rgba(0,0,0,.15));
  opacity: 0; pointer-events: none; transition: opacity .12s ease; z-index: 700;
}
.sync-age:hover .sync-age__text, .sync-age:focus-visible .sync-age__text { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .sync-age__text { transition: none; } }
@media (max-width: 900px) { .sync-age { display: none; } }

/* Filter controls sit in the table toolbar rather than above the panel, so the
   count beside them updates in the same glance. */
.filter-field { display: flex; align-items: center; }
.filter-field input[type="search"] {
  font: inherit; font-size: var(--t9-fs-sm); color: var(--t9-text);
  background: #fff; border: 1px solid var(--t9-border-control);
  border-radius: var(--t9-radius-md); height: var(--t9-control-h); padding: 0 10px;
  min-width: 220px;
}
.filter-field input:focus-visible, .filter-field input:focus { outline: none; border-color: var(--t9-focus); box-shadow: var(--t9-ring-focus); }
@media (max-width: 720px) { .filter-field input[type="search"] { min-width: 140px; } }

/* ── Skeletons ───────────────────────────────────────────────────────────
   "Loading…" as bare text makes a page look broken for the second it is there.
   Shaped placeholders read as content arriving. */
.skeleton-block { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-4) var(--space-5); }
.skeleton-row span {
  display: block; height: 12px; border-radius: var(--radius-full);
  background: linear-gradient(90deg, var(--panel-raised) 25%, var(--hairline) 37%, var(--panel-raised) 63%);
  background-size: 400% 100%;
  animation: skeleton-sweep 1.4s ease-in-out infinite;
}
@keyframes skeleton-sweep { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) {
  .skeleton-row span { animation: none; background: var(--panel-raised); }
}

/* A quieter button for utilities that sit beside a heading. */
.btn-quiet {
  border-color: transparent; background: transparent; color: var(--t9-text-muted); font-weight: var(--t9-fw-regular);
  font-size: var(--t9-fs-xs); min-height: 28px; padding: 0 8px;
}
.btn-quiet:hover { color: var(--t9-text); background: var(--t9-slate-100); border-color: transparent; }

.back-link { display: inline-flex; align-items: center; gap: 4px; margin-bottom: 8px; font-size: var(--t9-fs-sm); color: var(--t9-link); border: 0; background: none; padding: 0; min-height: 0; }
.back-link:hover { background: none; color: var(--t9-link); text-decoration: underline; }

/* The version you are looking at, in a list of versions. */
tr.row-selected td { background: var(--accent-soft); }
tr.row-selected td:first-child { box-shadow: inset 3px 0 0 var(--accent); }

/* ── Service codes ────────────────────────────────────────────────────────
   A service is "Per vCPU", not "compute.vcpu". The code is an internal
   identifier and printing it under every row is noise on a page whose job is
   to show prices.

   It stays in the DOM rather than being removed, because two things read the
   text of these tables and would quietly lose the ability to find anything by
   code: the filter box above every table, and the CSV export. Hiding it
   visually keeps both working. It is also on the row's title, so hovering
   still answers "what is this called in the API". */
.code-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


/* ── Icon-only chrome ─────────────────────────────────────────────────────
   Seventeen pages carried a labelled "Refresh" button beside their real
   actions, all the same width, all competing for the same attention as the
   thing that actually changes something. Auto-update is on by default, so the
   button is a fallback: it keeps its place and loses its voice. */
.btn.btn-icon, button.btn-icon {
  padding: 0; width: var(--t9-control-h); height: var(--t9-control-h); min-height: 0; display: grid; place-items: center; flex: none;
  border: 1px solid var(--t9-border-control); background: #fff; color: var(--t9-text-secondary); border-radius: var(--t9-radius-md);
}
.btn-icon:hover { background: var(--t9-slate-50); color: var(--t9-text); }
.btn-icon svg { width: 14px; height: 14px; }
.btn-icon:active svg { transform: rotate(180deg); transition: transform .3s ease; }



/* ═══════════════ COMPUTE LIST ═══════════════
   The table did not fit, for two reasons that compounded: the uuid was printed
   twice — once under the name and once in its own column, thirty-six monospace
   characters wrapping to four lines — and every row carried five action buttons.
   Both are gone. The uuid lives on the row as data and on the detail panel; the
   actions live behind one control, or on a selection. */

.toolbar-right { display: flex; align-items: center; gap: var(--space-2); margin-left: auto; }

.select-field { display: inline-flex; align-items: center; gap: var(--space-2); }
.select-field > span { font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); font-weight: var(--t9-fw-medium); }
.select-field select {
  font: inherit; font-size: var(--t9-fs-xs); font-weight: var(--t9-fw-regular);
  color: var(--t9-text); background: #fff; cursor: pointer;
  border: 1px solid var(--t9-border-control); border-radius: var(--t9-radius-md);
  height: 30px; padding: 0 8px; min-width: 104px;
}
.select-field select:focus { outline: none; border-color: var(--t9-focus); box-shadow: var(--t9-ring-focus); }

/* Column views. Fewer columns at a time beats a horizontal scrollbar: a column
   you have to scroll to is one you will not read. */
.table-select .col-capacity { display: none; }
.table-select.view-general .col-general { display: table-cell; }
.table-select.view-capacity .col-capacity { display: table-cell; }
.table-select.view-capacity .col-general { display: none; }
/* Both column groups at once — the default now, so General and Capacity no
   longer have to be switched between to see one VM's full picture.
   table-wrap already scrolls horizontally (see its overflow-x rule) for
   whatever this doesn't fit at the current viewport width. */
.table-select.view-all .col-general,
.table-select.view-all .col-capacity { display: table-cell; }

/* Selection */
.col-check { width: 34px; padding-right: 0 !important; }
.col-check input { width: 15px; height: 15px; cursor: pointer; accent-color: var(--accent); }
.col-actions { width: 40px; text-align: right; }

/* Delete-lock — locked (the default) reads as muted/neutral so ninety
   ordinary rows don't look alarmed; unlocked is the one that should catch
   the eye, since it's the row now one click away from being deletable. */
.col-lock { width: 30px; padding-right: 0 !important; }
.lock-toggle {
  background: none; border: none; padding: 4px; border-radius: var(--radius-sm);
  color: var(--faint); cursor: pointer; display: grid; place-items: center;
}
.lock-toggle svg { width: 15px; height: 15px; }
.lock-toggle:hover { background: var(--panel-raised); color: var(--text-soft); }
.lock-toggle:not(.locked) { color: var(--warn); }
.lock-toggle:not(.locked):hover { background: var(--warn-soft); }
tbody tr.row-selected { background: var(--accent-soft); }

/* A small recognizable glyph before an OS name (see osIcon() in
   dashboard.js) — inline with the text it labels, not a separate column,
   since a VM table already has enough columns. */
.os-icon { display: inline-flex; vertical-align: -3px; margin-right: 5px; color: var(--text-soft); }
.os-icon svg { width: 15px; height: 15px; }
tbody tr.row-selected:hover { background: var(--accent-soft); }

.selection-bar {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--accent-soft); border-bottom: 1px solid var(--accent);
  animation: slide-down 140ms ease-out;
}
@keyframes slide-down { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.selection-count { font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--accent-soft-text); }
.selection-actions { display: flex; gap: var(--space-2); }
.selection-actions .btn { padding: 4px var(--space-3); font-size: var(--fs-xs); }
.selection-bar .btn-quiet { margin-left: auto; font-size: var(--fs-xs); }
/* A destructive page action is the AWS soft red button; the confirming button
   in a dialog (the last step) is its solid red one. */
.btn.danger { background: var(--t9-red-50); color: var(--t9-red-700); border-color: var(--t9-red-50); }
.btn.danger:hover { background: var(--t9-red-100); color: var(--t9-red-700); border-color: var(--t9-red-100); }
.fd-foot .btn.danger, .modal .form-actions .btn.danger, .modal-foot .btn.danger { background: var(--t9-red-600); border-color: var(--t9-red-600); color: #fff; }
.fd-foot .btn.danger:hover, .modal .form-actions .btn.danger:hover, .modal-foot .btn.danger:hover { background: var(--t9-red-700); border-color: var(--t9-red-700); color: #fff; }
.btn.danger:disabled:hover { background: var(--t9-red-50); color: var(--t9-red-700); }

/* Row menu */
.kebab {
  background: none; border: 1px solid transparent; border-radius: var(--radius-md);
  color: var(--muted); font-size: 17px; line-height: 1; cursor: pointer;
  padding: 2px 7px; letter-spacing: 1px;
}
.kebab:hover { background: var(--panel-raised); border-color: var(--hairline); color: var(--text); }
.kebab-menu {
  position: absolute; z-index: 300; width: 168px; padding: 4px 0;
  background: #fff;
  border: 1px solid var(--t9-border-control);
  border-radius: var(--t9-radius-md); box-shadow: var(--t9-shadow-lg);
  display: flex; flex-direction: column;
  /* Anchored at the corner nearest the kebab that opened it (the JS positions
     it below-right of the trigger), so it visibly grows from the control
     rather than materialising from nowhere on the page. */
  transform-origin: top right;
  animation: menu-grow 140ms cubic-bezier(.2,.7,.3,1);
}
@keyframes menu-grow {
  from { opacity: 0; transform: scale(0.94) translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .kebab-menu { background: var(--panel); backdrop-filter: none; }
}
@media (prefers-reduced-motion: reduce) {
  .kebab-menu { animation: rise 1ms linear; }
}
.kebab-menu button {
  text-align: left; background: none; border: 0; cursor: pointer;
  font: inherit; font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); color: var(--t9-text);
  padding: 6px 10px; border-radius: 0;
}
.kebab-menu button:hover { background: var(--t9-slate-50); color: var(--t9-text); }
.kebab-menu button.danger { color: var(--t9-red-700); }
.kebab-menu button.danger:hover { background: var(--t9-red-50); color: var(--t9-red-700); }
.kebab-menu button:disabled {
  color: var(--faint); cursor: not-allowed; opacity: .55;
}
.kebab-menu button.danger:disabled:hover,
.kebab-menu button:disabled:hover { background: none; color: var(--faint); }

/* Grouping */
tbody tr.group-row td {
  background: var(--panel-raised); padding: 6px var(--space-4);
  border-bottom: 1px solid var(--hairline); border-top: 1px solid var(--hairline);
}
tbody tr.group-row:hover td { background: var(--panel-raised); }
.group-name {
  font-size: var(--fs-xs); font-weight: var(--fw-bold); color: var(--text);
  text-transform: uppercase; letter-spacing: var(--ls-wide);
}
.group-count {
  margin-left: var(--space-2); font-size: var(--fs-xs); color: var(--muted);
  background: var(--panel); border: 1px solid var(--hairline);
  border-radius: var(--radius-full); padding: 0 7px; font-weight: var(--fw-semibold);
}

/* A long list is read by scrolling, and a column heading that scrolls away
   takes the meaning of every row with it. This used to cap every table at
   nearly the full viewport height (100vh - 300px) — harmless for a page with
   one table, but Infrastructure stacks five of them (clusters, hosts,
   datacenters, racks, network devices), and each independently claimed
   almost the whole screen: five nested near-full-height scrollboxes instead
   of one page that scrolls. A fixed, human-scale cap means a table long
   enough to need its own scrollbar gets one sized to actually read from,
   not one sized to the window it happens to be open in. */
.table-wrap { max-height: 420px; overflow: auto; }
.table-wrap thead th { position: sticky; top: 0; z-index: 2; }

/* Compute is a single-table page — the fixed cap above exists to stop a
   multi-table page (Infrastructure) from turning into five stacked
   scrollboxes, which doesn't apply here: this table effectively *is* the
   page. Capping it anyway just adds a second, cramped inner scrollbar on
   top of the page's own — reported directly against production, on a
   94-row table with every column now shown by default. Only max-height
   changes, not overflow: with no height cap the box is exactly as tall as
   its content, so overflow:auto (inherited from the rule above) never has
   anything to scroll internally — the page scrolls once, the ordinary
   way, and the sticky header and horizontal scrollbar both keep working
   exactly as before. */
#page-compute .table-wrap { max-height: none; }

/* Compute's Prev/Next + "Page N of M" — the flat (ungrouped) view of a
   filtered list is paginated client-side (see applyVmFilter/
   renderVmPagination in dashboard.js), 25 rows at a time, rather than the
   full list rendering — and, before this, requiring a scroll — every load. */
.pagination { display: flex; align-items: center; justify-content: center; gap: 12px; padding: 8px 0; font-size: var(--t9-fs-xs); color: var(--t9-text-secondary); }
.pagination .btn-icon { width: 28px; height: 28px; font-size: var(--t9-fs-sm); line-height: 1; }
.pagination .btn-icon:disabled { opacity: .4; cursor: not-allowed; }

/* Compute's own row density — 2-3px smaller than the shared table default,
   scoped here rather than in the global --fs-* tokens (which every table
   and every other page reads from too): this is about fitting more of a
   94-row list on screen, not a site-wide type-scale change. */
#page-compute .table-wrap table { font-size: var(--t9-fs-xs); line-height: var(--t9-lh-xs); }
#page-compute .table-wrap thead th { font-size: var(--t9-fs-xs); padding: 8px 10px; }
#page-compute .table-wrap tbody td { padding: 8px 10px; }

/* A name is a link to somewhere, and should look like one. */
button.linky {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-weight: var(--fw-semibold); color: var(--text);
  text-align: left;
}
button.linky:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }


/* ═══════════════ MACHINE DETAIL ═══════════════
   Prism's VM page is a tab strip over one machine with its actions along the
   top. Ours was a single scroll ending in two tables, and the performance
   figures were printed as text — "CPU utilization 0.1%". A number is not a
   reading: a ring that is nearly empty says "idle" before you have read it. */

/* A machine's detail is a page's worth of tables, not a dialogue. It takes the
   window, less a margin that keeps the dimmed page visible behind it — so it
   still reads as something you opened and can close, rather than a navigation. */
.modal.modal-wide {
  max-width: none; width: calc(100vw - 48px);
  max-height: calc(100vh - 48px); display: flex; flex-direction: column;
}
.modal.modal-wide .modal-body { overflow: auto; flex: 1; }
.modal.modal-wide .detail-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
@media (max-width: 720px) { .modal.modal-wide { width: calc(100vw - 16px); } }

.vm-head { min-width: 0; }
.vm-head-meta { display: flex; align-items: center; gap: var(--space-3); margin-top: 5px; flex-wrap: wrap; }
.vm-head-actions { display: flex; gap: var(--space-2); margin-left: auto; margin-right: var(--space-3); }
.vm-head-actions .btn { padding: 4px var(--space-3); font-size: var(--fs-xs); }

.tabstrip {
  display: flex; gap: 4px; padding: 0 16px;
  border-bottom: 1px solid var(--t9-border); background: #fff;
  overflow-x: auto;
}
.tabstrip .tab {
  background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px;
  padding: 8px 12px; cursor: pointer; white-space: nowrap;
  font: inherit; font-size: var(--t9-fs-sm); line-height: var(--t9-lh-sm); font-weight: var(--t9-fw-regular);
  color: var(--t9-text-secondary); transition: color 120ms ease, border-color 120ms ease;
}
.tabstrip .tab:hover { color: var(--t9-slate-800); }
.tabstrip .tab.active { color: var(--t9-brand-700); border-bottom-color: var(--t9-tab-active); font-weight: var(--t9-fw-medium); }

/* VM detail page (#page-vm-detail) — the AWS resource detail: back link, the
   name with its state, actions on the right, tabs on the page's own ground. */
.vm-detail-page { display: flex; flex-direction: column; gap: 16px; }
.vm-detail-page > .back-link { align-self: flex-start; margin-bottom: -8px; }
.detail-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.detail-head-text { flex: 1 1 320px; min-width: 0; }
.detail-head .h1 { flex-wrap: wrap; overflow-wrap: anywhere; }
.detail-head .vm-head-meta { margin-top: 2px; gap: 12px; }
.detail-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex-shrink: 0; }
.vm-detail-page .tabstrip { padding: 0; background: none; }
.vm-detail-page .tabstrip:empty { display: none; }

/* An IP is one token: wrapped, it made every VM row three times the AWS
   module's row height. */
#vms-table td.nowrap { white-space: nowrap; }

/* A settings page (IBM Power Global settings): read-only facts, then a form card. */
.settings-body { max-width: var(--t9-detail-max); }
.settings-form { display: flex; flex-direction: column; gap: 12px; max-width: 640px; padding: 16px; background: #fff; border: 1px solid var(--t9-border); border-radius: var(--t9-radius-lg); }
.settings-form-foot { display: flex; justify-content: flex-end; padding-top: 4px; }
.vm-detail-body { min-height: 160px; }

/* The inside of a .banner (tech9-ui.css): icon, title + detail, Retry. */
.banner > .i { margin-top: 2px; }
.banner-text { flex: 1; min-width: 0; }
.banner-title { margin: 0; font-weight: var(--t9-fw-medium); overflow-wrap: anywhere; }
.banner-detail { margin: 2px 0 0; opacity: .9; overflow-wrap: anywhere; }
.banner-retry { display: inline-flex; align-items: center; gap: 4px; padding: 4px 8px; border: 0; border-radius: var(--t9-radius-md); background: rgb(0 0 0 / .05); font: inherit; font-size: var(--t9-fs-xs); font-weight: var(--t9-fw-medium); color: inherit; cursor: pointer; flex-shrink: 0; }
.banner-retry:hover { background: rgb(0 0 0 / .1); }

/* Gauges */
.gauge-row { display: flex; gap: var(--space-6); flex-wrap: wrap; margin-bottom: var(--space-5); }
.gauge { position: relative; text-align: center; min-width: 108px; }
.gauge-svg { width: 84px; height: 84px; transform: rotate(-90deg); }
.gauge-track { fill: none; stroke: var(--panel-raised); stroke-width: 7; }
.gauge-value {
  fill: none; stroke-width: 7; stroke-linecap: round;
  transition: stroke-dashoffset 700ms cubic-bezier(.2,.7,.3,1);
}
.gauge-svg.good .gauge-value { stroke: var(--good); }
.gauge-svg.warn .gauge-value { stroke: var(--color-warning, #E8B460); }
.gauge-svg.critical .gauge-value { stroke: var(--color-danger); }
.gauge-text { position: absolute; top: 30px; left: 0; right: 0; line-height: 1.15; }
.gauge-text strong { display: block; font-size: var(--fs-sm); color: var(--text); font-variant-numeric: tabular-nums; }
.gauge-text span { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: var(--ls-wide); }
.gauge-hint { font-size: 10px; color: var(--faint); margin-top: 2px; }

/* Meters. Each has a stated reference, because a bar with a hidden scale
   invites a comparison between two things that are not comparable. */
.meter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-4); }
.meter-top { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-2); }
.meter-top span { font-size: var(--fs-xs); color: var(--muted); }
.meter-top strong { font-size: var(--fs-sm); color: var(--text); font-variant-numeric: tabular-nums; }
.meter-unit { font-size: 10px; color: var(--muted); font-weight: var(--fw-regular); }
.meter-track { height: 5px; background: var(--panel-raised); border-radius: var(--radius-full); margin-top: 5px; overflow: hidden; }
.meter-fill {
  height: 100%; background: var(--accent); border-radius: var(--radius-full);
  animation: meter-grow 600ms cubic-bezier(.2,.7,.3,1);
}
@keyframes meter-grow { from { width: 0 !important; } }
.meter-note { font-size: 10px; color: var(--faint); margin-top: 3px; }

/* VM detail's Metrics tab — assigned + live utilization, each with a small
   history built up client-side from polling (see loadVmPerformance): no
   historical-query dependency on Nutanix's Groups API beyond the single
   /stats call this page already made once per tab open. */
.metric-matrix { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: var(--space-4); margin-top: var(--space-5); }
.metric-card { background: var(--card-bg); border: var(--card-border); border-radius: var(--card-radius); padding: var(--space-3); }
.metric-card-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-2); }
.metric-card-label { font-size: var(--fs-xs); color: var(--muted); text-transform: uppercase; letter-spacing: var(--ls-wide); }
.metric-card-value { font-size: var(--fs-sm); color: var(--text); font-variant-numeric: tabular-nums; }
.metric-card-caption { font-size: 10px; color: var(--faint); margin-top: 2px; }
.sparkline { width: 100%; height: 40px; margin-top: var(--space-2); display: block; }
/* The AWS module's time-series colour (--t9-chart-1), a line over a faint fill. */
.sparkline-line { fill: none; stroke: var(--t9-chart-1); stroke-width: 2; vector-effect: non-scaling-stroke; }
.sparkline-area { fill: var(--t9-chart-1); opacity: .08; stroke: none; }
.sparkline-empty { font-size: 10px; fill: var(--t9-text-faint); }

.pad { padding: var(--space-4); }

@media (prefers-reduced-motion: reduce) {
  .gauge-value, .meter-fill { transition: none; animation: none; }
}


/* A pointer to where a thing actually lives, in place of a copy of it. */
.panel-note {
  margin-top: var(--space-4); padding: var(--space-3) var(--space-4);
  background: var(--panel); border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); font-size: var(--fs-xs); color: var(--text-soft);
}


/* Tenant quota and account blocks. */
.quota-body { padding: var(--space-4); }
.quota-row { margin-bottom: var(--space-4); }
.quota-row:last-child { margin-bottom: 0; }
.quota-label {
  font-size: var(--fs-xs); font-weight: var(--fw-semibold); color: var(--muted);
  text-transform: uppercase; letter-spacing: var(--ls-wide); margin-bottom: 5px;
}
.quota-body .detail-grid { padding: 0; }


/* ═══════════════ CHARTS ═══════════════
   Six steps of one hue, not six colours. Categorical colour says "these are
   different kinds of thing"; a cost breakdown is one kind of thing in different
   amounts, so the only job the colour has is rank — and a mono ramp stays
   readable for anyone who cannot separate red from green. */

.chart-body { padding: var(--space-4); }
.tabstrip-page {
  padding: 0; margin: var(--space-5) 0 var(--space-4);
  background: none; border-bottom: 1px solid var(--hairline);
}
.tabpane { animation: rise 160ms ease-out; }

/* Donut */
.donut-wrap { display: flex; gap: var(--space-5); align-items: center; flex-wrap: wrap; }
.donut { width: 150px; height: 150px; transform: rotate(-90deg); flex: none; }
.donut circle { transition: stroke-dasharray 500ms cubic-bezier(.2,.7,.3,1); }
.donut text { transform: rotate(90deg); transform-origin: 70px 70px; text-anchor: middle; }
.donut-total { font-size: 15px; font-weight: 700; fill: var(--text); }
.donut-cap { font-size: 8px; fill: var(--muted); text-transform: uppercase; letter-spacing: .1em; }

.legend { list-style: none; margin: 0; padding: 0; flex: 1; min-width: 210px; }
.legend li {
  display: flex; align-items: center; gap: var(--space-2);
  padding: 4px 0; font-size: var(--fs-xs); border-bottom: 1px solid var(--border-subtle);
}
.legend li:last-child { border-bottom: 0; }
.swatch { width: 9px; height: 9px; border-radius: 2px; flex: none; }
.legend-label { color: var(--text-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.legend-value { margin-left: auto; font-weight: var(--fw-semibold); color: var(--text); font-variant-numeric: tabular-nums; }
.legend-pct { color: var(--muted); min-width: 42px; text-align: right; font-variant-numeric: tabular-nums; }

/* Columns */
.columns { display: flex; gap: var(--space-3); align-items: flex-end; height: 168px; }
.column { flex: 1; display: flex; flex-direction: column; align-items: center; height: 100%; min-width: 0; }
.column-value { font-size: 10px; font-weight: var(--fw-semibold); color: var(--text); margin-bottom: 4px; }
.column-track { flex: 1; width: 100%; display: flex; align-items: flex-end; }
.column-fill {
  width: 100%; background: var(--accent); border-radius: 3px 3px 0 0;
  animation: col-grow 500ms cubic-bezier(.2,.7,.3,1);
}
@keyframes col-grow { from { height: 0 !important; } }
.column-label {
  font-size: 10px; color: var(--muted); margin-top: 5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}

/* Ranked bars */
.ranked { display: flex; flex-direction: column; gap: 7px; }
.ranked-row { display: flex; align-items: center; gap: var(--space-3); font-size: var(--fs-xs); }
.ranked-label {
  width: 160px; flex: none; color: var(--text-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ranked-track { flex: 1; height: 16px; background: var(--panel-raised); border-radius: 3px; overflow: hidden; }
.ranked-fill { height: 100%; border-radius: 3px; animation: meter-grow 500ms cubic-bezier(.2,.7,.3,1); }
.ranked-value {
  width: 92px; text-align: right; font-weight: var(--fw-semibold);
  color: var(--text); font-variant-numeric: tabular-nums;
}

/* The actions belong on one line with the title, not wrapped under it. */
.page-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

@media (prefers-reduced-motion: reduce) {
  .donut circle, .column-fill, .ranked-fill { animation: none; transition: none; }
}


/* An edit offered where the value is shown, rather than in a menu somewhere
   else. Quiet until the section is hovered, so it does not compete with the
   numbers it sits beside. */
.detail-section-label { display: flex; align-items: center; gap: var(--space-2); }
.section-edit {
  background: none; border: 0; cursor: pointer; padding: 0 2px;
  font: inherit; font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  color: var(--accent); text-transform: none; letter-spacing: normal;
  opacity: 0; transition: opacity 120ms ease;
}
.detail-section:hover .section-edit, .section-edit:focus-visible { opacity: 1; }
.section-edit:hover { text-decoration: underline; text-underline-offset: 2px; }


/* ═══════════════ MOBILE ═══════════════
   Below 720px the sidebar becomes an off-canvas drawer, opened by the menu
   button and closed by its backdrop, Escape, or picking a destination. */
.rail-backdrop {
  position: fixed; inset: 0; background: var(--t9-overlay);
  z-index: 550; opacity: 0; pointer-events: none; transition: opacity 200ms ease;
}
.rail-backdrop.show { opacity: 1; pointer-events: auto; }

@media (max-width: 720px) {
  button.hamburger-btn { display: inline-flex; }
  .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; width: 84vw; max-width: var(--t9-sidebar-w);
    transform: translateX(-100%); transition: transform 220ms cubic-bezier(.2, .7, .3, 1);
    z-index: 600; box-shadow: var(--t9-shadow-xl);
  }
  .sidebar.rail-open { transform: none; }
  .topbar { padding: 0 12px; gap: 8px; }
  .crumbs { display: none; }
  .search-wrap { width: auto; flex: 1; min-width: 0; }
  .topbar__right { flex: 1; min-width: 0; }
  .search kbd, .refresh-btn span { display: none; }
  .content { padding: 16px; }
}
@media (max-width: 720px) and (prefers-reduced-motion: reduce) { .sidebar { transition: none; } }

/* Collapsible sidebar (the topbar's menu button, wider than a phone). Folded,
   it is a 48px rail of icons that opens back out over the page on hover or
   keyboard focus — a cloud's section items have no icons, so they are always
   one hover away rather than gone. The rail's width stays reserved, so the
   page doesn't jump as it opens. */
.sidebar__brand .sidebar__brand-mark { display: none; height: 26px; width: 26px; }
/* Provider marks (cloud-icons.svg) carry their own colours and read better a size up. */
.i.i-brand { width: 18px; height: 18px; margin: -1px; }
@media (min-width: 721px) {
  button.hamburger-btn { display: inline-flex; }
  .sidebar-collapsed .t9-app { padding-left: 48px; }
  .sidebar-collapsed .sidebar {
    position: fixed; top: 0; bottom: 0; left: 0; width: 48px; overflow: hidden; z-index: 500;
    transition: width 160ms ease, box-shadow 160ms ease;
  }
  .sidebar-collapsed .sidebar:hover,
  .sidebar-collapsed .sidebar:focus-within { width: var(--t9-sidebar-w); overflow-y: auto; box-shadow: var(--t9-shadow-xl); }
  /* Folded: icons only. */
  .sidebar-collapsed .sidebar:not(:hover):not(:focus-within) .sidebar__brand { padding: 0 11px; }
  .sidebar-collapsed .sidebar:not(:hover):not(:focus-within) .sidebar__brand .sidebar__brand-mark { display: block; }
  .sidebar-collapsed .sidebar:not(:hover):not(:focus-within) :is(
    .sidebar__brand > img:not(.sidebar__brand-mark), .sidebar__brand-divider, .sidebar__brand-name,
    .sidebar__heading, .sidebar__conn, .sidebar__item, .sidebar__who-text, .badge, .truncate, .eyebrow,
    .sidebar__topLink > span, .sidebar__group > span, .sidebar__back > span, .sidebar__signout > span
  ) { display: none; }
  .sidebar-collapsed .sidebar:not(:hover):not(:focus-within) .sidebar__who { padding: 4px 0 8px; }
}
@media (min-width: 721px) and (prefers-reduced-motion: reduce) { .sidebar-collapsed .sidebar { transition: none; } }


/* ═══════════════ 404 ═══════════════
   Rendered by server.js for anything that matches no route and no static file.
   It links this stylesheet, so it is never a second, forgotten design system —
   just a page with no .shell around it. */
.notfound-page {
  min-height: 100vh; display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center; padding: var(--space-6);
  background: var(--canvas);
}
.notfound-logo { height: 32px; width: auto; margin-bottom: var(--space-6); }
.notfound-code {
  font-size: 72px; font-weight: var(--fw-bold); color: var(--accent-soft);
  line-height: 1; letter-spacing: -.02em;
}
.notfound-page h1 { font-size: var(--fs-lg); color: var(--text); margin: var(--space-3) 0 var(--space-2); }
.notfound-page p { color: var(--text-soft); font-size: var(--fs-sm); max-width: 46ch; margin: 0 0 var(--space-5); }
.notfound-page .btn.primary { text-decoration: none; }


/* Consolidated Dashboard summary stats — each a clickable entry point into
 * the page it's counting, not just a static tile. */
.summary-stat {
  text-align: left; cursor: pointer;
  transition: transform 160ms cubic-bezier(.2,.7,.3,1), box-shadow 160ms ease, border-color 160ms ease;
}
.summary-stat:hover { transform: translateY(-2px); box-shadow: var(--shadow-raised); border-color: var(--accent); }
.summary-stat .widget-body { display: flex; flex-direction: column; gap: 2px; }
.summary-stat .widget-body svg {
  width: 20px; height: 20px; margin-bottom: var(--space-2); color: var(--accent); opacity: 0.85;
}
.summary-stat .widget-body .sub { margin: 0; font-size: var(--fs-xs); color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.summary-stat .widget-body h2 {
  margin: 0; font-size: 28px; font-weight: var(--fw-bold); letter-spacing: -0.02em; color: var(--text);
}

/* A VM NIC's public IPs (Network tab) — address, simulated tag, services, release. */
.pip-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.pip-row + .pip-row { margin-top: var(--space-1); }

/* ── Page headers, the AWS way ─────────────────────────────────────────────
   Title and description take the free space; every action sits together on
   the right. Platform pages drop their "Back to your clouds" (the sidebar is
   that now); Tenant detail keeps its back link, above the title, as an AWS
   detail page does. */
.page-head > div:first-child { flex: 1 1 320px; min-width: 0; }
.page-head [data-back-to-clouds] { display: none; }
#page-platform-tenant-detail .page-head [data-back-to-clouds] { display: inline-flex; order: -1; flex-basis: 100%; justify-content: flex-start; }
#ibm-unconfigured-banner p { margin: 0; }

/* Switch-over: several policies per person (access-ui.js). */
.access-multi { position: relative; }
.access-multi > summary { list-style: none; cursor: pointer; padding: 6px 28px 6px 10px; border: 1px solid var(--hairline); border-radius: var(--t9-radius-md); background: var(--t9-surface, #fff); font-size: var(--t9-fs-sm); max-width: 320px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.access-multi > summary::-webkit-details-marker { display: none; }
.access-multi > summary::after { content: "\25BE"; position: absolute; right: 10px; top: 6px; color: var(--t9-text-secondary); }
.access-multi[open] > summary { border-color: var(--t9-primary); }
.access-multi__list { position: absolute; z-index: 20; right: 0; top: calc(100% + 4px); width: 340px; max-height: 320px; overflow-y: auto; padding: 6px; border: 1px solid var(--hairline); border-radius: var(--t9-radius-lg); background: var(--t9-surface, #fff); box-shadow: var(--t9-shadow-card, 0 4px 16px rgba(15, 23, 42, .12)); }
.access-multi__list label { display: flex; align-items: flex-start; gap: 8px; padding: 6px 8px; border-radius: var(--t9-radius-md); cursor: pointer; font-size: var(--t9-fs-sm); }
.access-multi__list label:hover { background: var(--t9-slate-50, #f8fafc); }
.access-multi__list input { margin-top: 3px; }
.access-switch-people { overflow: visible; }

/* Cloud dashboards (cloud-dashboards.js, dash-kit.js): the KPI strip, what
   needs attention, short lists, the trend chart and period picker. */
.dk-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 10px; }
.dk-kpi { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 12px 14px; border: 1px solid var(--hairline); border-radius: var(--t9-radius-lg); background: var(--panel-raised); text-align: left; font: inherit; color: inherit; cursor: pointer; min-width: 0; }
.dk-kpi:hover:not(:disabled) { border-color: var(--t9-brand-500); }
.dk-kpi:disabled { cursor: default; }
.dk-kpi:focus-visible { outline: 2px solid var(--t9-brand-500); outline-offset: 2px; }
.dk-kpi-label { font-size: var(--fs-xs); color: var(--muted); }
.dk-kpi-value { font-size: var(--fs-xl, 20px); font-weight: var(--fw-bold); color: var(--text); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.dk-kpi-sub { font-size: var(--fs-xs); color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.dk-kpi.critical { background: var(--critical-soft); border-color: var(--critical-soft); }
.dk-kpi.critical .dk-kpi-value { color: var(--critical); }
.dk-kpi.warn { background: var(--warn-soft); border-color: var(--warn-soft); }
.dk-kpi.warn .dk-kpi-value { color: var(--warn); }
.dk-insights { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.dk-insight { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-top: 1px solid var(--hairline); font-size: var(--fs-sm); }
.dk-insight:first-child { border-top: 0; padding-top: 0; }
.dk-insight-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--info); }
.dk-insight.critical .dk-insight-dot { background: var(--critical); }
.dk-insight.warning .dk-insight-dot { background: var(--warn); }
.dk-insight-text { flex: 1; min-width: 0; }
.dk-ok { display: flex; align-items: center; gap: 6px; color: var(--good); }
.dk-factors { margin: 8px 0 0; padding-left: 18px; font-size: var(--fs-xs); color: var(--muted); display: flex; flex-direction: column; gap: 2px; }
.dk-rows { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.dk-rows li { display: flex; align-items: center; gap: 8px; font-size: var(--fs-sm); min-width: 0; }
.dk-row-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dk-range { display: flex; gap: 4px; justify-content: flex-end; margin-bottom: 8px; }
.dk-range .is-on { border-color: var(--t9-brand-500); color: var(--t9-brand-600, var(--text)); font-weight: var(--fw-semibold); }
.dk-chart-trend { height: 220px; }
.dk-chart-donut { height: 150px; margin: 6px 0; }
.dk-consumers { display: flex; gap: 16px; flex-wrap: wrap; }
.dk-consumers .tc-col { min-width: 160px; }
