/* Admin panel (ML-26) - separate small stylesheet since this is its own
   growing area (Release tests today; Usage, Accounts later), not part of
   the practice-tracker SPA's layout. Reuses style.css's design tokens
   (colors, spacing, radius, dark mode) rather than redefining them. */

body.admin-body { display: block; background: var(--bg-color); }

.admin-logged-out { max-width: var(--app-max-width); margin: var(--space-10) auto; text-align: center; padding: 0 var(--space-5); }

.admin-shell { display: flex; min-height: 100vh; }

/* ML-277: the menu stays where it is while the page beside it scrolls; if it is taller than the window it scrolls by itself */
.admin-sidebar { width: 220px; flex-shrink: 0; background: var(--container-bg); border-right: 1px solid var(--input-border); padding: var(--space-5) 0; box-sizing: border-box; position: sticky; top: 0; align-self: flex-start; height: 100vh; overflow-y: auto; }
.admin-sidebar-title { font-weight: var(--font-weight-bold); font-size: var(--font-lg); padding: 0 var(--space-5) var(--space-5) var(--space-5); color: var(--text-color); }
.admin-nav-item { display: block; width: 100%; box-sizing: border-box; text-align: left; background: none; border: none; border-left: 3px solid transparent; padding: var(--space-3) var(--space-5); font-size: var(--font-base); font-weight: var(--font-weight-semibold); font-family: var(--font-sans); color: var(--text-color); cursor: pointer; }
.admin-nav-item:disabled { color: var(--label-color); cursor: default; }
.admin-nav-item.active { background: var(--secondary-color); border-left-color: var(--primary-action); }
/* ML-110: the sidebar's own <a> (not <button>) needs its default link colour/underline reset to
   match the plain nav buttons above/below it, plus a separator so it doesn't read as just another
   section tab. */
.admin-back-link { text-decoration: none; color: var(--label-color); border-bottom: 1px solid var(--input-border); margin-bottom: var(--space-2); padding-bottom: var(--space-4); }
.admin-back-link:hover { color: var(--text-color); }

/* ML-443: the menu in groups. A heading (a button) opens and closes its group; a shut group's heading carries
   the count of what is waiting inside. On a wide screen the double arrow folds the whole menu down to a
   strip, so a wide table gets the window - a phone has the ☰ toggle instead. */
.admin-sidebar-head { display: flex; align-items: flex-start; justify-content: space-between; }
.admin-nav-fold { display: flex; align-items: center; justify-content: center; flex-shrink: 0; width: var(--touch-target); height: var(--touch-target); margin: calc(-1 * var(--space-3)) var(--space-2) 0 0; background: none; border: none; border-radius: var(--radius-sm); color: var(--label-color); cursor: pointer; }
.admin-nav-fold:hover { color: var(--text-color); }
.admin-nav-group { border-top: 1px solid var(--input-border); }
.admin-nav-group:first-of-type { border-top: none; }
.admin-nav-group-head { display: flex; align-items: center; gap: var(--space-2); width: 100%; min-height: var(--touch-target); box-sizing: border-box; padding: var(--space-2) var(--space-4) var(--space-2) var(--space-5); background: none; border: none; font-family: var(--font-sans); font-size: var(--font-sm); font-weight: var(--font-weight-bold); color: var(--label-color); text-align: left; cursor: pointer; }
.admin-nav-group-head:hover { color: var(--text-color); }
.admin-nav-group-name { flex: 1; min-width: 0; }
.admin-nav-group-items { padding-bottom: var(--space-2); }
@media (min-width: 701px) {
  .admin-shell.is-nav-folded .admin-sidebar { width: auto; padding: var(--space-2) var(--space-1); }
  .admin-shell.is-nav-folded .admin-sidebar-title, .admin-shell.is-nav-folded .admin-nav-items { display: none; }
  .admin-shell.is-nav-folded .admin-nav-fold { margin: 0; }
}

.admin-content { flex: 1; min-width: 0; padding: var(--space-6) var(--space-7); box-sizing: border-box; max-width: 900px; overflow-wrap: break-word; } /* min-width: 0 lets wide tables scroll inside .admin-stat-table-wrap instead of widening the page (ML-204) */
.admin-content h1 { margin-top: 0; color: var(--text-color); }
.admin-intro { color: var(--label-color); font-size: var(--font-sm); margin: calc(-1 * var(--space-2)) 0 var(--space-3); }
.admin-intro code { background: var(--input-bg); padding: var(--space-0-5) var(--space-1); border-radius: var(--radius-xs); }

.admin-link { display: inline-block; color: var(--primary-action-strong); font-weight: var(--font-weight-bold); font-size: var(--font-base); text-decoration: none; margin-bottom: var(--space-5); }
.admin-link:hover { text-decoration: underline; }

.admin-summary-grid { grid-template-columns: repeat(4, 1fr); margin-bottom: var(--space-7); }

.admin-add-btn { max-width: 220px; margin-bottom: var(--space-5); }

/* ML-109: the Metadata lists section's own inner tab row (Durations/Time signatures/Note values/
   Playback speeds) - a horizontal counterpart to .admin-nav-item's vertical sidebar tabs, since these
   four live inside one section rather than as separate top-level sidebar entries. */
.admin-subtabs { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-5); border-bottom: 1px solid var(--input-border); }
.admin-subtab-item { background: none; border: none; border-bottom: 3px solid transparent; padding: var(--space-3) var(--space-4); margin-bottom: -1px; /* token-audit-ignore: overlaps the row border so the active underline sits on it */ font-size: var(--font-base); font-weight: var(--font-weight-semibold); font-family: var(--font-sans); color: var(--label-color); cursor: pointer; }
.admin-subtab-item.active { color: var(--text-color); border-bottom-color: var(--primary-action); }

