/*
 * Admin v2 presentation layer — Phase 4 (#520).
 *
 * Every selector is under `.spruce-admin.spruce-admin--v2`. Without the
 * `--v2` body marker this file is completely inert (plan §5.4 / Phase 4 D2).
 *
 * `!important` appears ONLY where a rule competes with a Bootstrap 4 utility
 * that is itself `!important` in the compiled admin.css (`.bg-primary`,
 * `.text-*` color utilities, `.float-right`, `.font-13`,
 * `.font-weight-*`) — specificity cannot beat those. Each use is commented.
 */

/* =========================================================================
 * 1. Base admin surface (migrated pages only)
 *
 * CONTENT CONTEXTS: the base surface must reach every place migrated page
 * content renders — not just the main column. Unpoly (`up-modal`, used by
 * 10 admin templates) and Bootstrap (`.modal`) append their overlays to
 * <body>, OUTSIDE `.sa-main`, so `.sa-main`-only rules stopped at the modal
 * boundary: order details rendered with the new fonts on its own page and
 * the legacy fonts in the modal (Bruce, staging 2026-07-23). Keep this
 * selector list in sync with any new overlay container.
 * ========================================================================= */

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) {
  font-family: var(--font-body);
  font-size: var(--text-md);
  color: var(--text-body);
  line-height: var(--leading-normal);
}