.admin-feature { border: 1px solid var(--input-border); border-radius: var(--radius-md); margin-bottom: var(--space-5); overflow: hidden; }
.admin-feature[data-feedback-row] { cursor: pointer; } /* a Feedback card opens its review pop-up */
/* ML-294: Warm-ups - the list and the tap-to-build editor (see specs/components/admin-shell.md). */
.admin-warmup-kind { margin: var(--space-5) 0 var(--space-2) 0; font-size: var(--font-md); }
.admin-warmup-row-preview svg { display: block; width: 100%; max-width: 480px; height: auto; margin-top: var(--space-2); }
.admin-warmup-off { opacity: var(--opacity-muted); }
.modal-content.admin-modal-wide { max-width: 720px; }
.admin-warmup-fields { display: grid; grid-template-columns: 2fr 1.4fr 1fr 1fr; gap: var(--space-3); }
.admin-warmup-preview-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-top: var(--space-3); }
.admin-warmup-preview-head .radio-group { margin: 0; width: 240px; flex-shrink: 0; }
.admin-warmup-preview { background: var(--container-bg); border: 1px solid var(--input-border); border-radius: var(--radius-md); padding: var(--space-2); min-height: calc(var(--touch-target) * 2); margin-top: var(--space-2); }
.admin-warmup-preview svg { display: block; width: 100%; height: auto; }
.admin-warmup-preview .warmup-note { cursor: pointer; }
.admin-warmup-preview .is-selected { fill: var(--primary-action-strong); }
.admin-warmup-status { font-size: var(--font-sm); color: var(--label-color); min-height: 1.4em; margin: var(--space-2) 0; }
.admin-warmup-status.has-errors { color: var(--danger-text); }
.admin-warmup-inline { margin-top: var(--space-2); }
.admin-warmup-tools { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.admin-warmup-tools .btn-edit, .admin-warmup-tools .btn-delete { width: auto; min-width: var(--touch-target); }
@media (max-width: 700px) { .admin-warmup-fields { grid-template-columns: 1fr 1fr; } }
/* flex-wrap (plus the text side's own min-width:0 below) lets a wide sibling - the level <select>,
   or actions - drop to its own line under the text on a narrow viewport instead of overlapping it:
   the admin sidebar (.admin-sidebar, 220px fixed) leaves very little width for content on a phone-
   width screen, and a plain no-wrap flex row has nowhere else to put a sibling that doesn't fit. */
.admin-feature-header { background: var(--input-bg); padding: var(--space-4); display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; gap: var(--space-3); }
.admin-feature-header-text { flex: 1 1 calc(var(--touch-target) * 5); min-width: 0; } /* ML-390: a basis, so on a phone the buttons wrap under the text instead of squeezing it to one letter wide */
.admin-feature-header h2 { margin: 0 0 var(--space-1) 0; font-size: var(--font-md); color: var(--text-color); }
.admin-feature-header p { margin: 0; color: var(--label-color); font-size: var(--font-sm); }
/* Bare <a> tags (band website links) otherwise fall back to the browser's default link blue/purple,
   which is very low-contrast against a dark background - every other in-app link already sets an
   explicit colour (e.g. .admin-test-case-meta a below), this one just hadn't yet. */
.admin-feature-header p a { color: var(--info-text); }
.admin-feature-actions { display: flex; gap: var(--space-2); flex-shrink: 0; }
.admin-feature-actions .btn-icon-edit,
.admin-feature-actions .btn-icon-delete { width: 30px; height: 30px; }
.admin-feature-actions .material-symbols-outlined { font-size: var(--icon-sm); }

.admin-level-select { flex-shrink: 0; max-width: 100%; box-sizing: border-box; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); border: 1px solid var(--control-border); background: var(--input-bg); color: var(--text-color); font-size: var(--font-sm); }

.admin-test-case { padding: var(--space-4); border-top: 1px solid var(--input-border); }
.admin-test-case-head { display: flex; justify-content: space-between; align-items: center; cursor: pointer; gap: var(--space-3); }
.admin-test-case-title { font-weight: var(--font-weight-semibold); color: var(--text-color); }
.admin-test-case-meta { font-size: var(--font-sm); color: var(--label-color); margin-top: var(--space-0-5); }
.admin-test-case-meta a { color: var(--info-text); }

.admin-badge { display: inline-block; padding: var(--space-0-5) var(--space-3); border-radius: var(--radius-pill); font-size: var(--font-xs); font-weight: var(--font-weight-bold); text-transform: uppercase; white-space: nowrap; }
.admin-badge.pass { background: var(--success-color); color: var(--text-on-accent); }
.admin-badge.fail { background: var(--danger-color); color: var(--text-on-accent); }
.admin-badge.skipped { background: var(--nav-action); color: var(--nav-action-text); }
.admin-badge.never { background: var(--input-border); color: var(--label-color); }

.admin-run-history { margin-top: var(--space-3); display: none; }
.admin-run-history.show { display: block; }
.admin-run-row { display: flex; gap: var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--input-border); font-size: var(--font-sm); align-items: flex-start; }
.admin-run-row:first-child { border-top: none; }
.admin-run-when { color: var(--label-color); white-space: nowrap; width: 150px; flex-shrink: 0; }
.admin-run-detail { flex: 1; min-width: 0; }
.admin-run-duration { color: var(--label-color); font-size: var(--font-xs); margin-left: var(--space-2); }
.admin-run-error { color: var(--danger-text); margin: var(--space-1) 0 0 0; font-family: var(--font-mono); font-size: var(--font-xs); white-space: pre-wrap; word-break: break-word; }
.admin-run-notes { margin: var(--space-1) 0 0 0; font-size: var(--font-xs); color: var(--text-color); }

.admin-feature-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-2); }
.admin-chip { background: var(--secondary-color); color: var(--text-color); border-radius: var(--radius-pill); padding: var(--space-0-5) var(--space-3); font-size: var(--font-xs); font-weight: var(--font-weight-semibold); }
.admin-chip-empty { background: var(--input-border); color: var(--label-color); font-weight: var(--font-weight-normal); }

/* ML-240: phone-width menu. The head row (title + current section + ☰ toggle) only shows as a row
   on a phone; on wider screens the toggle and current-section label are hidden and the list is the
   plain sidebar as before. */
.admin-sidebar-current { display: none; margin-left: var(--space-2); color: var(--label-color); font-weight: var(--font-weight-semibold); font-size: var(--font-base); }
.admin-nav-toggle { display: none; align-items: center; justify-content: center; flex-shrink: 0; width: var(--touch-target); height: var(--touch-target); background: none; border: none; border-radius: var(--radius-sm); color: var(--text-color); cursor: pointer; }

@media (max-width: 700px) {
  .admin-shell { flex-direction: column; }
  /* The section list used to become one long horizontal row here, which pushed the whole page to
     ~1200px wide - everything else (cards, stat tiles, pop-ups centred on the page) then sat
     partly off-screen. Now it folds away behind the ☰ toggle and opens as a vertical list. */
  .admin-sidebar { width: 100%; padding: var(--space-2) var(--space-4); border-right: none; border-bottom: 1px solid var(--input-border); position: static; align-self: auto; height: auto; overflow-y: visible; }
  .admin-sidebar-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
  .admin-sidebar-title { padding: 0; min-width: 0; overflow-wrap: anywhere; }
  .admin-sidebar-current { display: inline; }
  .admin-nav-toggle { display: flex; }
  .admin-nav-fold { display: none; }
  .admin-sidebar-head { align-items: center; }
  .admin-nav-group-head { padding: var(--space-2) var(--space-4); }
  .admin-nav-items { display: none; padding: var(--space-2) 0; }
  .admin-sidebar.expanded .admin-nav-items { display: block; }
  .admin-nav-item { min-height: var(--touch-target); padding: var(--space-3) var(--space-4); }
  .admin-content { padding: var(--space-4); }
  /* minmax(0, 1fr), not plain 1fr, so a long number or label can't stretch a column past the
     screen edge - it wraps inside its tile instead. */
  .admin-summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .admin-run-row { flex-direction: column; }
  .admin-run-when { width: auto; }
}

/* ML-199 - Flow authoring time. Plain tables rather than the .admin-feature card stack the rest of
   this panel uses: these are dense numeric comparisons (median/mean/min/max across several
   groupings), and the whole point is reading DOWN a column to compare one app version against
   another, which a stack of cards makes impossible. */
.admin-stat-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-3); margin-bottom: var(--space-6); }
/* ML-203: number first, then its spread, then the label - same value-over-caption order as the app's
   stat cards and tiles (flex order only, so the markup still reads label-first). */
.admin-stat-tile { display: flex; flex-direction: column; border: 1px solid var(--input-border); border-radius: var(--radius-md); padding: var(--space-4); background: var(--input-bg); }
.admin-stat-tile-value { order: 1; }
.admin-stat-tile-sub { order: 2; }
.admin-stat-tile-label { order: 3; font-size: var(--font-sm); color: var(--label-color); margin-top: var(--space-1); }
.admin-stat-tile-value { font-size: var(--font-lg); font-weight: var(--font-weight-bold); color: var(--text-color); }
/* The spread (min-max) sits under every headline number deliberately - a median with no sense of
   its spread invites a conclusion the sample can't support. */
.admin-stat-tile-sub { font-size: var(--font-sm); color: var(--label-color); margin-top: var(--space-1); }

.admin-stat-section-title { font-size: var(--font-md); font-weight: var(--font-weight-bold); color: var(--text-color); margin: var(--space-6) 0 var(--space-2) 0; }
.admin-stat-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; margin-bottom: var(--space-5); }
/* Feature access's grid (7 columns) uses the whole width beside the menu, not the usual 900px reading width;
   its intro stays at that width so the lines don't run too long. Still scrolls sideways when the window is narrower. */