.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  :is(h1, h2, h3, h4, h5, h6) {
  font-family: var(--font-display);
  color: var(--text-heading);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a {
  color: var(--text-link);
  text-decoration: none;
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a:hover {
  color: var(--green-700);
  text-decoration: underline;
}

/* Buttons and badges are anchors too — keep them underline-free on hover */
.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  a:is(.btn, .badge):hover {
  text-decoration: none;
}

.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  :is(a, button, input, select, textarea, .btn):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Inline code — shared AdminV2 contract (#589).
   Design: contract §1.3 mono role (IDs/codes/plates) + design/index.html
   `.note code` / guidelines/type-mono (Roboto Mono at body text color).
   Hyper sets `$code-color: $cyan` (#39afd1); override with tokens only.
   Related elements: only the nested-in-link companion below — `kbd`/`pre`/
   `samp` use different Bootstrap variables and are out of this narrow fix. */
.spruce-admin.spruce-admin--v2 code {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-body);
}

/* Nested in links: Bootstrap's `a > code { color: inherit }` is (0,0,2)
   and loses to the bare-code rule above (0,2,1). Restate inherit under the
   content contexts so linked code keeps the `.sa-main a` link color
   (cookbook `.sa-main a` trap) rather than `--text-body`. */
.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  a
  code {
  color: inherit;
}

/* Hyper's .content wrapper padding — shell .sa-main owns page gutters */
.spruce-admin.spruce-admin--v2 .content {
  padding: 0;
}

/* =========================================================================
 * 2. Bootstrap/Hyper compatibility mappings (dashboard contract, D6)
 * ========================================================================= */

/* PageHeader — page-title-box.
   Laid out as a flex row (design PageHeader): Hyper floats
   `.page-title-right` with `margin-top: 25px`, a value sized for the 85px
   `line-height` this mapping removes — the float then dropped into the gap
   between the title and the page content, colliding with the first card
   (Bruce, staging 2026-07-23). The markup emits `.page-title-right` BEFORE
   the `<h1>`, so `order` restores the visual sequence. */
.spruce-admin.spruce-admin--v2 .page-title-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  line-height: normal;
}

.spruce-admin.spruce-admin--v2 .page-title-box .page-title {
  order: 0;
}

.spruce-admin.spruce-admin--v2 .page-title-box .page-title-right {
  order: 1;
  float: none;
  margin-top: 0;
  margin-left: auto;
}

/* Only the title and the actions belong on the header row. Several flipped
   templates put block content INSIDE .page-title-box after the <h1> (tips
   on invitation :new, compare form/results copy and badge rows, the
   revenue-breakdown warning alert, membership resend status) — without
   this, flex pulls that content up beside the title (Grok review, PR #558).
   Everything else spans the full width below the header row. */
.spruce-admin.spruce-admin--v2 .page-title-box > :not(.page-title):not(.page-title-right) {
  flex-basis: 100%;
  order: 2;
}

/* The last control in the header row sits flush with the content edge; BS4
   spacing utilities (`.mr-2` on the programme dropdown) are `!important`. */
.spruce-admin.spruce-admin--v2 .page-title-right .form-inline > *:last-child {
  margin-right: 0 !important;
}

/* PageHeader title — page-title */
.spruce-admin.spruce-admin--v2 .page-title {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: 700;
  color: var(--text-heading);
  line-height: var(--leading-tight);
}

/* Card / StatCard — .card */
.spruce-admin.spruce-admin--v2 .card {
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  margin-bottom: var(--space-4);
}

/* Card body padding — Bootstrap .card-body; Materialize leftover
   .card > .card-content (renewal invitation index, Phase 7 batch 9 #523).
   Design Card.jsx body: padding 20px → --space-5. */
.spruce-admin.spruce-admin--v2 .card-body,
.spruce-admin.spruce-admin--v2 .card > .card-content {
  padding: var(--space-5);
}

/* PanelCard label — .card .header-title */
.spruce-admin.spruce-admin--v2 .card .header-title {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.045em;
  color: var(--text-muted);
}

/* brand PanelCard — .card.bg-primary
   (!important: BS4's `.bg-primary{background-color:…!important}` utility) */
.spruce-admin.spruce-admin--v2 .card.bg-primary {
  background-color: var(--brand) !important;
  border: none;
  color: var(--text-on-brand);
}

.spruce-admin.spruce-admin--v2 .card.bg-primary .header-title {
  color: rgba(255, 255, 255, 0.9);
}

/* !important: `.text-muted-primary` / `.text-white` are !important utilities */
.spruce-admin.spruce-admin--v2 .card.bg-primary .text-muted-primary,
.spruce-admin.spruce-admin--v2 .card.bg-primary .text-white {
  color: var(--text-on-brand) !important;
}

/* The brand panel's header carries BOTH header-title and text-white; the
   PanelCard label contract (90% white) must beat the text-white override
   above — higher specificity, same sanctioned !important. */
.spruce-admin.spruce-admin--v2 .card.bg-primary .header-title.text-white {
  color: rgba(255, 255, 255, 0.9) !important;
}

/* ghost-on-brand button — .card.bg-primary .btn.btn-outline-light */
.spruce-admin.spruce-admin--v2 .card.bg-primary .btn.btn-outline-light {
  border: 1px solid rgba(255, 255, 255, 0.5);
  color: #ffffff;
  background: transparent;
  border-radius: var(--radius-sm);
  transition: background-color var(--transition-fast), border-color var(--transition-fast),
    color var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 .card.bg-primary .btn.btn-outline-light:hover {
  background: rgba(255, 255, 255, 0.12);
  color: #ffffff;
}

/* StatCard value — pod h3
   (!important on weight: pod h3s carry `.font-weight-normal{400!important}`) */
.spruce-admin.spruce-admin--v2 .card h3 {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: 700 !important;
  color: var(--text-heading);
}

.spruce-admin.spruce-admin--v2 .card.bg-primary h3 {
  color: #ffffff;
}

/* PanelMetric caption — .font-13.text-uppercase
   (!important: `.font-13{font-size:13px!important}` and Hyper's
   `.font-weight-bold{font-weight:600!important}` utilities) */
.spruce-admin.spruce-admin--v2 .font-13.text-uppercase {
  font-size: var(--text-xs) !important;
  font-weight: 700 !important;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.spruce-admin.spruce-admin--v2 .card.bg-primary .font-13.text-uppercase {
  color: rgba(255, 255, 255, 0.82) !important;
}

/* PanelRow — .chart-widget-list p */
.spruce-admin.spruce-admin--v2 .chart-widget-list p {
  display: flex;
  gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid var(--border-default);
  font-size: 14px;
  margin-bottom: 0;
}

.spruce-admin.spruce-admin--v2 .chart-widget-list p:last-child {
  border-bottom: none;
}

/* PanelRow value — .chart-widget-list p .float-right
   (!important on float: `.float-right{float:right!important}` utility) */
.spruce-admin.spruce-admin--v2 .chart-widget-list p .float-right {
  float: none !important;
  margin-left: auto;
  font-weight: 600;
  color: var(--text-heading);
}

/* !important on all four: BS4 `.text-*` color utilities are all !important */
.spruce-admin.spruce-admin--v2 .text-muted {
  color: var(--text-muted) !important;
}

.spruce-admin.spruce-admin--v2 .text-success {
  color: var(--success) !important;
}

.spruce-admin.spruce-admin--v2 .text-danger {
  color: var(--danger) !important;
}

.spruce-admin.spruce-admin--v2 .text-info {
  color: var(--info) !important;
}

/* design primary Button — .btn.btn-primary */
.spruce-admin.spruce-admin--v2 .btn.btn-primary {
  background-color: var(--green-500);
  border-color: var(--green-500);
  color: #ffffff;
  font-weight: 600;
  border-radius: var(--radius-md);
  font-size: 14px;
  transition: background-color var(--transition-fast), border-color var(--transition-fast),
    box-shadow var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 .btn.btn-primary:hover {
  background-color: var(--green-600);
  border-color: var(--green-600);
  color: #ffffff;
}

.spruce-admin.spruce-admin--v2 .btn.btn-primary:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* design Badge — .badge + tone variants. Tones are `.sa-main`-qualified so
   an anchor badge keeps its tone colors against the `.sa-main a` base rule
   (same class count, extra element would otherwise win). */
.spruce-admin.spruce-admin--v2 .badge {
  border-radius: var(--radius-full);
  padding: 1px 10px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-success {
  background-color: var(--success-bg);
  color: var(--success);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-danger {
  background-color: var(--danger-bg);
  color: var(--danger);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-warning {
  background-color: var(--warning-bg);
  color: var(--warning);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-info {
  background-color: var(--info-bg);
  color: var(--info);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-primary {
  background-color: var(--brand-soft);
  color: var(--brand);
}

/* =========================================================================
 * 3. Batch 1 — account/profile/security contracts (#523, Phase 7)
 *
 * Contract census: templates/admin/admin_user_self_serve/* (dual-mounted at
 * /superadmin/me* and /:org/admin/me*). Design-reference citations per
 * mapping; contract values beat prototype drift (§5.6): control radius is
 * --radius-md 12px, not the prototype's 11px.
 * ========================================================================= */

/* =========================================================================
 * Bootstrap layout primitives (#690)
 *
 * admin_v2 skins Bootstrap class contracts (colours, borders, radii) but
 * historically relied on admin.css for their *layout*. root.html.heex does
 * not load Bootstrap; layout/admin.html.eex and layout/basic.html.eex do
 * (via css_link_tag(:admin) → /css/admin.css).
 *
 * ARCHITECTURE (GPT review, 2026-07-29): every rule below is scoped under
 * `.sa-no-bootstrap`, which ONLY root.html.heex emits. Legacy pages never
 * match these selectors, so they cannot defeat Bootstrap's contextual /
 * responsive / state / variant rules — by construction, not by value-
 * matching. Do NOT re-scope these under bare `.spruce-admin--v2`.
 *
 * basic.html.eex (admin login / MFA / forgot / reset password) must NOT
 * emit `.sa-no-bootstrap`. It loads admin.css, so the #690 "shim without
 * Bootstrap" condition does not apply. Adding the marker there would make
 * these (0,3,0) base copies defeat Bootstrap companions on the auth
 * surface — the exact regression the marker exists to prevent. Measured
 * 2026-07-29: login + forgot load admin.css + admin_v2, have no marker,
 * and Bootstrap geometry (row flex, form-group margin, form-control block)
 * is intact. (basic also omits admin_ui.css — documented §7.1/#515
 * isolated-legacy exception; that is unrelated to this marker.)
 *
 * Declarations probed from built priv/static/css/admin.css. Includes base
 * PLUS companions (input-group children, nav-pills padding, progress-sm,
 * open-modal overflow, 576px form-inline / modal-dialog). Detector:
 * admin_v2_bootstrap_layout_test.exs + e2e/18 + e2e/19.
 * ========================================================================= */

/* .nav — AdminUI.nav_tabs. Without flex, tabs stack under root. */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .nav {
  display: flex;
  flex-wrap: wrap;
  padding-left: 0;
  margin-bottom: 0;
  list-style: none;
}

/* Base .nav-link padding — required for :pills (nav-tabs skin overrides
   padding for the underline tabs variant). */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .nav-link {
  display: block;
  padding: 0.5rem 1rem;
}

/* Do NOT set .nav-pills .nav-link border-radius here — that is cosmetic,
   not layout. The design skin (.spruce-admin--v2 .nav-pills .nav-link)
   uses border-radius: var(--radius-sm) (8px); a Bootstrap 0.25rem copy at
   higher specificity was measured regressing root pills 8px → 4px. */

/* .pagination */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .pagination {
  display: flex;
  padding-left: 0;
  list-style: none;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .page-link {
  position: relative;
  display: block;
  padding: 0.5rem 0.75rem;
  margin-left: -1px;
  line-height: 1.25;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .page-item:first-child .page-link {
  margin-left: 0;
}

/* .dropdown */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .dropdown {
  position: relative;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .dropdown-menu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1000;
  display: none;
  float: left;
  min-width: 10rem;
  padding: 0.25rem 0;
  margin: 0.125rem 0 0;
  list-style: none;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .dropdown-menu.show {
  display: block;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .dropdown-menu-right {
  right: 0;
  left: auto;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .dropdown-item {
  display: block;
  width: 100%;
  padding: 0.375rem 1.5rem;
  clear: both;
  white-space: nowrap;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .dropdown-divider {
  height: 0;
  margin: 0.5rem 0;
  overflow: hidden;
}

/* .card — root LiveViews use sa-card; kept for any raw .card under root. */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .card {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .card-body,
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .card > .card-content {
  flex: 1 1 auto;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .card-header {
  margin-bottom: 0;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .card-title {
  margin-bottom: 0.75rem;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .badge {
  display: inline-block;
  white-space: nowrap;
  vertical-align: baseline;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .btn {
  display: inline-block;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  padding: 0.45rem 0.9rem;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .btn.btn-block {
  display: block;
  width: 100%;
}

/* Forms */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-group {
  margin-bottom: 1rem;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-control {
  display: block;
  width: 100%;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-check {
  position: relative;
  display: block;
  padding-left: 1.25rem;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-check-input {
  position: absolute;
  margin-top: 0.3rem;
  margin-left: -1.25rem;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-check-label {
  margin-bottom: 0;
}

/* Base: stacked checkbox inside .form-inline fills the row (<576px). */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-inline .form-check {
  width: 100%;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-inline {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
}

/* Bootstrap gates the auto-width override at sm+. Applying it unconditionally
   was the mobile regression on legacy; under sa-no-bootstrap we mirror the
   media query so root matches Bootstrap's breakpoint behaviour. */
@media (min-width: 576px) {
  .spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-inline .form-control {
    display: inline-block;
    width: auto;
    vertical-align: middle;
  }

  .spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-inline .form-group,
  .spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-inline .input-group {
    display: flex;
    flex: 0 0 auto;
    flex-flow: row wrap;
    align-items: center;
    margin-bottom: 0;
  }

  .spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-inline .form-check {
    display: flex;
    align-items: center;
    justify-content: center;
    width: auto;
    padding-left: 0;
  }

  .spruce-admin.spruce-admin--v2.sa-no-bootstrap .form-inline .form-check-input {
    position: relative;
    margin-top: 0;
    margin-right: 0.25rem;
    margin-left: 0;
  }
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .custom-control {
  position: relative;
  display: block;
  min-height: 1.425rem;
  padding-left: 1.5rem;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .custom-control-input {
  position: absolute;
  z-index: -1;
  opacity: 0;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .custom-control-label {
  position: relative;
  margin-bottom: 0;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .custom-control-label::before,
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .custom-control-label::after {
  position: absolute;
  top: 0.2125rem;
  left: -1.5rem;
  display: block;
  width: 1rem;
  height: 1rem;
  content: "";
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  width: 100%;
}

/* Companion: child control must flex, not take width:100% from .form-control */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group > .form-control,
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group > .custom-select,
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group > .custom-file {
  position: relative;
  flex: 1 1 auto;
  width: 1%;
  margin-bottom: 0;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group-prepend,
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group-append {
  display: flex;
}

/* Fuse append/prepend to the control (Bootstrap's -1px overlap). */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group-prepend {
  margin-right: -1px;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group-append {
  margin-left: -1px;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .input-group-text {
  display: flex;
  align-items: center;
  padding: 0.45rem 0.9rem;
  margin-bottom: 0;
  white-space: nowrap;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .alert {
  position: relative;
  margin-bottom: 1rem;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .table {
  width: 100%;
  margin-bottom: 1.5rem;
  /* no position:relative — #675 */
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .progress {
  display: flex;
  height: 1rem;
  overflow: hidden;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .progress-sm {
  height: 5px;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .progress-bar {
  display: flex;
  flex-direction: column;
  justify-content: center;
  white-space: nowrap;
}

/* Modal — resting + open-state companions */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1050;
  display: none;
  overflow: hidden;
}

/* body.modal-open is set by Bootstrap JS alongside the marker classes */
.spruce-admin.spruce-admin--v2.sa-no-bootstrap.modal-open .modal {
  overflow-x: hidden;
  overflow-y: auto;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-dialog {
  position: relative;
  width: auto;
  margin: 0.5rem;
  pointer-events: none;
}

@media (min-width: 576px) {
  .spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-dialog {
    max-width: 500px;
    margin: 1.75rem auto;
  }
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-content {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  pointer-events: auto;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-body {
  position: relative;
  flex: 1 1 auto;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-backdrop {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1040;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .close {
  float: right;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .modal-header .close {
  padding: 1rem;
  margin: -1rem -1rem -1rem auto;
}

.spruce-admin.spruce-admin--v2.sa-no-bootstrap .collapse:not(.show) {
  display: none;
}

/* Settings nav — design Tabs: underline style replaces Bootstrap's boxed
   tabs (border-bottom rail, 2px green active underline). */
.spruce-admin.spruce-admin--v2 .nav-tabs {
  border-bottom: 1px solid var(--border-default);
  gap: 4px;
}

.spruce-admin.spruce-admin--v2 .nav-tabs .nav-link {
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  border-radius: 0;
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 500;
  color: var(--stone-500);
  background: transparent;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .nav-tabs .nav-link:hover {
  color: var(--green-700);
  text-decoration: none;
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .nav-tabs .nav-link.active {
  color: var(--green-700);
  border-bottom-color: var(--green-500);
  background: transparent;
}

/* Field label — design Input Label: 13px/600 stone-700.
   :not(.form-check-label) — checkbox labels are body text (design Checkbox),
   and without the exclusion this rule's extra element selector (0,3,1) beats
   the .form-check-label mapping (0,3,0) below (Grok review, PR #549). */
.spruce-admin.spruce-admin--v2 .form-group label:not(.form-check-label),
.spruce-admin.spruce-admin--v2 .control-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--stone-700);
  margin-bottom: 6px;
}

/* FieldGroup legend — design FieldGroup.jsx: the agent-token scope chooser
   uses Bootstrap's `.h6` size utility on a legend rather than a label. Keep
   the selector narrow so ordinary `.h6` headings retain the shared heading
   ladder above. */
.spruce-admin.spruce-admin--v2 .form-group > legend.h6 {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--stone-700);
  padding: 0;
  margin: 0 0 var(--space-2);
  line-height: var(--leading-normal);
}

/* Text input / select — design Input: border-strong, contract radius-md,
   14px body text on card surface */
.spruce-admin.spruce-admin--v2 .form-control {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  font-size: 14px;
  font-family: var(--font-body);
  color: var(--stone-800);
  background-color: var(--surface-card);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 .form-control:focus {
  border-color: var(--border-focus);
  box-shadow: var(--focus-ring);
  color: var(--stone-800);
  background-color: var(--surface-card);
}

.spruce-admin.spruce-admin--v2 .form-control.is-invalid {
  border-color: var(--danger);
}

/* Checkbox — design Checkbox's green-500 checked state via accent-color
   (native rendering; the SVG-check custom control is Phase 5 work) */
.spruce-admin.spruce-admin--v2 .form-check-input {
  accent-color: var(--green-500);
}

.spruce-admin.spruce-admin--v2 .form-check-label {
  font-size: 14px;
  color: var(--stone-800);
}

/* Field hint / error — design Input Msg: 12px muted or danger */
.spruce-admin.spruce-admin--v2 .form-text {
  font-size: 12px;
  color: var(--text-muted);
}

.spruce-admin.spruce-admin--v2 .help-block {
  display: block;
  font-size: 12px;
  margin-top: 5px;
  color: var(--danger);
}

/* Button base — design Button geometry for every .btn variant on migrated
   pages (Phase 4 mapped only .btn-primary) */
.spruce-admin.spruce-admin--v2 .btn {
  border-radius: var(--radius-md);
  font-weight: 600;
  font-size: 14px;
  transition: background-color var(--transition-fast), border-color var(--transition-fast),
    color var(--transition-fast), box-shadow var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 .btn.btn-sm {
  border-radius: var(--radius-sm);
  font-size: 13px;
}

/* Secondary button — design Button secondary: card surface, border-strong,
   stone text, stone-100 hover (replaces both Bootstrap outline grays) */
.spruce-admin.spruce-admin--v2 .btn.btn-outline-secondary {
  background-color: var(--surface-card);
  border-color: var(--border-strong);
  color: var(--stone-700);
}

.spruce-admin.spruce-admin--v2 .btn.btn-outline-secondary:hover,
.spruce-admin.spruce-admin--v2 .btn.btn-outline-secondary:focus,
.spruce-admin.spruce-admin--v2 .btn.btn-outline-secondary:not(:disabled):active {
  background-color: var(--stone-100);
  border-color: var(--border-strong);
  color: var(--stone-700);
}

/* Outline-primary — green outline treatment aligned to brand tokens */
.spruce-admin.spruce-admin--v2 .btn.btn-outline-primary {
  background-color: transparent;
  border-color: var(--green-500);
  color: var(--green-600);
}

.spruce-admin.spruce-admin--v2 .btn.btn-outline-primary:hover,
.spruce-admin.spruce-admin--v2 .btn.btn-outline-primary:focus,
.spruce-admin.spruce-admin--v2 .btn.btn-outline-primary:not(:disabled):active {
  background-color: var(--brand-soft);
  border-color: var(--green-500);
  color: var(--green-700);
}

/* Outline-danger — status token alignment */
.spruce-admin.spruce-admin--v2 .btn.btn-outline-danger {
  border-color: var(--danger);
  color: var(--danger);
  background-color: transparent;
}

.spruce-admin.spruce-admin--v2 .btn.btn-outline-danger:hover,
.spruce-admin.spruce-admin--v2 .btn.btn-outline-danger:focus,
.spruce-admin.spruce-admin--v2 .btn.btn-outline-danger:not(:disabled):active {
  background-color: var(--danger);
  color: #ffffff;
}

/* Link-styled button — contract link colors (§1.9) */
.spruce-admin.spruce-admin--v2 .btn.btn-link {
  color: var(--text-link);
}

.spruce-admin.spruce-admin--v2 .btn.btn-link:hover {
  color: var(--green-700);
}

/* Alert — design Alert: tone wash bg, 25% tone border, radius-md */
.spruce-admin.spruce-admin--v2 .alert {
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font-size: 13px;
  color: var(--stone-700);
}

.spruce-admin.spruce-admin--v2 .alert-danger {
  background-color: var(--danger-bg);
  border: 1px solid color-mix(in srgb, var(--danger) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .alert-danger strong {
  color: var(--danger);
}

.spruce-admin.spruce-admin--v2 .alert-warning {
  background-color: var(--warning-bg);
  border: 1px solid color-mix(in srgb, var(--warning) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .alert-warning strong {
  color: var(--warning);
}

/* Hyper lighten badges — design Badge tones (badge base geometry mapped in
   §2; Hyper's badge-*-lighten rules are NOT !important, plain specificity
   wins here) */
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-success-lighten {
  background-color: var(--success-bg);
  color: var(--success);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-warning-lighten {
  background-color: var(--warning-bg);
  color: var(--warning);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-info-lighten {
  background-color: var(--info-bg);
  color: var(--info);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-secondary-lighten {
  background-color: var(--stone-100);
  color: var(--stone-600);
}

/* Tone/surface utilities used by the avatar chips and info boxes.
   !important on each: the competing Bootstrap 4 color/border/rounded
   utilities and Hyper's bg-*-lighten are themselves !important. */
.spruce-admin.spruce-admin--v2 .text-primary {
  color: var(--brand) !important;
}

.spruce-admin.spruce-admin--v2 .text-secondary {
  color: var(--stone-600) !important;
}

.spruce-admin.spruce-admin--v2 .bg-light {
  background-color: var(--stone-100) !important;
}

.spruce-admin.spruce-admin--v2 .bg-primary-lighten {
  background-color: var(--brand-soft) !important;
}

.spruce-admin.spruce-admin--v2 .bg-success-lighten {
  background-color: var(--success-bg) !important;
}

.spruce-admin.spruce-admin--v2 .border {
  border-color: var(--border-default) !important;
}

.spruce-admin.spruce-admin--v2 .border-top {
  border-top-color: var(--border-default) !important;
}

.spruce-admin.spruce-admin--v2 .border-left {
  border-left-color: var(--border-default) !important;
}

.spruce-admin.spruce-admin--v2 .rounded {
  border-radius: var(--radius-sm) !important;
}

/* Heading-size utilities on card/section headings — token ladder */
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .h5 {
  font-size: var(--text-lg);
  font-weight: 600;
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .h4 {
  font-size: var(--text-xl);
}

/* =========================================================================
 * 4. Shared contracts — cross-family clusters (#523, Phase 7 batch 2)
 *
 * Mapped centrally so family batches only add family-specific leftovers
 * (cookbook §"Shared contract clusters"). These rules are inert until a
 * consuming family is allowlisted. JS state classes (collapse/fade/show,
 * progress-bar-striped/animated — they compose over mapped kin) and pure
 * geometry (form-inline, table-responsive, btn-block, list-unstyled,
 * dropdown-menu-right/left, rounded-circle, border-0) take :state_only /
 * :structure_only triage entries in consuming families, not mappings.
 * ========================================================================= */

/* Table — design Table.jsx: 13px body on card surface, 12px/600 muted
   headers on sunken surface, hairline rows, sunken row hover */
.spruce-admin.spruce-admin--v2 .table {
  font-size: var(--text-sm);
  color: var(--stone-700);
  background: var(--surface-card);
}

.spruce-admin.spruce-admin--v2 .table thead th {
  background: var(--surface-sunken);
  color: var(--stone-600);
  font-weight: 600;
  font-size: 12px;
  border-bottom: 1px solid var(--border-default);
  border-top: none;
}

.spruce-admin.spruce-admin--v2 .table td,
.spruce-admin.spruce-admin--v2 .table th {
  border-top: none;
  border-bottom: 1px solid var(--border-default);
  font-variant-numeric: tabular-nums;
}

.spruce-admin.spruce-admin--v2 .table tbody tr:last-child td {
  border-bottom: none;
}

.spruce-admin.spruce-admin--v2 .table-hover tbody tr:hover {
  background-color: var(--surface-sunken);
  color: var(--stone-700);
}

.spruce-admin.spruce-admin--v2 .table-striped tbody tr:nth-of-type(odd) {
  background-color: var(--stone-50);
}

.spruce-admin.spruce-admin--v2 .table-bordered,
.spruce-admin.spruce-admin--v2 .table-bordered td,
.spruce-admin.spruce-admin--v2 .table-bordered th {
  border-color: var(--border-default);
}

/* Card sections — design Card.jsx: hairline-separated header, display title */
.spruce-admin.spruce-admin--v2 .card-header {
  background-color: var(--surface-card);
  border-bottom: 1px solid var(--border-default);
}

.spruce-admin.spruce-admin--v2 .card-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-lg);
  color: var(--text-heading);
}

.spruce-admin.spruce-admin--v2 .card-text {
  color: var(--text-body);
}

/* Pagination — secondary-button chips, brand active (design core buttons) */
/* The extra `.sa-main a` variant out-ranks the base-surface anchor rule
   (`.sa-main a` carries an element selector that would otherwise win —
   codex review, PR #550) */
.spruce-admin.spruce-admin--v2 .page-link,
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.page-link {
  color: var(--stone-700);
  border-color: var(--border-default);
  font-size: var(--text-sm);
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.page-link:hover {
  background-color: var(--surface-sunken);
  color: var(--stone-700);
  text-decoration: none;
}

.spruce-admin.spruce-admin--v2 .page-item.active .page-link {
  background-color: var(--brand);
  border-color: var(--brand);
  color: var(--text-on-brand);
}

.spruce-admin.spruce-admin--v2 .page-item.disabled .page-link {
  color: var(--stone-400);
  border-color: var(--border-default);
}

.spruce-admin.spruce-admin--v2 .page-item:first-child .page-link {
  border-top-left-radius: var(--radius-sm);
  border-bottom-left-radius: var(--radius-sm);
}

.spruce-admin.spruce-admin--v2 .page-item:last-child .page-link {
  border-top-right-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
}

.spruce-admin.spruce-admin--v2 .page-link:focus {
  box-shadow: var(--focus-ring);
}

/* Modal — design Modal.jsx: radius-lg, shadow-lg, display title (contract
   ladder --text-xl, not the prototype's off-ladder 19px), stone-900 scrim
   (Bootstrap applies opacity .5 to .modal-backdrop, matching the contract's
   rgba(33,31,28,.5)) */
.spruce-admin.spruce-admin--v2 .modal-content {
  border: none;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  background: var(--surface-card);
}

.spruce-admin.spruce-admin--v2 .modal-header {
  border-bottom: 1px solid var(--border-default);
  padding: 18px 24px 16px;
}

.spruce-admin.spruce-admin--v2 .modal-title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-xl);
  color: var(--text-heading);
  line-height: 1.25;
}

.spruce-admin.spruce-admin--v2 .modal-body {
  font-size: var(--text-md);
  color: var(--text-body);
}

.spruce-admin.spruce-admin--v2 .modal-footer {
  border-top: 1px solid var(--border-default);
  padding: 14px 24px;
}

.spruce-admin.spruce-admin--v2 .modal-backdrop {
  background-color: var(--stone-900);
}

/* Close glyph (modals, dismissible alerts) */
.spruce-admin.spruce-admin--v2 .close {
  color: var(--stone-400);
  text-shadow: none;
  opacity: 1;
  transition: color var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 .close:hover {
  color: var(--stone-600);
  opacity: 1;
}

/* Progress — design capacity bars: sunken track, brand fill, full radius */
.spruce-admin.spruce-admin--v2 .progress {
  background-color: var(--stone-100);
  border-radius: var(--radius-full);
}

.spruce-admin.spruce-admin--v2 .progress-bar {
  background-color: var(--green-500);
}

/* Bootstrap custom checkboxes — design Checkbox: green-500 checked state,
   border-strong resting, focus ring. Geometry stays Bootstrap's, EXCEPT the
   border: BS 4.1's ::before is a flat #dee2e6 box with no border at all, so
   a border-color alone is inert and the resting box would be invisible
   white-on-white — declare the full border (codex review, PR #550). */
.spruce-admin.spruce-admin--v2 .custom-control-label::before {
  background-color: var(--surface-card);
  border: 1px solid var(--border-strong);
}

.spruce-admin.spruce-admin--v2 .custom-control-input:checked ~ .custom-control-label::before {
  background-color: var(--green-500);
  border-color: var(--green-500);
}

/* Disabled states — the resting/checked rules above out-rank or out-order
   Bootstrap's disabled variants, so restate them (codex review, PR #550) */
.spruce-admin.spruce-admin--v2 .custom-control-input:disabled ~ .custom-control-label::before {
  background-color: var(--stone-200);
  border-color: var(--border-default);
}

.spruce-admin.spruce-admin--v2
  .custom-control-input:disabled:checked
  ~ .custom-control-label::before {
  background-color: var(--green-200);
  border-color: var(--green-200);
}

.spruce-admin.spruce-admin--v2 .custom-control-input:focus ~ .custom-control-label::before {
  box-shadow: var(--focus-ring);
}

.spruce-admin.spruce-admin--v2
  .custom-control-input:focus:not(:checked)
  ~ .custom-control-label::before {
  border-color: var(--border-focus);
}

/* Pill nav — design Tabs pill variant: brand-soft active */
.spruce-admin.spruce-admin--v2 .nav-pills .nav-link {
  color: var(--stone-500);
  font-size: 14px;
  font-weight: 500;
  border-radius: var(--radius-sm);
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .nav-pills .nav-link:hover {
  color: var(--green-700);
  text-decoration: none;
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .nav-pills .nav-link.active {
  /* Was brand-soft/green-700 — too close to the inactive state to read as
     selected (Bruce, 2026-07-28). Segmented-control treatment instead: the
     active pill goes white with near-black text against the sunken track. */
  background-color: var(--surface-card);
  color: var(--stone-800);
  box-shadow: var(--shadow-sm);
}

/* Hyper bordered nav — same underline language as the mapped .nav-tabs */
.spruce-admin.spruce-admin--v2 .nav-bordered .nav-link {
  color: var(--stone-500);
  font-weight: 500;
}

/* Inactive bordered tabs carry NO underline. Hyper gives them `border: 0`,
   which hid the per-tab inline `border-bottom-color` (chart-series colors on
   the orders metric tabs); the `.nav-tabs` mapping's 2px transparent bottom
   border revealed those inline colors on every tab at once, so the underline
   appeared permanently on any tab that has one and only-when-selected on the
   tab that doesn't (Bruce, staging 2026-07-23). Restore zero width when
   inactive so the underline marks selection again. */
.spruce-admin.spruce-admin--v2 .nav-tabs.nav-bordered .nav-link:not(.active) {
  border-bottom-width: 0;
}

/* Active tabs keep their inline series color where the template sets one
   (inline styles outrank this); tabs without one get the brand underline. */
.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  .nav-bordered
  .nav-link.active {
  color: var(--green-700);
  border-bottom-color: var(--green-500);
}

/* Dropdown menus — design menu surface: radius-md, shadow-lg (menus only,
   per readme shadow rules), hairline border */
.spruce-admin.spruce-admin--v2 .dropdown-menu {
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  background: var(--surface-card);
  font-size: var(--text-md);
  color: var(--text-body);
}

/* Anchor variants out-rank the `.sa-main a` base rules, which carry an
   element selector and would otherwise keep menu links link-green and
   underline them on hover (codex review, PR #550) */
.spruce-admin.spruce-admin--v2 .dropdown-item,
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.dropdown-item {
  color: var(--stone-700);
}

.spruce-admin.spruce-admin--v2 .dropdown-item:hover,
.spruce-admin.spruce-admin--v2 .dropdown-item:focus,
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.dropdown-item:hover,
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.dropdown-item:focus {
  background-color: var(--surface-sunken);
  color: var(--stone-700);
  text-decoration: none;
}

.spruce-admin.spruce-admin--v2 .dropdown-divider {
  border-top-color: var(--border-default);
}

/* Remaining solid button tones (design Button variants) */
.spruce-admin.spruce-admin--v2 .btn.btn-secondary {
  background-color: var(--surface-card);
  border-color: var(--border-strong);
  color: var(--stone-700);
}

.spruce-admin.spruce-admin--v2 .btn.btn-secondary:hover,
.spruce-admin.spruce-admin--v2 .btn.btn-secondary:focus,
.spruce-admin.spruce-admin--v2 .btn.btn-secondary:not(:disabled):active {
  background-color: var(--stone-100);
  border-color: var(--border-strong);
  color: var(--stone-700);
}

.spruce-admin.spruce-admin--v2 .btn.btn-danger {
  background-color: var(--danger);
  border-color: var(--danger);
  color: #ffffff;
}

/* Content-specific: darkened danger hover, same literal as .sa-btn-danger */
.spruce-admin.spruce-admin--v2 .btn.btn-danger:hover {
  background-color: #a93226;
  border-color: #a93226;
  color: #ffffff;
}

.spruce-admin.spruce-admin--v2 .btn.btn-warning {
  background-color: var(--warning);
  border-color: var(--warning);
  color: #ffffff;
}

/* Remaining badge tones (design Badge) */
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-secondary {
  background-color: var(--stone-100);
  color: var(--stone-600);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-light {
  background-color: var(--stone-50);
  color: var(--stone-600);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-primary-lighten {
  background-color: var(--brand-soft);
  color: var(--brand);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .badge.badge-danger-lighten {
  background-color: var(--danger-bg);
  color: var(--danger);
}

/* Remaining alert tones (design Alert) */
.spruce-admin.spruce-admin--v2 .alert-info {
  background-color: var(--info-bg);
  border: 1px solid color-mix(in srgb, var(--info) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .alert-info strong {
  color: var(--info);
}

.spruce-admin.spruce-admin--v2 .alert-success {
  background-color: var(--success-bg);
  border: 1px solid color-mix(in srgb, var(--success) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .alert-success strong {
  color: var(--success);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .alert .alert-link {
  color: inherit;
  font-weight: 600;
  text-decoration: underline;
}

/* Input groups — design Input prefix/suffix chips */
.spruce-admin.spruce-admin--v2 .input-group-text,
.spruce-admin.spruce-admin--v2 .input-group-addon {
  background-color: var(--surface-sunken);
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
  font-size: var(--text-sm);
  border-radius: var(--radius-md);
}

/* Small/light form controls — geometry from Bootstrap, skin from tokens */
.spruce-admin.spruce-admin--v2 .form-control-sm {
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
}

/* !important on both: Hyper's .form-control-light declares background-color
   and border-color !important (_forms.scss — codex review, PR #550) */
.spruce-admin.spruce-admin--v2 .form-control-light {
  background-color: var(--stone-100) !important;
  border-color: transparent !important;
}

/* Bootstrap-3 relics still in legacy templates: .label ≈ badge, .well ≈
   sunken panel. Mapped onto the same design tokens as their modern kin.
   Narrowed to toned labels only (Stage 2 / Phase 6a): every legacy relic
   pairs `.label` with a `label-<tone>` class (incl. label-default), while
   the fundraising admin's Tailwind form-label contract is a BARE `.label`
   (CoreComponents) — the unqualified mapping painted every form label as
   a badge pill on the shared --v2 marker. The qualifier sits in :where()
   so it adds ZERO specificity: this base stays (0,4,0), tied with the
   `.label-success/-warning/-info` tone rules below, and the later tone
   rules keep winning the tie (a bare `[class*=…]` qualifier at (0,5,0)
   would have beaten every tone wash — R1 review). */
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .label:where([class*="label-"]) {
  display: inline-block;
  border-radius: var(--radius-full);
  padding: 1px 10px;
  font-size: 12px;
  font-weight: 600;
  background-color: var(--stone-100);
  color: var(--stone-600);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .label-success {
  background-color: var(--success-bg);
  color: var(--success);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .label-warning {
  background-color: var(--warning-bg);
  color: var(--warning);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) .label-info {
  background-color: var(--info-bg);
  color: var(--info);
}

.spruce-admin.spruce-admin--v2 .well {
  background-color: var(--surface-sunken);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: none;
  padding: var(--space-4);
}

/* Monospace content (IDs, codes, plates) — contract §1.3 mono role */
.spruce-admin.spruce-admin--v2 .monospace {
  font-family: var(--font-mono);
}

/* Tone/surface utilities. !important: competing BS4 utilities are
   !important. */
.spruce-admin.spruce-admin--v2 .text-warning {
  color: var(--warning) !important;
}

.spruce-admin.spruce-admin--v2 .text-body {
  color: var(--text-body) !important;
}

/* No !important: BS4.1 defines .text-black-50 but no .text-black utility,
   so there is no !important competitor (codex review, PR #550) */
.spruce-admin.spruce-admin--v2 .text-black {
  color: var(--stone-900);
}

.spruce-admin.spruce-admin--v2 .bg-success {
  background-color: var(--success) !important;
}

.spruce-admin.spruce-admin--v2 .bg-warning {
  background-color: var(--warning) !important;
}

.spruce-admin.spruce-admin--v2 .bg-danger {
  background-color: var(--danger) !important;
}

.spruce-admin.spruce-admin--v2 .border-bottom {
  border-bottom-color: var(--border-default) !important;
}

/* =========================================================================
 * 5. Batch 3 — order / transaction / revenue_breakdown (#523, Phase 7)
 *
 * Financial-tables cluster: templates/admin/order/*,
 * templates/admin/transaction/*, templates/admin/revenue_breakdown/*.
 * Shared contracts (tables, pagination, modals, nav-bordered, input-group*,
 * dropdown-divider, form-control-light) live in §3–§4 — only family-specific
 * leftovers are mapped here.
 * ========================================================================= */

/* Hyper calendar adornment — .background-light on .input-group-text (commented
   markup in order/transaction/revenue templates; same sunken chip contract as
   §4 .input-group-text / .form-control-light) */
.spruce-admin.spruce-admin--v2 .input-group-text.background-light {
  background-color: var(--surface-sunken);
  color: var(--text-muted);
}

/* Table centered rows — design Table.jsx vertical alignment (Hyper
   _tables.scss `.table-centered th,td{vertical-align:middle!important}`) */
.spruce-admin.spruce-admin--v2 .table-centered th,
.spruce-admin.spruce-admin--v2 .table-centered td {
  vertical-align: middle !important;
}

/* Period-detail pagination — compact chip row inside expanded transaction
   groups (design pagination secondary-button chips at --text-xs) */
.spruce-admin.spruce-admin--v2 .pagination.pagination-sm .page-link {
  padding: 0.25rem 0.5rem;
  font-size: var(--text-xs);
}

/* =========================================================================
 * 6. Batch 4 — membership_group + registration_invitation (#523, Phase 7)
 *
 * Family census: templates/admin/membership_group/* and
 * templates/admin/registration_invitation/*. Shared clusters (tables,
 * badges, nav-pills, alerts, card-header, progress, …) live in §4; this
 * section only covers family-specific leftovers.
 * ========================================================================= */

/* Comparison summary cards — design Card tone borders
   (compare_results.html.eex metric panels) */
.spruce-admin.spruce-admin--v2 .card.border-danger {
  border-color: var(--danger) !important; /* BS4 `.border-danger` utility */
}

.spruce-admin.spruce-admin--v2 .card.border-success {
  border-color: var(--success) !important; /* BS4 `.border-success` utility */
}

/* Comparison column headers — tone panel headers on participant tables */
.spruce-admin.spruce-admin--v2 .card-header.bg-danger {
  background-color: var(--danger) !important; /* BS4 `.bg-danger` utility */
  border-bottom: 1px solid color-mix(in srgb, var(--danger) 25%, transparent);
  color: #ffffff;
}

.spruce-admin.spruce-admin--v2 .card-header.bg-success {
  background-color: var(--success) !important; /* BS4 `.bg-success` utility */
  border-bottom: 1px solid color-mix(in srgb, var(--success) 25%, transparent);
  color: #ffffff;
}

/* Ghost export button on tone headers — same contract as §2
   `.card.bg-primary .btn.btn-outline-light` */
.spruce-admin.spruce-admin--v2 .card-header.bg-danger .btn.btn-outline-light,
.spruce-admin.spruce-admin--v2 .card-header.bg-success .btn.btn-outline-light {
  border: 1px solid rgba(255, 255, 255, 0.5);
  color: #ffffff;
  background: transparent;
  border-radius: var(--radius-sm);
  transition: background-color var(--transition-fast), border-color var(--transition-fast),
    color var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 .card-header.bg-danger .btn.btn-outline-light:hover,
.spruce-admin.spruce-admin--v2 .card-header.bg-success .btn.btn-outline-light:hover {
  background: rgba(255, 255, 255, 0.12);
  color: #ffffff;
}

/* Legacy native checkbox — design Checkbox accent (invitation form) */
.spruce-admin.spruce-admin--v2 input.checkbox {
  accent-color: var(--green-500);
}

/* Hyper extra-small button — shared size variant (first consumer:
   registration_invitation; design Button sm geometry scaled down) */
.spruce-admin.spruce-admin--v2 .btn.btn-xs {
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
}

/* Kebab menu toggle — Hyper's .dot-dropper{color:inherit} (0,1,0) loses to
   the .sa-main a base rule (0,3,1), turning the dots link-green (Grok
   review, PR #552 — recurring .sa-main a pattern). Muted icon per design
   IconButton ghost treatment. */
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.dot-dropper {
  color: var(--text-muted);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.dot-dropper:hover {
  color: var(--stone-600);
  text-decoration: none;
}

/* =========================================================================
 * 7. Batch 5 — registration (#523, Phase 7)
 *
 * Family census: templates/admin/registration/*. Shared clusters (tables,
 * pagination, modals, dropdowns, badges, chart-widget-list, …) live in §2–§4;
 * only family-specific leftovers are mapped here.
 * ========================================================================= */

/* Cancelled rows — legacy registration.scss `.order-cancelled { color: #f99 }` */
.spruce-admin.spruce-admin--v2 .table tr.order-cancelled td {
  color: #f99;
}

/* Segmentation card menu — Hyper `.card-drop { color: inherit }` loses to the
   `.sa-main a` base rule (same pattern as §6 `a.dot-dropper`). */
.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.card-drop {
  color: var(--text-muted);
}

.spruce-admin.spruce-admin--v2 :is(.sa-main, .up-modal-content, .modal) a.card-drop:hover {
  color: var(--stone-600);
  text-decoration: none;
}

/* Registerable selects use `.form-input` instead of `.form-control` — same
   Input contract as §3 `.form-control` */
.spruce-admin.spruce-admin--v2 .form-input {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  font-size: 14px;
  font-family: var(--font-body);
  color: var(--stone-800);
  background-color: var(--surface-card);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.spruce-admin.spruce-admin--v2 .form-input:focus {
  border-color: var(--border-focus);
  box-shadow: var(--focus-ring);
  color: var(--stone-800);
  background-color: var(--surface-card);
}

/* ================================================================== * 8. Batch 5 — coupon (#523, Phase 7)
 *
 * Family census: templates/admin/coupon/*. Shared clusters live in §2–§4.
 * ========================================================================= */

/* Coupon subset tabs — sunken pill track (class has no legacy rule; pairs
   with §4 `.nav-pills`) */
.spruce-admin.spruce-admin--v2 .bg-nav-pills {
  background-color: var(--surface-sunken);
  border-radius: var(--radius-sm);
  padding: 4px;
  /* The track should hug its pills, not run the full row width
     (Bruce, 2026-07-28). `.nav` is display:flex, so fit-content works. */
  width: fit-content;
}

/* Redemption meter fill tones — coupon index `progress-bar bg-success|warning`
   (!important: BS4 `.bg-success` / `.bg-warning` utilities) */
.spruce-admin.spruce-admin--v2 .progress-bar.bg-success {
  background-color: var(--success) !important;
}

.spruce-admin.spruce-admin--v2 .progress-bar.bg-warning {
  background-color: var(--warning) !important;
}

/* =========================================================================
 * 9. Batch 5 — financial_period (#523, Phase 7)
 *
 * Family census: templates/admin/financial_period/*. Shared clusters live in
 * §2–§4. Superadmin `sa_*` and org `index`/`show` share these partials.
 * ========================================================================= */

/* Period table section breaks — legacy `admin.scss` rule for this class is
   commented out; hairline top rule per design Table.jsx section grouping */
.spruce-admin.spruce-admin--v2 .financial-period-header-row th {
  border-top: 2px solid var(--border-default);
}

/* =========================================================================
 * 10. Batch 6 — registerable (#523, Phase 7)
 *
 * Family census: templates/admin/registerable/* (controller pages + the
 * RegisterableEditorLive partials embedded by show.html). Shared clusters
 * (tables, badges/-lighten, alerts, progress, input-group*, custom-control*,
 * btn tones, form-control-sm) live in §2–§6; this section only covers
 * family-specific leftovers. Geometry/hook classes (table-sm, progress-md,
 * no-wrap, no-top-border, input-group-prepend, gifting-options,
 * short-description) are triaged in the coverage test.
 * ========================================================================= */

/* Registerable revenue accordion tables — design Table.jsx hairline rules
   (legacy admin.scss .revenue-category-table / .revenue-orders-table). Token
   substitutes for the Hyper greys #f5f7f9 / #eef0f2 / #dee2e6. */
.spruce-admin.spruce-admin--v2 .revenue-category-table tr.font-weight-bold td {
  border-bottom: none;
}

.spruce-admin.spruce-admin--v2
  .revenue-category-table
  tbody.collapse
  tr:first-child
  td {
  border-top: 1px solid var(--stone-50);
}

.spruce-admin.spruce-admin--v2
  .revenue-category-table
  tbody.collapse
  tr:last-child
  td {
  border-bottom: 1px solid var(--border-default);
}

.spruce-admin.spruce-admin--v2
  .revenue-orders-table
  tr.revenue-order-row.revenue-order-row--expandable
  td {
  border-bottom: none;
}

.spruce-admin.spruce-admin--v2
  .revenue-orders-table
  tr.revenue-order-row.revenue-order-row--expandable
  + tbody.revenue-line-items
  tr.revenue-line-item-row:first-child
  td {
  border-top: 1px solid var(--stone-50);
}

.spruce-admin.spruce-admin--v2
  .revenue-orders-table
  tbody.revenue-line-items
  tr.revenue-line-item-row:not(:first-child)
  td {
  border-top: 1px solid var(--stone-100);
}

.spruce-admin.spruce-admin--v2
  .revenue-orders-table
  tbody.revenue-line-items
  tr.revenue-line-item-row:last-child
  td {
  border-bottom: 1px solid var(--border-default);
}

/* =========================================================================
 * 11. Batch 6 — timeable (#523, Phase 7)
 *
 * Family census: templates/admin/timeable/*. Shared clusters (tables, alerts,
 * badges/-lighten, .label/.well, dropdowns, form-control-sm, checkbox accent)
 * live in §2–§6. Census leftovers were geometry-only (no-top-border,
 * table-responsive-xl, dropdown-menu-left) and are triaged — no family-
 * specific skin mappings required.
 * ========================================================================= */

/* =========================================================================
 * 12. Batch 6 — registration_import_job (#523, Phase 7)
 *
 * Family census: templates/admin/registration_import_job/* (controller pages
 * + RegistrationImporterLive partials embedded by show.html). Shared
 * clusters (nav-pills, badges, alerts, tables, btn tones, bg-light) live in
 * §2–§6; geometry (nav-justified, rounded-0, table-sm) is triaged. The
 * dismiss-X on ignored-column badges is the only family-specific leftover.
 * ========================================================================= */

/* Ignored-column dismiss control — Hyper used BS4 `.text-light` (near-white
   !important) on a dark badge; v2 `.badge-secondary` is a stone wash, so
   inherit the badge foreground. a.-qualified + !important: BS4 `.text-light`
   is !important, and the `.sa-main a` base rule (0,3,1) would otherwise keep
   the icon link-green (cookbook .sa-main a trap). */
.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  a.text-light {
  color: inherit !important; /* BS4 `.text-light` utility */
}

.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  a.text-light:hover {
  color: inherit !important;
  text-decoration: none;
}

/* =========================================================================
 * 13. Batch 7 — autorenewal (#523, Phase 7)
 *
 * This family styles itself via a large inline <style> block in
 * index.html.eex using the LEGACY Hyper palette (indigo #727cf5, amber
 * #ffbc00, lime #7ecb23, pink #fa5c7c, gray #6c757d) for its five status
 * tones (primary/warning/success/danger/secondary = scheduled / needs
 * attention / succeeded / failed / hidden). The adapter re-themes those
 * tones onto status tokens — scheduled maps to --info (the design has no
 * indigo; info-blue keeps "scheduled" distinct from success-green) and
 * "secondary" to stone. Most geometry (carets, rowspan alignment, collapse
 * chevrons, inactive opacity) stays with the inline block. A few geometry
 * contracts must be remapped here because the global scoped `.card` rule
 * (0,3,0) beats the unscoped inline (0,1–2,0) for border width, resting
 * shadow, and corner radius — see the overrides below.
 * ========================================================================= */

/* Summary cards are <a class="card … autorenew-summary-card …">. The base
   `.sa-main a` rule (0,3,1) would paint them link-green and underline on
   hover — same trap as a.dot-dropper / a.card-drop. Keep card chrome as
   body text, no underline. */
.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  a.autorenew-summary-card {
  color: var(--text-body);
  text-decoration: none;
}

.spruce-admin.spruce-admin--v2
  :is(.sa-main, .up-modal-content, .modal)
  a.autorenew-summary-card:hover {
  color: var(--text-body);
  text-decoration: none;
}

/* Restore the 2px transparent border the inline block intends for layout
   stability when a tone border-color appears on --active. Global scoped
   `.card` sets `border: 1px solid …` at (0,3,0) and otherwise wins. */
.spruce-admin.spruce-admin--v2 .card.autorenew-summary-card {
  border-width: 2px;
  border-color: transparent;
}

/* Inactive-card hover elevation. Scoped to :not(--active) so this does not
   replace the active tone glow below. Uses --shadow-md (token) rather than
   the inline rgba stack. Specificity (0,6,0) beats `.card` (0,3,0) and the
   unscoped inline hover (0,2,0). */
.spruce-admin.spruce-admin--v2
  .card.autorenew-summary-card:not(.autorenew-summary-card--active):hover {
  box-shadow: var(--shadow-md);
  opacity: 1;
}

/* Active border/glow per tone (design focus/selection language: 25% tone
   glow via color-mix, like --focus-ring's construction). Specificity
   (0,4,0) beats the unscoped inline (0,2,0) tone rules. Inactive hover is
   :not(--active), so it never competes with these glow rules. */
.spruce-admin.spruce-admin--v2 .autorenew-summary-card--active.autorenew-summary-card--primary {
  border-color: var(--info);
  box-shadow: 0 2px 12px color-mix(in srgb, var(--info) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .autorenew-summary-card--active.autorenew-summary-card--warning {
  border-color: var(--warning);
  box-shadow: 0 2px 12px color-mix(in srgb, var(--warning) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .autorenew-summary-card--active.autorenew-summary-card--success {
  border-color: var(--success);
  box-shadow: 0 2px 12px color-mix(in srgb, var(--success) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .autorenew-summary-card--active.autorenew-summary-card--danger {
  border-color: var(--danger);
  box-shadow: 0 2px 12px color-mix(in srgb, var(--danger) 25%, transparent);
}

.spruce-admin.spruce-admin--v2 .autorenew-summary-card--active.autorenew-summary-card--secondary {
  border-color: var(--stone-500);
  box-shadow: 0 2px 12px color-mix(in srgb, var(--stone-500) 25%, transparent);
}

/* Active-card caret pointing into the panel below — tone-matched */
.spruce-admin.spruce-admin--v2
  .autorenew-summary-card--active.autorenew-summary-card--primary::after {
  border-top-color: var(--info);
}

.spruce-admin.spruce-admin--v2
  .autorenew-summary-card--active.autorenew-summary-card--warning::after {
  border-top-color: var(--warning);
}

.spruce-admin.spruce-admin--v2
  .autorenew-summary-card--active.autorenew-summary-card--success::after {
  border-top-color: var(--success);
}

.spruce-admin.spruce-admin--v2
  .autorenew-summary-card--active.autorenew-summary-card--danger::after {
  border-top-color: var(--danger);
}

.spruce-admin.spruce-admin--v2
  .autorenew-summary-card--active.autorenew-summary-card--secondary::after {
  border-top-color: var(--stone-500);
}

/* Card stat icons — tone fg on tone wash (design Badge tone pairs) */
.spruce-admin.spruce-admin--v2 .widget-flat .widget-icon.widget-icon-primary {
  color: var(--info);
  background-color: var(--info-bg);
}

.spruce-admin.spruce-admin--v2 .widget-flat .widget-icon.widget-icon-warning {
  color: var(--warning);
  background-color: var(--warning-bg);
}

.spruce-admin.spruce-admin--v2 .widget-flat .widget-icon.widget-icon-success {
  color: var(--success);
  background-color: var(--success-bg);
}

.spruce-admin.spruce-admin--v2 .widget-flat .widget-icon.widget-icon-danger {
  color: var(--danger);
  background-color: var(--danger-bg);
}

.spruce-admin.spruce-admin--v2 .widget-flat .widget-icon.widget-icon-secondary {
  color: var(--stone-600);
  background-color: var(--stone-100);
}

/* Status tab panels — tone accent strip + wash header + tone icon.
   Square top corners so the coloured accent reads as a clean straight
   strip; global `.card` would otherwise apply --radius-md on all corners.
   Keep this at (0,3,0), equal to global `.card`, so the later status-tone
   rules at the same specificity can still replace border-top-color. */
.spruce-admin.spruce-admin--v2 .autorenew-tab-panel {
  border-top: 3px solid var(--border-default);
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel-header {
  border-bottom: 1px solid var(--border-default);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--primary {
  border-top-color: var(--info);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--primary .autorenew-tab-panel-header {
  background-color: var(--info-bg);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--primary .autorenew-tab-panel-icon {
  color: var(--info);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--warning {
  border-top-color: var(--warning);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--warning .autorenew-tab-panel-header {
  background-color: var(--warning-bg);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--warning .autorenew-tab-panel-icon {
  color: var(--warning);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--success {
  border-top-color: var(--success);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--success .autorenew-tab-panel-header {
  background-color: var(--success-bg);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--success .autorenew-tab-panel-icon {
  color: var(--success);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--danger {
  border-top-color: var(--danger);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--danger .autorenew-tab-panel-header {
  background-color: var(--danger-bg);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--danger .autorenew-tab-panel-icon {
  color: var(--danger);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--secondary {
  border-top-color: var(--stone-400);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--secondary .autorenew-tab-panel-header {
  background-color: var(--surface-sunken);
}

.spruce-admin.spruce-admin--v2 .autorenew-tab-panel--secondary .autorenew-tab-panel-icon {
  color: var(--stone-500);
}

/* =========================================================================
 * 14. Batch 10 — organization (#523, Phase 7)
 *
 * Super-admin organization CRUD (templates/admin/organization/*). Shared
 * contracts (tables, forms, cards, buttons, alerts, input-group-addon,
 * checkbox accent) live in §2–§4. Only family leftover: theme hex inputs
 * marked `.color-picker` on organization/form.html.eex. Hex theme values
 * are code-like → contract §1.3 mono role (IDs/codes), not a new shared
 * cluster. Specificity beats §3 `.form-control` font-family.
 * ========================================================================= */

.spruce-admin.spruce-admin--v2 .form-control.color-picker {
  font-family: var(--font-mono);
}

/* =========================================================================
 * 15. Batch 12 staging correction — classless Phoenix selects (#523)
 *
 * timed_stage/form.html, scanner_assignment/form.html, and (Batch 14 /
 * final sweep) participant_plate/form.html emit bare `select/3` helpers
 * with no `class:` option, so Phoenix still assigns predictable ids
 * (`#timed_stage_organization_id`, `#scanner_assignment_timed_stage_id`,
 * `#participant_plate_plate_set_id`) but never `.form-control`. The class
 * census only extracts class= attributes, so these controls were
 * invisible to the Batch 12 gate and kept the UA native border/radius
 * (0px / rgb(118,118,118)). Staging also showed the scanner stage
 * select's long option text expanding intrinsic width past a 375px
 * viewport — constrain width here without broadening to every bare
 * select. Same control contract as §3 `.form-control` / design Select.jsx;
 * the tokenized 40px height keeps these classless controls aligned with the
 * legacy `.form-control` geometry while `--radius-md` wins over the JSX 11px.
 * ========================================================================= */

.spruce-admin.spruce-admin--v2
  :is(
    #timed_stage_organization_id,
    #scanner_assignment_timed_stage_id,
    #participant_plate_plate_set_id
  ) {
  display: block;
  width: 100%;
  max-width: 100%;
  height: calc(var(--space-8) + var(--space-2));
  padding: 0 var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  font-size: var(--text-md);
  line-height: var(--leading-normal);
  font-family: var(--font-body);
  color: var(--stone-800);
  background-color: var(--surface-card);
  background-clip: padding-box;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.spruce-admin.spruce-admin--v2
  :is(
    #timed_stage_organization_id,
    #scanner_assignment_timed_stage_id,
    #participant_plate_plate_set_id
  ):focus {
  border-color: var(--border-focus);
  box-shadow: var(--focus-ring);
  outline: none;
  color: var(--stone-800);
  background-color: var(--surface-card);
}

/* =========================================================================
 * 16. Batch 13 — scanner_message (#523, Phase 7)
 *
 * Custom Spruce page header (admin.scss `.admin-page-header` / absolute
 * `.admin-page-header-actions`), used by scanner_message/index. Not the
 * Hyper `.page-title-box` contract (§2), so the shared PageHeader mapping
 * does not cover these classes. Reproduce design PageHeader.jsx: flex
 * title/actions row, display title at `--text-3xl` / 700, actions as a
 * non-shrinking cluster. Override legacy absolute positioning with flex
 * (specificity beats admin.scss's two-class absolute rule).
 * ========================================================================= */

.spruce-admin.spruce-admin--v2 .admin-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  position: relative;
}

.spruce-admin.spruce-admin--v2 .admin-page-header h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: var(--weight-bold);
  color: var(--text-heading);
  line-height: var(--leading-tight);
}

.spruce-admin.spruce-admin--v2 .admin-page-header .admin-page-header-actions {
  position: static;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
  margin-left: auto;
}

/* =========================================================================
 * 17. Batch 14 — participant_plate (#523, Phase 7)
 *
 * Family leftover: signup_sheet.html.eex `.signup-sheet-table` (admin.scss
 * bumps print-day legibility to 110% / black / 700). Under v2 the shared
 * `.table` contract (§4) would otherwise force `--text-sm` / `--stone-700`.
 * Re-assert the race-day sheet emphasis with tokens: `--text-md` ≈ 110% of
 * table body 13px, `--stone-900` for near-black, `--weight-bold` for 700.
 *
 * Header cells need the same three tokens directly: `.table thead th` sets
 * font-size/color/weight on the child, so table-level inheritance alone
 * cannot reach them (Batch 14 review P2).
 *
 * Bare-control catch (class census cannot see these): new/create form
 * `select/3` for plate_set has no `class:` option → `#participant_plate_plate_set_id`
 * keeps the UA native chrome unless mapped. Folded into the Batch 12
 * exact-ID `:is(...)` classless-select contract above (review P3) rather
 * than duplicating the rule. Batch-assignment `checkbox/3` for
 * allow_reassignment is also classless → map its exact Phoenix id for
 * Checkbox accent. Long plate-set labels need max-width containment at
 * mobile widths (content-shaped overflow risk).
 * ========================================================================= */

/* Class only — do not prefix with `.sa-table` (admin_ui.css owns that token)
   or `.table`. Both legacy and converted markup keep `signup-sheet-table`.
   The class is DOUBLED purely for specificity, and it is load-bearing:
   admin_ui.css is linked AFTER admin_v2.css (layout/admin.html.eex), so a
   single `.signup-sheet-table` loses both of these declarations to the
   converted table's own rules —
     `table.sa-table`         (0,3,1) beats `.signup-sheet-table`      (0,3,0)
     `.sa-table thead th`     (0,3,2) ties  `.signup-sheet-table th`   (0,3,2)
   and a tie goes to the later sheet. That silently reverted the signup sheet
   to --text-sm/--stone-600/semibold. Doubling gives (0,4,0)/(0,4,2), which
   wins on class count without naming a token admin_ui.css owns. This is a
   printed race-day document; the larger, darker heading is the point. */
.spruce-admin.spruce-admin--v2 .signup-sheet-table.signup-sheet-table,
.spruce-admin.spruce-admin--v2 .signup-sheet-table.signup-sheet-table thead th {
  font-size: var(--text-md);
  color: var(--stone-900);
  font-weight: var(--weight-bold);
}

.spruce-admin.spruce-admin--v2 #assign_allow_reassignment {
  accent-color: var(--green-500);
}

/* =========================================================================
 * 18. Final sweep — registerable_question leftovers (#523, Phase 7)
 *
 * Nested under the already-flipped Registerable editor (real renderer:
 * RegisterableQuestionSetupLive → registerable_question_setup.html.heex;
 * images via RegisterableQuestionImagesLive). Unused twin
 * unused__registerable_question_setup_2.html.leex is not mounted.
 * Preserve Sortable handle/class coupling (hooks/index.js handle:
 * ".drag-handle") and LiveView upload entry markup — map skin only.
 * ========================================================================= */

/* Sortable list chrome — contract radius on the drag list surface. */
.spruce-admin.spruce-admin--v2 .sortable-list-rounded {
  border-radius: var(--radius-md);
}

/* Drag affordance — Sortable handle selector; cursor only (no markup change). */
.spruce-admin.spruce-admin--v2 .drag-handle {
  cursor: move;
  color: var(--text-muted);
}

/* LiveView upload preview article — compact card-surface entry. */
.spruce-admin.spruce-admin--v2 .upload-entry {
  display: inline-block;
  margin: var(--space-2);
  padding: var(--space-2);
  vertical-align: top;
  text-align: center;
  color: var(--text-body);
  background-color: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
}

/* a11y visually-hidden (admin.scss / a11yproject pattern). Clip geometry is
   the documented content-specific need; keep 1px box so LiveView file input
   remains programmatically clickable via Alpine x-ref. */
.spruce-admin.spruce-admin--v2 .visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* =========================================================================
 * 19. Final sweep — session / admin login (#523, Phase 7)
 *
 * Auth surfaces render through LayoutView :basic (not the admin shell).
 * basic.html.eex loads tokens + admin_v2 and applies the --v2 marker when
 * AdminLayoutPlug assigns :admin_v2. Reproduce _login.scss admin-login-*
 * and Hyper account-pages contracts with tokens on the dark theme-
 * background: translucent card, on-brand text, full-width submit.
 *
 * Do NOT add `.account-pages` to the shared light-content
 * `:is(.sa-main, .up-modal-content, .modal)` list — that context sets
 * `--text-body` / `--text-heading` / link-green colors that would wipe the
 * dark branded auth surface. Mirror only typography + focus-visible here
 * (final-sweep review P2): body font/size/leading, display headings, and
 * the contract focus ring for links/buttons/controls (forgot/recovery
 * anchors otherwise keep Hyper outline:none with no ring).
 * ========================================================================= */

.spruce-admin.spruce-admin--v2 .account-pages {
  padding: var(--space-6) 0 var(--space-16);
  /* Design contract §1.3 / base surface: Public Sans 14px / normal leading.
     Color intentionally omitted — dark branded-surface copy stays on-brand
     via admin-login-* / text-white* mappings below. */
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: var(--leading-normal);
}

/* Display ladder for auth headings (forgot/MFA/reset h4 + login h1).
   Color omitted so text-white / admin-login-heading on-brand colors win. */
.spruce-admin.spruce-admin--v2 .account-pages :is(h1, h2, h3, h4, h5, h6) {
  font-family: var(--font-display);
}

/* Auth-scoped focus ring — same token as §1 shared content focus-visible.
   Covers forgot-password, recovery nav, passkey, submit, and form controls. */
.spruce-admin.spruce-admin--v2
  .account-pages
  :is(a, button, input, select, textarea, .btn):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.spruce-admin.spruce-admin--v2 .account-pages.admin-login-page {
  padding-top: var(--space-6);
  padding-bottom: var(--space-16);
}

.spruce-admin.spruce-admin--v2 .login-form {
  max-width: 300px;
  margin-left: auto;
  margin-right: auto;
}

.spruce-admin.spruce-admin--v2 .admin-login-card {
  max-width: 430px;
  margin: 0 auto;
  padding: var(--space-8);
  color: var(--text-on-brand);
  background-color: color-mix(in srgb, var(--text-on-brand) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--text-on-brand) 16%, transparent);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.spruce-admin.spruce-admin--v2 .admin-login-card .login-form,
.spruce-admin.spruce-admin--v2 .admin-login-form {
  max-width: none;
}

.spruce-admin.spruce-admin--v2 .admin-login-heading {
  margin: var(--space-4) 0 var(--space-2);
  color: var(--text-on-brand);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
}

.spruce-admin.spruce-admin--v2 .admin-login-subtitle,
.spruce-admin.spruce-admin--v2 .admin-login-passkey-help {
  margin-bottom: 0;
  color: color-mix(in srgb, var(--text-on-brand) 80%, transparent);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

.spruce-admin.spruce-admin--v2 .admin-login-passkey-help {
  margin-top: var(--space-2);
}

.spruce-admin.spruce-admin--v2 .admin-login-label,
.spruce-admin.spruce-admin--v2 .admin-login-card .form-group label:not(.form-check-label) {
  margin-bottom: var(--space-2);
  color: color-mix(in srgb, var(--text-on-brand) 90%, transparent);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

/* Anchor forgot-link: basic layout has no .sa-main, but keep a.-qualified
   specificity for any future shell wrap (cookbook .sa-main a trap). */
.spruce-admin.spruce-admin--v2 a.admin-login-forgot,
.spruce-admin.spruce-admin--v2 .admin-login-forgot {
  color: color-mix(in srgb, var(--text-on-brand) 82%, transparent);
  font-size: var(--text-xs);
}

.spruce-admin.spruce-admin--v2 a.admin-login-forgot:hover,
.spruce-admin.spruce-admin--v2 .admin-login-forgot:hover {
  color: var(--text-on-brand);
}

.spruce-admin.spruce-admin--v2 .admin-login-card .login-form .form-control {
  min-height: calc(var(--space-8) + var(--space-3));
  margin-bottom: 0;
  border: 1px solid color-mix(in srgb, var(--text-on-brand) 20%, transparent);
  border-radius: var(--radius-sm);
}

.spruce-admin.spruce-admin--v2 .admin-login-submit {
  min-height: calc(var(--space-8) + var(--space-3));
  margin-top: var(--space-6);
}

.spruce-admin.spruce-admin--v2 .admin-login-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-6) 0;
  color: color-mix(in srgb, var(--text-on-brand) 72%, transparent);
  font-size: var(--text-xs);
  text-transform: uppercase;
}

.spruce-admin.spruce-admin--v2 .admin-login-divider::before,
.spruce-admin.spruce-admin--v2 .admin-login-divider::after {
  flex: 1;
  height: 1px;
  background-color: color-mix(in srgb, var(--text-on-brand) 18%, transparent);
  content: "";
}

/* Passkey ghost button on the dark auth card — same outline-light contract
   as §2 brand-panel ghost, scoped to the login card rather than .bg-primary. */
.spruce-admin.spruce-admin--v2 .admin-login-card .btn.btn-outline-light {
  border: 1px solid color-mix(in srgb, var(--text-on-brand) 50%, transparent);
  color: var(--text-on-brand);
  background-color: transparent;
  border-radius: var(--radius-md);
}

.spruce-admin.spruce-admin--v2 .admin-login-card .btn.btn-outline-light:hover {
  background-color: color-mix(in srgb, var(--text-on-brand) 12%, transparent);
  color: var(--text-on-brand);
}

/* Full-width auth buttons — Bootstrap .btn-block geometry (no !important). */
.spruce-admin.spruce-admin--v2 .btn.btn-block {
  display: block;
  width: 100%;
}

/* Muted white copy on dark account pages.
   !important: Bootstrap `.text-white-50{color:hsla(0,0%,100%,.5)!important}`. */
.spruce-admin.spruce-admin--v2 .account-pages .text-white-50,
.spruce-admin.spruce-admin--v2 .text-white-50 {
  color: color-mix(in srgb, var(--text-on-brand) 50%, transparent) !important;
}

.spruce-admin.spruce-admin--v2 .account-pages .text-white {
  color: var(--text-on-brand) !important;
}

/* MFA "remember this browser" label on dark account surface — beat shared
   .form-check-label stone-800 (0,3,0) with the account-pages ancestor. */
.spruce-admin.spruce-admin--v2 .account-pages .form-check-label {
  color: color-mix(in srgb, var(--text-on-brand) 80%, transparent);
}

@media (max-width: 575.98px) {
  .spruce-admin.spruce-admin--v2 .account-pages.admin-login-page {
    padding-top: var(--space-2);
  }

  .spruce-admin.spruce-admin--v2 .admin-login-card {
    padding: var(--space-6);
  }
}