.admin-content:has(> #feature-access-section:not(.hidden-group)) { max-width: none; }
/* ML-415 / ML-416: the Accounts and Flows tables use the window's width too */
.admin-content:has(> #accounts-section:not(.hidden-group)), .admin-content:has(> #flows-section:not(.hidden-group)) { max-width: none; }
#accounts-section .admin-intro, #flows-section .admin-intro { max-width: 900px; }
/* ML-429: so do Third parties' cost and usage tables; the reading text stays at reading width */
.admin-content:has(> #third-parties-section:not(.hidden-group)), .admin-content:has(> #costs-usage-section:not(.hidden-group)) { max-width: none; }
#third-parties-section .admin-intro, #third-parties-section .admin-feature, #third-parties-section .admin-stat-tiles, #costs-usage-section .admin-intro, #costs-usage-section .admin-feature, #costs-usage-section .admin-stat-tiles { max-width: 900px; }
/* ML-427: Usage's tables (Recent sessions has 15 columns) use the window's width as well */
.admin-content:has(> #usage-section:not(.hidden-group)) { max-width: none; }
#usage-section .admin-intro { max-width: 900px; }
#usage-section .admin-stat-table td:first-child { white-space: normal; } /* a long piece name wraps, so the other columns stay on screen */
/* ML-415: one line per account - text columns read from the left, the ⋮ sits at the right */
.admin-stat-table.admin-accounts-table th, .admin-stat-table.admin-accounts-table td { text-align: left; vertical-align: middle; }
.admin-stat-table.admin-accounts-table td:last-child, .admin-flows-table td:last-child { text-align: right; width: 1%; }
.admin-flows-table td:last-child { vertical-align: middle; }
#feature-access-section .admin-intro { max-width: 900px; }
.admin-stat-table { border-collapse: collapse; width: 100%; font-size: var(--font-sm); }
.admin-stat-table th, .admin-stat-table td { padding: var(--space-2) var(--space-3); text-align: right; border-bottom: 1px solid var(--input-border); white-space: nowrap; }
.admin-stat-table th { color: var(--label-color); font-weight: var(--font-weight-semibold); text-align: right; }
.admin-stat-table th:first-child, .admin-stat-table td:first-child { text-align: left; }
.admin-stat-table tbody tr:hover { background: var(--input-bg); }
/* An excluded run stays visible and readable, just visibly not counted - the point of excluding is
   to keep the evidence, so hiding the row would defeat it. */
.admin-stat-row-excluded td { opacity: 0.45; text-decoration: line-through; }
.admin-stat-empty { color: var(--label-color); font-size: var(--font-sm); padding: var(--space-4) 0; }
.admin-stat-pill { display: inline-block; font-size: var(--font-sm); padding: var(--space-0-5) var(--space-2); border-radius: var(--radius-md); background: var(--input-bg); border: 1px solid var(--input-border); color: var(--label-color); }
.admin-stat-exclude-btn { background: none; border: 1px solid var(--input-border); border-radius: var(--radius-md); padding: var(--space-0-5) var(--space-2); font-size: var(--font-sm); font-family: var(--font-sans); color: var(--label-color); cursor: pointer; }
.admin-stat-exclude-btn:hover { color: var(--text-color); }

/* ML-170 - Feedback triage. */
.admin-nav-count { display: inline-block; min-width: 18px; padding: 0 var(--space-1); border-radius: var(--radius-sm); background: var(--primary-action); color: var(--text-on-accent); font-size: var(--font-sm); text-align: center; }
/* white-space: pre-wrap so a submission's own line breaks survive - people write bug reports as
   short lists, and collapsing those into a paragraph makes them harder to act on. */
.admin-feedback-message { white-space: pre-wrap; background: var(--input-bg); border: 1px solid var(--input-border); border-radius: var(--radius-md); padding: var(--space-4); margin-bottom: var(--space-4); color: var(--text-color); }
.admin-feedback-snippet { color: var(--text-color); margin: var(--space-1) 0 0 0; }
.admin-feedback-badges { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.admin-feedback-badge { font-size: var(--font-sm); padding: var(--space-0-5) var(--space-2); border-radius: var(--radius-md); border: 1px solid transparent; }
/* The colours ML-170 asks for, extended to the two statuses its own dropdown mentions but never
   gave a colour to (in progress, resolved) - see 045_feedback.sql on reconciling the three lists.
   Each pairs a tinted background with a readable foreground rather than relying on hue alone, so
   the status is still distinguishable without colour vision. */
.admin-feedback-badge.status-under_review { background: var(--status-amber-bg); color: var(--status-amber-fg); }
.admin-feedback-badge.status-planned { background: var(--status-green-bg); color: var(--status-green-fg); }
.admin-feedback-badge.status-in_progress { background: var(--status-blue-bg); color: var(--status-blue-fg); }
.admin-feedback-badge.status-not_progressing { background: var(--status-grey-bg); color: var(--status-grey-fg); }
.admin-feedback-badge.status-resolved { background: var(--status-purple-bg); color: var(--status-purple-fg); }
.admin-feedback-badge.cat { background: var(--input-bg); color: var(--label-color); border-color: var(--input-border); }
/* Dark-mode variants come from tokens.css - body.dark-mode remaps the --status-* aliases (ML-198). */

/* Must come AFTER the base rules above, not folded into the existing max-width:700px block near the
   top of this file - these have the same specificity, so whichever is declared last wins and a
   narrow-screen override placed above the base rule would simply never apply.
   Four stat tiles don't fit a phone once the fixed 220px sidebar has taken its share, and the
   tables carry more columns than that leaves room for - they scroll sideways inside their own
   wrapper (.admin-stat-table-wrap) rather than crushing every column to unreadable width. */
@media (max-width: 700px) {
  .admin-stat-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ML-201 - Notifications */
.admin-notification-body { white-space: pre-wrap; margin: var(--space-2) 0 0 !important; color: var(--text-color) !important; }
.admin-feature-actions .btn-edit, .admin-feature-actions .btn-delete { min-height: 36px; padding: var(--space-1) var(--space-3); }
.admin-feedback-badge.notification-status-live { background: var(--status-green-bg); color: var(--status-green-fg); }
.admin-feedback-badge.notification-status-scheduled { background: var(--status-blue-bg); color: var(--status-blue-fg); }
.admin-feedback-badge.notification-status-expired, .admin-feedback-badge.notification-status-withdrawn { background: var(--status-grey-bg); color: var(--status-grey-fg); }
/* ML-167: an urgent notification (pops up in the app until read) */
.admin-feedback-badge.notification-status-urgent { background: var(--status-amber-bg); color: var(--status-amber-fg); }

/* ML-204 - Flows (export/import between environments). Reuses .admin-stat-table for the list; the
   import preview is a scrolling list inside the standard modal, one card per flow in the file. */
.admin-flows-toolbar { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; margin-bottom: var(--space-5); }
.admin-flows-toolbar .btn-submit { width: auto; flex: 0 0 auto; padding-left: var(--space-5); padding-right: var(--space-5); }
.admin-flows-filter { flex: 1 1 240px; min-width: 0; padding: var(--space-3); border: 1px solid var(--control-border); border-radius: var(--radius-md); background: var(--input-bg); color: var(--text-color); font-family: var(--font-sans); font-size: var(--font-base); }
.admin-flows-table td { vertical-align: top; }
.admin-flows-table td:nth-child(2), .admin-flows-table th:nth-child(2), .admin-flows-table td:nth-child(3), .admin-flows-table th:nth-child(3) { text-align: left; white-space: normal; min-width: 110px; }
.admin-flows-table td:nth-child(6), .admin-flows-table td:nth-child(7) { white-space: normal; }
.admin-flows-table th, .admin-flows-table td { padding-left: var(--space-2); padding-right: var(--space-2); }
.admin-flows-import-modal { max-width: 640px; }
#flowsImportList { max-height: 50vh; overflow-y: auto; margin: var(--space-4) 0; }
.admin-flows-import-item { border: 1px solid var(--input-border); border-radius: var(--radius-md); padding: var(--space-3); margin-bottom: var(--space-3); display: flex; flex-direction: column; gap: var(--space-1); }
.admin-flows-import-item.has-errors { border-color: var(--danger-text); }
.admin-flows-import-item p { margin: 0; font-size: var(--font-sm); }
.admin-flows-import-error { color: var(--danger-text); }
.admin-flows-import-note { color: var(--label-color); }

/* ML-192 - Security (review of the OMR service). Cards, tiles, run rows and badges are the shared
   admin ones; these add the two statuses a security check has that a back-test doesn't (warn, info),
   the check row's title/badge line (not clickable - unlike .admin-test-case-head), and the native
   <details> disclosure used for evidence and history (keyboard/screen-reader behaviour for free). */
.admin-badge.warn { background: var(--status-amber-bg); color: var(--status-amber-fg); }
.admin-badge.info { background: var(--status-blue-bg); color: var(--status-blue-fg); }
.admin-security-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: var(--space-5); }
.admin-security-toolbar .btn-submit { width: auto; flex: 0 0 auto; padding-left: var(--space-5); padding-right: var(--space-5); }
.admin-security-head { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
/* display: list-item (the default) keeps the disclosure triangle - display:flex would drop it. */
.admin-security-details summary { display: list-item; min-height: var(--touch-target); box-sizing: border-box; padding: var(--space-3) 0; cursor: pointer; font-size: var(--font-sm); font-weight: var(--font-weight-semibold); color: var(--info-text); }
.admin-security-evidence { margin: var(--space-1) 0 var(--space-2) 0; padding-left: var(--space-5); font-size: var(--font-xs); color: var(--text-color); word-break: break-word; }
.admin-security-evidence li { margin-bottom: var(--space-1); }

/* ML-198 - Design (read-only design-system catalogue, admin-design.js). Page chrome only - every
   example inside .admin-design-stage is rendered with the real app classes, untouched. */
.admin-design-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-4); }
.admin-design-theme { margin-bottom: 0; min-width: 200px; }
.admin-design-toggle { display: flex; align-items: center; gap: var(--space-3); margin: 0; font-weight: var(--font-weight-semibold); }
.admin-design-jumps { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-bottom: var(--space-5); }
.admin-design-jump { margin-bottom: 0; }
.admin-design-group { margin: var(--space-8) 0 var(--space-3); padding-bottom: var(--space-2); border-bottom: 2px solid var(--primary-action-strong); color: var(--text-color); }
.admin-design-subhead { margin: var(--space-7) 0 var(--space-3); color: var(--text-color); }
.admin-design-minihead { margin: var(--space-5) 0 var(--space-2); color: var(--label-color); font-size: var(--font-sm); }
.admin-design-section { border: 1px solid var(--input-border); border-radius: var(--radius-md); padding: var(--space-5); margin-bottom: var(--space-5); background: var(--container-bg); }
.admin-design-section-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-3); }
.admin-design-section-head h3 { margin: 0; color: var(--text-color); }
.admin-design-section-head code, .admin-design-annotation code { font-family: var(--font-mono); font-size: var(--font-xs); color: var(--label-color); }
.admin-design-example { padding: var(--space-4) 0; border-top: 1px dashed var(--input-border); }
.admin-design-example:first-of-type { border-top: none; }
.admin-design-example-label { font-size: var(--font-sm); font-weight: var(--font-weight-semibold); color: var(--label-color); margin-bottom: var(--space-2); }
/* App components are built for the 500px app column - show them at that width. */
.admin-design-stage { max-width: var(--app-max-width); padding: var(--space-4); border-radius: var(--radius-sm); background: var(--bg-color); color: var(--text-color); }
.admin-design-stage-wide { max-width: none; }
.admin-design-annotations { display: flex; flex-direction: column; gap: var(--space-1); margin-top: var(--space-2); }
.admin-design-annotation { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }
.admin-design-chip { font-size: var(--font-xs); padding: var(--space-0-5) var(--space-2); border-radius: var(--radius-pill); background: var(--input-bg); border: 1px solid var(--input-border); color: var(--text-color); }
.admin-design-chip b { color: var(--label-color); font-weight: var(--font-weight-semibold); }
.admin-design-chip-warn { background: var(--danger-tint); border-color: var(--danger-text); }
/* What's new (design sign-off): public/design-new.json from npm run design-gate marks every example
   that uses a new class; "Only what's new" hides the rest, so the owner reviews pictures. */
.admin-design-new-panel { border: 2px solid var(--primary-action-strong); border-radius: var(--radius-md); padding: var(--space-5); margin-bottom: var(--space-5); background: var(--container-bg); }
.admin-design-new-title { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-2); color: var(--text-color); }
.admin-design-new-badge { display: inline-block; padding: var(--space-0-5) var(--space-2); margin-right: var(--space-1); border-radius: var(--radius-pill); background: var(--primary-action); color: var(--primary-action-text); font-size: var(--font-xs); font-weight: var(--font-weight-bold); vertical-align: middle; }
.admin-design-new-classes { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-bottom: var(--space-2); }
.admin-design-new-classes code { font-family: var(--font-mono); font-size: var(--font-xs); padding: var(--space-0-5) var(--space-2); border-radius: var(--radius-pill); background: var(--input-bg); border: 1px solid var(--input-border); color: var(--text-color); }
.admin-design-new-swatch { display: inline-block; width: var(--space-6); height: var(--space-6); border-radius: var(--radius-sm); border: 1px solid var(--input-border); background: var(--sample); }
.admin-design-example.admin-design-is-new { border-left: 3px solid var(--primary-action-strong); padding-left: var(--space-3); }
.admin-design-only-new :is(.admin-design-foundations, .admin-design-jumps, .admin-design-group-wrap:not(.admin-design-is-new), .admin-design-section:not(.admin-design-is-new), .admin-design-example:not(.admin-design-is-new)) { display: none; }
.admin-design-show-spacing .admin-design-measured { outline: 1px dashed var(--info-text); outline-offset: 0; }
.admin-design-show-spacing .admin-design-stage * { outline: 1px dotted var(--info-tint); }

/* ML-210 overlays: every tap target (and its invisible 44px hit area), and the keyboard focus ring. */
.admin-design-show-targets .admin-design-stage :is(button, a[href], input, select, textarea, [role="button"], [role="slider"]) { outline: 1px dashed var(--info-text); }
.admin-design-show-targets .admin-design-stage :is(button, [role="button"])::before { outline: 1px dashed var(--danger-text); }
.admin-design-show-focus .admin-design-stage :is(button, a[href], input, select, textarea, [role="button"], [role="slider"]) { box-shadow: var(--focus-ring); }

/* Overlays render in place here rather than floating over the page. */
.admin-design-static .modal { position: relative; inset: auto; display: flex; z-index: auto; padding: var(--space-6) var(--space-4); border-radius: var(--radius-sm); }
.admin-design-static .toast { position: relative; left: auto; bottom: auto; transform: none; display: inline-flex; z-index: auto; }
.admin-design-static .dropdown-menu { position: relative; top: auto; right: auto; z-index: auto; max-width: 240px; }
.admin-design-static .dropdown-menu.nav-menu { position: static; }
/* The phone-width admin head row, shown at desktop width - the same rules as the 700px media query. */
.admin-design-phone .admin-sidebar-head { display: flex; align-items: center; justify-content: space-between; }
.admin-design-phone .admin-sidebar-title { padding: 0; }
.admin-design-phone .admin-sidebar-current { display: inline; }
.admin-design-phone .admin-nav-toggle { display: flex; }
.admin-design-static .anchored-popup { position: relative; display: inline-block; z-index: auto; }
.admin-design-static .splash-screen { position: relative; inset: auto; z-index: auto; min-height: 260px; border-radius: var(--radius-sm); }
.admin-design-static .splash-login-btn { display: block; }
.admin-design-static .top-bar-sticky-group { position: relative; z-index: auto; }
.admin-design-relative { position: relative; min-height: var(--touch-target); }
.admin-design-badge-host { display: inline-block; min-height: 0; width: var(--space-6); height: var(--space-6); }
.admin-design-sidebar { max-width: 220px; background: var(--container-bg); border: 1px solid var(--input-border); border-radius: var(--radius-sm); }
.admin-design-dots .metro-tier { margin-left: var(--space-4); margin-right: var(--space-4); }
.admin-design-bars { display: flex; align-items: flex-end; gap: var(--space-2); height: 120px; }
.admin-design-bars .chart-bar { width: var(--space-7); }
.admin-design-bars .admin-design-bar-slot { height: 100%; min-width: 0; width: var(--space-7); margin: 0; cursor: default; } /* a stacked projected bar in the bar-colour row */

/* Foundations */
.admin-design-swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--space-3); }
.admin-design-swatch { border: 1px solid var(--input-border); border-radius: var(--radius-sm); overflow: hidden; background: var(--container-bg); }
/* Token tables: each row's token arrives as --sample (admin-design.js) and the sample class applies it. */
.admin-design-swatch-color { background: var(--sample); height: 56px; border-bottom: 1px solid var(--input-border); }
.admin-design-swatch-label { display: flex; flex-direction: column; gap: var(--space-0-5); padding: var(--space-2); font-size: var(--font-xs); color: var(--text-color); }
.admin-design-swatch-label code { font-family: var(--font-mono); font-weight: var(--font-weight-bold); }
.admin-design-swatch-label small, .admin-design-shadow small { color: var(--label-color); }
.admin-design-token-value { font-family: var(--font-mono); font-size: var(--font-xs); color: var(--label-color); }
.admin-design-table td { text-align: left; white-space: normal; vertical-align: middle; }
.admin-design-table code { font-family: var(--font-mono); }
.admin-design-sample-size { font-size: var(--sample); }
.admin-design-sample-weight { font-weight: var(--sample); }
.admin-design-sample-family { font-family: var(--sample); }
.admin-design-space-bar { width: var(--sample); display: inline-block; height: var(--space-3); background: var(--primary-action); border-radius: var(--radius-2xs); }
.admin-design-leading { line-height: var(--sample); display: inline-block; font-size: var(--font-sm); background: var(--primary-action-tint); }
.admin-design-shape { border-radius: var(--sample); display: flex; flex-direction: column; justify-content: center; gap: var(--space-1); min-height: 90px; padding: var(--space-3); background: var(--input-bg); border: 2px solid var(--primary-action-strong); font-size: var(--font-xs); }
.admin-design-shadow { box-shadow: var(--sample); display: flex; flex-direction: column; justify-content: center; gap: var(--space-1); min-height: 90px; padding: var(--space-3); background: var(--container-bg); border-radius: var(--radius-sm); font-size: var(--font-xs); }
.admin-design-motion-track { position: relative; display: inline-block; width: 160px; height: var(--space-4); border-radius: var(--radius-pill); background: var(--input-bg); border: 1px solid var(--input-border); }
.admin-design-motion-dot { transition-duration: var(--sample); position: absolute; top: 50%; left: 0; width: var(--space-3); height: var(--space-3); border-radius: var(--radius-circle); background: var(--primary-action); transform: translate(0, -50%); transition-property: left; transition-timing-function: var(--ease-standard); }
.admin-design-table tr:hover .admin-design-motion-dot, .admin-design-table tr:active .admin-design-motion-dot { left: calc(100% - var(--space-3)); }
.admin-design-probe { color: var(--probe-color); box-shadow: var(--probe-shadow); } /* hidden; resolves token values for the annotations */

/* ML-345: Admin -> Feature access - see specs/components/admin-feature-access.md. The grid (every
   account type) reuses .admin-stat-table inside .admin-stat-table-wrap (it scrolls sideways on a narrow
   screen, the feature column staying put); the one-type view is a list of switch rows. */
.admin-access-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: var(--space-4); }
.admin-access-table th, .admin-access-table td { text-align: center; vertical-align: middle; }
.admin-access-table th[scope="row"] { position: sticky; left: 0; z-index: var(--z-sticky); text-align: left; white-space: normal; min-width: 200px; background: var(--container-bg); font-weight: var(--font-weight-normal); color: var(--text-color); }
.admin-access-table th[scope="row"] small, .admin-access-row small { display: block; color: var(--label-color); font-size: var(--font-xs); }
.admin-access-group th { text-align: left; background: var(--input-bg); color: var(--label-color); font-weight: var(--font-weight-bold); }
.admin-access-live { border-right: 1px solid var(--input-border); }
.admin-access-cell { display: inline-grid; place-items: center; width: var(--touch-target); height: var(--touch-target); border-radius: var(--radius-sm); cursor: pointer; }
.admin-access-cell input { width: var(--icon-md); height: var(--icon-md); accent-color: var(--primary-action); cursor: pointer; }
.admin-access-cell, .admin-access-row { border: 2px solid transparent; }
.admin-access-cell.is-changed, .admin-access-row.is-changed { border-color: var(--primary-action); }
/* ML-383: a limit - a number per account type (Limits group). Changed = the same gold outline as a changed cell */
.admin-access-limit { width: 5.5em; min-height: var(--touch-target); box-sizing: border-box; padding: var(--space-1) var(--space-2); font: inherit; text-align: right; color: var(--text-color); background: var(--input-bg); border: 1px solid var(--control-border); border-radius: var(--radius-sm); }
.admin-access-limit.is-changed { border: 2px solid var(--primary-action); }
.admin-access-copy { display: block; margin: var(--space-1) auto 0; font-size: var(--font-xs); font-weight: var(--font-weight-normal); }
.admin-access-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-2); border-bottom: 1px solid var(--input-border); border-radius: var(--radius-sm); }
.admin-access-savebar { position: sticky; bottom: var(--space-3); z-index: var(--z-float); display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-4); padding: var(--space-3) var(--space-4); background: var(--container-bg); border: 1px solid var(--input-border); border-radius: var(--radius-md); box-shadow: var(--shadow-md); }
.admin-access-toolbar select { width: auto; max-width: 100%; margin: 0; }
/* The catalog's descriptions are long - two lines here, the whole text on hover (title) and on Features. */
.admin-access-table th[scope="row"] small, .admin-access-row small { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; }

/* ML-443: Admin -> Business case (specs/components/admin-business-case.md). The page is built from the panel's
   own pieces - stat tiles, tables, the Save bar, switches, value boxes that open a pop-up. Only what is new
   to it is here. Like the other table pages it uses the window's width; its reading text keeps 900px. */
.admin-content:has(> #business-case-section:not(.hidden-group)) { max-width: none; }
#business-case-section .admin-intro, #business-case-section .admin-feature, #business-case-section .admin-stat-tiles { max-width: 900px; }
/* The plan's settings: a row of value boxes (launch, years, the dollar rate, how it is counted) */
.admin-bc-settings { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-3); max-width: 900px; margin-bottom: var(--space-5); }
.admin-bc-settings .metroBlk-ctrl-value-btn { width: 100%; }
/* A scenario at a glance - a button, because it opens the scenario. The one the owner is in now has a gold edge
   as well as saying so. */
.admin-bc-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-4); }
.admin-bc-card { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; min-height: var(--touch-target); padding: var(--space-4); text-align: left; font-family: var(--font-sans); color: var(--text-color); background: var(--input-bg); border: 1px solid var(--control-border); border-radius: var(--radius-md); cursor: pointer; }
.admin-bc-card.is-current { border-color: var(--primary-action-strong); }
.admin-bc-card-name { font-size: var(--font-sm); font-weight: var(--font-weight-semibold); color: var(--label-color); }
.admin-bc-card-value { font-size: var(--font-xl); font-weight: var(--font-weight-bold); font-variant-numeric: tabular-nums; }
.admin-bc-card-line { font-size: var(--font-sm); color: var(--label-color); }
/* A result that is up or down: green or red text, and always a plus or minus sign as well */
.admin-bc-good, .admin-bc-table td.admin-bc-good { color: var(--success-text); }
.admin-bc-bad, .admin-bc-table td.admin-bc-bad { color: var(--danger-text); }
/* A heading with something to its right (a scenario's name and its menu; the chart's title and its picker) */
.admin-bc-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-3); max-width: 900px; margin-bottom: var(--space-3); }
.admin-bc-head > div { flex: 1 1 calc(var(--touch-target) * 5); min-width: 0; }
.admin-bc-head h2 { margin: 0 0 var(--space-2) 0; font-size: var(--font-lg); color: var(--text-color); }
.admin-bc-head .admin-intro { margin: 0; }
/* The page's tables: words read from the left and wrap; a group row, a total row, and a cost that is left out */
.admin-bc-table th, .admin-bc-table td { vertical-align: middle; }
.admin-bc-table .admin-bc-text { text-align: left; white-space: normal; min-width: 180px; }
.admin-bc-table tbody th { font-weight: var(--font-weight-semibold); color: var(--text-color); }
.admin-bc-table small { display: block; max-width: 60ch; margin-top: var(--space-0-5); color: var(--label-color); font-size: var(--font-xs); font-weight: var(--font-weight-normal); }
.admin-bc-table small a { color: var(--info-text); }
.admin-bc-group th, .admin-bc-group td { text-align: left; background: var(--input-bg); color: var(--label-color); font-weight: var(--font-weight-bold); }
.admin-bc-group td { text-align: right; }
.admin-bc-total th, .admin-bc-total td { font-weight: var(--font-weight-bold); color: var(--text-color); background: var(--input-bg); }
.admin-bc-table .admin-bc-off th, .admin-bc-table .admin-bc-off td { color: var(--label-color); }
/* A row of small labelled number boxes (members by year, a price, a share) */
.admin-bc-fields { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3) var(--space-4); max-width: 900px; margin: var(--space-3) 0; }
.admin-bc-field { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; font-size: var(--font-sm); font-weight: var(--font-weight-semibold); color: var(--label-color); }
.admin-bc-num { width: 7em; min-height: var(--touch-target); box-sizing: border-box; margin: 0; padding: var(--space-1) var(--space-2); font: inherit; font-weight: var(--font-weight-normal); font-variant-numeric: tabular-nums; text-align: right; color: var(--text-color); background: var(--input-bg); border: 1px solid var(--control-border); border-radius: var(--radius-sm); }
/* One kind of income: its switch, its name, what it comes to, then its figures */
.admin-bc-income { max-width: 900px; box-sizing: border-box; margin-bottom: var(--space-3); padding: var(--space-3) var(--space-4); background: var(--container-bg); border: 1px solid var(--input-border); border-radius: var(--radius-md); }
.admin-bc-income-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: var(--space-2); }
.admin-bc-income-head strong { flex: 1; min-width: 0; color: var(--text-color); }
.admin-bc-income-head span { font-size: var(--font-sm); color: var(--label-color); }
.admin-bc-income .admin-intro { margin: 0; }
.admin-bc-income.admin-bc-off .admin-bc-fields { opacity: var(--opacity-muted); }
/* The chart: every scenario's running total, month by month. The chosen scenario is the thick gold line; the
   others are thin grey lines numbered at the end. Its numbers are in the table under it. */
.admin-bc-chart-card { position: relative; max-width: 1100px; box-sizing: border-box; margin-bottom: var(--space-5); padding: var(--space-4); background: var(--container-bg); border: 1px solid var(--input-border); border-radius: var(--radius-md); }
.admin-bc-chart-card .admin-bc-head { max-width: none; }
.admin-bc-chart-host { position: relative; }
.admin-bc-chart { display: block; max-width: 100%; height: auto; }
.admin-bc-chart text { font-family: var(--font-sans); font-size: var(--font-xs); fill: var(--label-color); font-variant-numeric: tabular-nums; }
.admin-bc-chart .admin-bc-chart-end { fill: var(--text-color); font-weight: var(--font-weight-semibold); }
.admin-bc-chart-grid { stroke: var(--input-border); stroke-width: 1px; }
.admin-bc-chart-zero { stroke: var(--control-border); stroke-width: 1px; }
.admin-bc-chart-other { fill: none; stroke: var(--label-color); stroke-width: 1px; }
.admin-bc-chart-line { fill: none; stroke: var(--primary-action-strong); stroke-width: 3px; stroke-linejoin: round; stroke-linecap: round; }
.admin-bc-chart-dot { fill: var(--primary-action-strong); stroke: var(--container-bg); stroke-width: 2px; }
/* What the chart says at the month under the pointer; placed by --tip-x / --tip-y (set as it moves) */
.admin-bc-chart-tip { position: absolute; left: var(--tip-x); top: var(--tip-y); z-index: var(--z-raised); min-width: 170px; padding: var(--space-2) var(--space-3); pointer-events: none; font-size: var(--font-sm); color: var(--text-color); background: var(--container-bg); border: 1px solid var(--input-border); border-radius: var(--radius-sm); box-shadow: var(--shadow-md); }
.admin-bc-chart-tip-row { display: flex; justify-content: space-between; gap: var(--space-4); color: var(--label-color); }
.admin-bc-chart-tip-row strong { color: var(--text-color); font-variant-numeric: tabular-nums; }

/* ML-443: the Dashboard - the page the panel opens on. Its boxes are the stat tiles as buttons (each
   opens the page behind it), and "Needs you" is a list of rows that do the same. */
.admin-dash-tile { width: 100%; box-sizing: border-box; font-family: var(--font-sans); text-align: left; cursor: pointer; }
.admin-dash-tile:hover { border-color: var(--control-border); }
#dashboard-section .admin-stat-section-title:first-child { margin-top: var(--space-4); }
.admin-dash-need { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--touch-target); box-sizing: border-box; padding: var(--space-3) var(--space-4); background: var(--container-bg); border: none; border-bottom: 1px solid var(--input-border); font-family: var(--font-sans); font-size: var(--font-base); color: var(--text-color); text-align: left; cursor: pointer; }
.admin-dash-need:last-child { border-bottom: none; }
.admin-dash-need:hover { background: var(--input-bg); }
.admin-dash-need .admin-badge { flex-shrink: 0; }
.admin-dash-need-text { flex: 1; min-width: 0; }

/* ML-515 - usage bar (specs/components/usage-bar.md): how much of a limit is used. The track is the limit,
   the fill is what is used (--bar-w, set by the renderer), and the fill's colour says whether that is fine,
   getting near or nearly full. The words beside it say the same, so colour is never the only signal. */
.usage-meter { display: flex; flex-direction: column; gap: var(--space-1); min-width: calc(var(--space-10) * 2); }
.usage-bar { display: block; box-sizing: border-box; width: 100%; height: var(--space-3); border: 1px solid var(--control-border); border-radius: var(--radius-pill); background: var(--container-bg); overflow: hidden; }
.usage-bar-fill { display: block; width: var(--bar-w); min-width: var(--space-1); max-width: 100%; height: 100%; background: var(--meter-ok); }
.usage-bar.is-near .usage-bar-fill { background: var(--meter-near); }
.usage-bar.is-full .usage-bar-fill { background: var(--meter-full); }
.usage-meter-text { font-size: var(--font-sm); color: var(--label-color); }
.admin-stat-tile .usage-meter { order: 2; margin-top: var(--space-2); min-width: 0; }
.admin-stat-table .usage-meter { margin-top: var(--space-1); } /* clear of the amount written above it */
