:root {
  --color-depot-navy: #17324d;
  --color-depot-navy-deep: #10263a;
  --color-counter-white: #ffffff;
  --color-ledger-grey: #f3f6f7;
  --color-ink: #17212b;
  --color-muted-slate: #596a76;
  --color-rule: #d4dee3;
  --color-purchased: #087a69;
  --color-purchased-wash: #e2f4ef;
  --color-pending: #945a00;
  --color-pending-wash: #fff0ce;
  --color-transit: #2463a7;
  --color-transit-wash: #e7f0fb;
  --color-shortfall: #b42318;
  --color-shortfall-deep: #7a1a12;
  --color-shortfall-wash: #fde8e5;
  --color-focus: #146cc0;
  --color-draft: #5e6872;
  --color-draft-wash: #edf0f2;
  --color-returned: #6941c6;
  --color-returned-wash: #eee9fb;

  /* Text and figures — CLAUDE.md section 3.

     Source Sans 3 replaced Atkinson Hyperlegible: a taller x-height (0.845 of
     the cap height against 0.793) and ~7% narrower per title, which is real
     room on a 360px card. Atkinson was chosen for its exaggerated letter
     differentiation, and the reason that is affordable to give up is the line
     below — every figure and identifier now renders in the mono, and those are
     the strings where 0/O and 1/l/I actually matter.

     --font-mono is a real webfont now, not a system stack. It used to be
     SFMono/Consolas/Liberation, which resolves to a different face on every
     device class — so an admission number lined up on the machine it was
     designed on and nowhere else. Pinning it is what makes a column of figures
     a column. */
  --font-sans: "Source Sans 3", Arial, Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-md: 1.125rem;
  --text-lg: 1.375rem;
  --text-xl: 1.75rem;
  --text-2xl: 2.25rem;
  --line-tight: 1.2;
  --line-base: 1.5;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;

  --radius-sm: 0.375rem;
  --radius-md: 0.625rem;
  --radius-lg: 0.875rem;
  --radius-pill: 999px;
  --shadow-raised: 0 0.5rem 1.5rem rgb(23 50 77 / 0.12);
  --shadow-focus: 0 0 0 0.2rem rgb(20 108 192 / 0.28);
  --tap-target: 3rem;

  /* The sidebar's own tokens — CLAUDE.md section 3.

     Deliberately separate from --color-depot-navy rather than a redefinition
     of it. That token has 47 uses and only 5 are backgrounds: the other 42 are
     `color:` on page titles, section titles, card headings, form labels and
     .btn-primary. Lightening it to lift the sidebar would repaint every
     heading in the application, which is the trap this set exists to avoid.

     --color-sidebar-surface is lifted and desaturated from the navy so the
     shell sits nearer the page and frames the content instead of competing
     with it; --color-sidebar-edge is the hairline that makes it a frame edge
     rather than a slab.

     --color-sidebar-selected is a filled accent, not another shade of the
     surface. Selection and hover used to be the same declaration, so a hovered
     item and the current page were indistinguishable. The mobile drawer
     already gets this right with a wash on a light surface; this is the same
     idea inverted, plus a left marker so it survives being glanced at.

     --sidebar-item-height is 2.5rem and not --tap-target on purpose. The
     sidebar renders only above the wide breakpoint — it is display:none at
     360px — so it is a pointer target, never a thumb one, and 3rem rows around
     a 1rem label are what made it read sparse. Nothing else may use this
     token, and --tap-target stays the floor everywhere touch happens. */
  --color-sidebar-surface: #24485f;
  --color-sidebar-edge: #35617d;
  --color-sidebar-selected: #3d7ea6;
  --color-sidebar-marker: #7fc4e8;
  --color-sidebar-text: rgb(255 255 255 / 0.82);
  --color-sidebar-muted: rgb(255 255 255 / 0.6);
  --sidebar-item-height: 2.5rem;
  --sidebar-width: 15.5rem;
  --mobile-nav-height: 4.5rem;
  --sticky-action-height: 5.25rem;
  --content-max: 90rem;

  --bs-body-font-family: var(--font-sans);
  --bs-body-font-size: var(--text-base);
  --bs-body-line-height: var(--line-base);
  --bs-body-color: var(--color-ink);
  --bs-body-bg: var(--color-ledger-grey);
  --bs-primary: var(--color-depot-navy);
  --bs-primary-rgb: 23, 50, 77;
  --bs-secondary-color: var(--color-muted-slate);
  --bs-border-color: var(--color-rule);
  --bs-border-radius: var(--radius-md);
  --bs-link-color: var(--color-transit);
  --bs-link-hover-color: var(--color-depot-navy);
  --bs-focus-ring-color: rgb(20 108 192 / 0.28);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  min-width: 20rem;
}

body {
  min-width: 20rem;
  margin: 0;
  background: var(--color-ledger-grey);
  color: var(--color-ink);
  font-family: var(--font-sans);
}

body.has-mobile-nav {
  padding-bottom: var(--mobile-nav-height);
}

body.purchase-page {
  padding-bottom: calc(var(--mobile-nav-height) + var(--sticky-action-height));
}

/* Figures and identifiers -------------------------------------------------
   CLAUDE.md section 3: every number a person compares against another number
   renders in the mono, tabular.

   One block rather than a font-family line on fifteen components, because the
   rule is "figures are mono" and a rule stated once cannot be half-applied.
   The next screen that shows a quantity adds its selector here; it does not
   invent its own treatment.

   What belongs: quantities, prices and totals, admission and invoice numbers,
   store and transfer codes. What does not: dates, which are read rather than
   compared and which the sans sets more compactly, and counts inside prose. */

.book-list__quantity,
.sale-summary__row dd,
.metric-block__figure,
.data-table .number-cell,
.shortfall-table td:last-child,
.quantity-state,
.set-capacity,
.result-strip__figure,
.quantity-readonly,
.report-total__figure,
.choice-card__price,
.invoice-line__value,
.compact-id,
.mobile-record__id,
.matched-student__identity,
.mapping-row__source {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

/* The mono runs ~25% wider than the sans at the same size, which is the real
   cost of this rule and lands hardest in a table cell on a 360px card. A step
   down holds the column widths where they were without touching the figure's
   legibility, since a mono digit is wider to begin with. */
.data-table .number-cell,
.compact-id,
.mobile-record__id {
  font-size: var(--text-sm);
}

a {
  text-underline-offset: 0.15em;
}

button,
input,
select,
textarea {
  font: inherit;
}

button,
a,
input,
select,
textarea,
[tabindex]:not([tabindex="-1"]) {
  scroll-margin: var(--space-6);
}

:focus-visible {
  outline: 0.1875rem solid var(--color-focus);
  outline-offset: 0.125rem;
}

.btn:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible {
  border-color: var(--color-focus);
  box-shadow: var(--shadow-focus);
  outline: 0;
}

.skip-link {
  position: fixed;
  top: var(--space-2);
  left: var(--space-2);
  z-index: 2000;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--color-counter-white);
  color: var(--color-depot-navy);
  font-weight: 700;
  transform: translateY(-150%);
}

.skip-link:focus {
  transform: translateY(0);
}

.app-shell {
  min-height: 100vh;
}

.app-main {
  min-width: 0;
}

.topbar {
  display: flex;
  min-height: 3.75rem;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border-bottom: 0.0625rem solid var(--color-rule);
  background: var(--color-counter-white);
}

/* min-height is the 44px rule, and it is stated rather than inherited on
   purpose. This link is a real touch target — it is the way back to the
   dashboard on a phone — and its height used to come from whatever line box
   the typeface happened to produce around a 2rem brand square. Atkinson
   Hyperlegible has unusually tall vertical metrics and padded it past 44px by
   accident; Source Sans 3's normal metrics let it collapse to 32px on every
   authenticated page in both shells, which the 360px audit caught on the run
   that swapped the font. A tap target must not be a side effect of a font. */
.topbar__brand {
  display: inline-flex;
  min-height: var(--tap-target);
  align-items: center;
  gap: var(--space-2);
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
  text-decoration: none;
}

.brand-mark {
  display: inline-grid;
  width: 2rem;
  height: 2rem;
  place-items: center;
  border-radius: var(--radius-sm);
  background: var(--color-depot-navy);
  color: var(--color-counter-white);
  font-size: var(--text-sm);
  letter-spacing: 0.04em;
}

.topbar__actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.icon-button {
  display: inline-grid;
  width: var(--tap-target);
  height: var(--tap-target);
  place-items: center;
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
  color: var(--color-depot-navy);
}

.context-strip {
  position: sticky;
  top: 0;
  z-index: 1020;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  border-bottom: 0.0625rem solid var(--color-rule);
  background: var(--color-counter-white);
  box-shadow: 0 0.1875rem 0.75rem rgb(23 50 77 / 0.06);
}

.context-strip__item {
  min-width: 0;
  padding: var(--space-2) var(--space-3);
}

.context-strip__item + .context-strip__item {
  border-left: 0.0625rem solid var(--color-rule);
}

.context-strip__label {
  display: block;
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: var(--line-tight);
  text-transform: uppercase;
}

.context-strip__value {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: var(--space-1);
  margin-top: var(--space-1);
  color: var(--color-depot-navy);
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: var(--line-tight);
}

.context-strip__value-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.context-current {
  display: inline-flex;
  flex: 0 0 auto;
  padding: 0.0625rem var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--color-purchased-wash);
  color: var(--color-purchased);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.context-lock {
  flex: 0 0 auto;
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
}

/*
 * The store switcher, on an owner's filter screens. Takes the place of
 * .context-strip__value in the same cell, so the strip's height does not jump
 * between a screen that has one and a screen that does not.
 *
 * min-height is the 44px rule, not decoration: this is a real control in the
 * sticky header and a counter reaches it with a thumb.
 */
.context-switcher {
  display: flex;
  min-width: 0;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-1);
}

.context-switcher .form-select {
  min-height: var(--tap-target);
  font-size: var(--text-sm);
  font-weight: 700;
}

.page-content {
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-4);
}

.page-header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.page-header__title {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-xl);
  font-weight: 700;
  line-height: var(--line-tight);
}

.page-header__subtitle {
  max-width: 45rem;
  margin: var(--space-1) 0 0;
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.page-header__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.surface {
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-lg);
  background: var(--color-counter-white);
}

.surface + .surface,
.section-stack > * + * {
  margin-top: var(--space-4);
}

.surface__header,
.surface__body,
.surface__footer {
  padding: var(--space-4);
}

.surface__header + .surface__body,
.surface__body + .surface__footer {
  border-top: 0.0625rem solid var(--color-rule);
}

.section-title {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
}

.section-copy {
  margin: var(--space-1) 0 0;
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.btn {
  --bs-btn-padding-y: 0.6875rem;
  --bs-btn-padding-x: 1rem;
  --bs-btn-font-weight: 700;
  --bs-btn-border-radius: var(--radius-md);
  min-height: var(--tap-target);
}

.btn-primary {
  --bs-btn-bg: var(--color-depot-navy);
  --bs-btn-border-color: var(--color-depot-navy);
  --bs-btn-hover-bg: var(--color-depot-navy-deep);
  --bs-btn-hover-border-color: var(--color-depot-navy-deep);
  --bs-btn-active-bg: var(--color-depot-navy-deep);
  --bs-btn-active-border-color: var(--color-depot-navy-deep);
  --bs-btn-disabled-bg: var(--color-muted-slate);
  --bs-btn-disabled-border-color: var(--color-muted-slate);
}

.btn-danger {
  --bs-btn-bg: var(--color-shortfall);
  --bs-btn-border-color: var(--color-shortfall);
  --bs-btn-hover-bg: var(--color-shortfall-deep);
  --bs-btn-hover-border-color: var(--color-shortfall-deep);
}

.btn-outline-danger {
  --bs-btn-color: var(--color-shortfall);
  --bs-btn-border-color: var(--color-shortfall);
  --bs-btn-hover-bg: var(--color-shortfall);
  --bs-btn-hover-border-color: var(--color-shortfall);
  --bs-btn-active-bg: var(--color-shortfall-deep);
  --bs-btn-active-border-color: var(--color-shortfall-deep);
}

.btn-outline-primary {
  --bs-btn-color: var(--color-depot-navy);
  --bs-btn-border-color: var(--color-depot-navy);
  --bs-btn-hover-bg: var(--color-depot-navy);
  --bs-btn-hover-border-color: var(--color-depot-navy);
}

.btn-link-danger {
  color: var(--color-shortfall);
}

.form-label,
.form-check-label {
  color: var(--color-ink);
  font-weight: 700;
}

.form-control,
.form-select {
  min-height: var(--tap-target);
  border-color: var(--color-rule);
  color: var(--color-ink);
  font-size: var(--text-base);
}

.form-control:disabled,
.form-select:disabled {
  border-color: var(--color-rule);
  background: var(--color-ledger-grey);
  color: var(--color-muted-slate);
  opacity: 1;
}

.form-text {
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.invalid-feedback {
  color: var(--color-shortfall);
  font-size: var(--text-sm);
  font-weight: 700;
}

.form-control.is-invalid,
.form-select.is-invalid {
  border-color: var(--color-shortfall);
}

.field-grid {
  display: grid;
  gap: var(--space-4);
}

.student-search-form {
  display: grid;
  gap: var(--space-3);
}

.search-input-wrap {
  position: relative;
}

.search-input-wrap .form-control {
  padding-left: 2.75rem;
}

.search-input-wrap::before {
  position: absolute;
  top: 50%;
  left: var(--space-4);
  z-index: 2;
  color: var(--color-muted-slate);
  content: "⌕";
  font-size: var(--text-lg);
  line-height: 1;
  transform: translateY(-50%);
}

.search-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.search-summary__count {
  margin: 0;
  font-size: var(--text-md);
  font-weight: 700;
}

.selection-list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.selection-list__button {
  display: grid;
  width: 100%;
  min-height: var(--tap-target);
  gap: var(--space-2);
  padding: var(--space-4);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
  color: var(--color-ink);
  text-align: left;
}

.selection-list__button:hover,
.selection-list__button[aria-current="true"] {
  border-color: var(--color-transit);
  background: var(--color-transit-wash);
}

.selection-list__name {
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
}

.selection-list__meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2) var(--space-4);
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.selection-list__meta-item {
  min-width: 0;
}

.selection-list__meta-item--wide {
  grid-column: 1 / -1;
}

.selection-list__meta-label {
  display: block;
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.status-band {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.status-band--pending {
  border-bottom: 0.125rem solid var(--color-pending);
  background: var(--color-pending-wash);
  color: var(--color-pending);
}

.status-band--purchased {
  border-bottom: 0.125rem solid var(--color-purchased);
  background: var(--color-purchased-wash);
  color: var(--color-purchased);
}

.matched-student {
  overflow: hidden;
}

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

.matched-student__name {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: var(--line-tight);
}

.matched-student__identity {
  margin: var(--space-1) 0 0;
  color: var(--color-muted-slate);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

.detail-list {
  display: grid;
  gap: var(--space-3);
  margin: var(--space-4) 0 0;
}

.detail-list__row {
  display: grid;
  grid-template-columns: 6rem minmax(0, 1fr);
  gap: var(--space-3);
}

.detail-list dt {
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
  font-weight: 400;
}

.detail-list dd {
  min-width: 0;
  margin: 0;
  color: var(--color-ink);
  font-weight: 700;
  overflow-wrap: anywhere;
}

.purchase-details {
  display: grid;
  gap: var(--space-4);
}

.bookset-options,
.payment-options {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  border: 0;
}

.choice-card {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: var(--tap-target);
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
  cursor: pointer;
}

.choice-card:hover,
.choice-card:has(.form-check-input:checked) {
  border-color: var(--color-transit);
  background: var(--color-transit-wash);
}

.choice-card .form-check-input {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
}

.choice-card__title {
  display: block;
  color: var(--color-depot-navy);
  font-weight: 700;
}

.choice-card__meta {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
  font-weight: 400;
}

.choice-card__price {
  font-weight: 700;
  white-space: nowrap;
}

.payment-options {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.payment-option {
  display: flex;
  min-height: var(--tap-target);
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
  cursor: pointer;
}

.payment-option:hover,
.payment-option:has(.form-check-input:checked) {
  border-color: var(--color-transit);
  background: var(--color-transit-wash);
}

.payment-option .form-check-input {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
}

.payment-option__text {
  font-weight: 700;
}

.permission-note {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-2);
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.return-form {
  display: grid;
  gap: var(--space-4);
}

.condition-options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  border: 0;
}

.condition-option {
  display: flex;
  min-height: var(--tap-target);
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
  cursor: pointer;
}

.condition-option:has(.form-check-input:checked) {
  border-color: var(--color-transit);
  background: var(--color-transit-wash);
}

.condition-option .form-check-input {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
}

.condition-option__title {
  display: block;
  font-weight: 700;
}

.condition-option__copy {
  display: block;
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
}

.book-list {
  margin: 0;
  padding: 0;
  border-top: 0.0625rem solid var(--color-rule);
  list-style: none;
}

.book-list__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 0.0625rem solid var(--color-rule);
}

.book-list__quantity {
  flex: 0 0 auto;
  color: var(--color-muted-slate);
  font-variant-numeric: tabular-nums;
}

.modal-footer--stacked {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.sale-summary {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-4) 0 0;
  border-top: 0.0625rem solid var(--color-rule);
}

.sale-summary__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
}

.sale-summary__row dt,
.sale-summary__row dd {
  margin: 0;
}

.sale-summary__row dt {
  color: var(--color-muted-slate);
}

.sale-summary__row dd {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.sale-summary__row--total {
  margin-top: var(--space-2);
  padding-top: var(--space-3);
  border-top: 0.125rem solid var(--color-depot-navy);
  color: var(--color-depot-navy);
  font-size: var(--text-md);
}

.purchased-actions {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.return-action {
  color: var(--color-shortfall);
}

.sticky-purchase-action {
  position: fixed;
  right: 0;
  bottom: var(--mobile-nav-height);
  left: 0;
  z-index: 1015;
  min-height: var(--sticky-action-height);
  padding: var(--space-3) var(--space-4);
  border-top: 0.0625rem solid var(--color-rule);
  background: var(--color-counter-white);
  box-shadow: 0 -0.375rem 1rem rgb(23 50 77 / 0.1);
}

.sticky-purchase-action .btn {
  width: 100%;
}

.required-note {
  margin: 0 0 var(--space-2);
  color: var(--color-shortfall);
  font-size: var(--text-xs);
  font-weight: 700;
  text-align: center;
}

.status-badge {
  display: inline-flex;
  min-height: 1.75rem;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border: 0.0625rem solid currentColor;
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1;
}

.status-badge::before {
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: currentColor;
  content: "";
}

.status-badge--purchased,
.status-badge--paid,
.status-badge--received {
  background: var(--color-purchased-wash);
  color: var(--color-purchased);
}

.status-badge--pending,
.status-badge--unpaid {
  background: var(--color-pending-wash);
  color: var(--color-pending);
}

.status-badge--dispatched,
.status-badge--transit {
  background: var(--color-transit-wash);
  color: var(--color-transit);
}

.status-badge--draft {
  background: var(--color-draft-wash);
  color: var(--color-draft);
}

.status-badge--returned {
  background: var(--color-returned-wash);
  color: var(--color-returned);
}

.status-badge--cancelled {
  background: var(--color-shortfall-wash);
  color: var(--color-shortfall);
}

.metric-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

.metric-block {
  min-width: 0;
  padding: var(--space-4);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
}

.metric-block__label {
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.metric-block__figure {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-depot-navy);
  font-size: var(--text-xl);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  line-height: var(--line-tight);
}

.metric-block__secondary {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
}

.split-rail__labels {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  font-weight: 700;
}

.split-rail__purchased {
  color: var(--color-purchased);
}

.split-rail__pending {
  color: var(--color-pending);
  text-align: right;
}

.split-progress {
  display: block;
  width: 100%;
  height: 1rem;
  overflow: hidden;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--color-pending-wash);
  accent-color: var(--color-purchased);
}

.split-progress::-webkit-progress-bar {
  background: var(--color-pending-wash);
}

.split-progress::-webkit-progress-value {
  background: var(--color-purchased);
}

.split-progress::-moz-progress-bar {
  background: var(--color-purchased);
}

.split-rail__summary {
  margin: var(--space-2) 0 0;
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.filter-panel__mobile-toggle {
  width: 100%;
}

.filter-grid {
  display: grid;
  gap: var(--space-3);
  padding-top: var(--space-4);
}

.filter-actions {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-2);
}

.applied-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.filter-chip {
  display: inline-flex;
  min-height: 2.25rem;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
  border: 0.0625rem solid var(--color-transit);
  border-radius: var(--radius-pill);
  background: var(--color-transit-wash);
  color: var(--color-depot-navy);
  font-size: var(--text-sm);
}

.filter-chip__remove {
  display: inline-grid;
  width: 1.75rem;
  height: 1.75rem;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--color-depot-navy);
}

.table-shell {
  overflow: hidden;
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
}

.data-table {
  width: 100%;
  margin: 0;
  border-collapse: collapse;
}

.data-table th,
.data-table td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 0.0625rem solid var(--color-rule);
  vertical-align: middle;
}

.data-table tr:last-child td {
  border-bottom: 0;
}

.data-table th {
  background: var(--color-ledger-grey);
  color: var(--color-depot-navy);
  font-size: var(--text-sm);
  font-weight: 700;
  text-align: left;
}

.data-table .number-cell {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.sort-button {
  display: inline-flex;
  min-height: 2rem;
  align-items: center;
  gap: var(--space-1);
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font-weight: inherit;
}

.row-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
}

.mobile-record-list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.mobile-record {
  padding: var(--space-4);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
}

.mobile-record__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.mobile-record__title {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
}

.mobile-record__id {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-muted-slate);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
}

.mobile-record__details {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
  margin: var(--space-4) 0;
}

.mobile-record__label {
  display: block;
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
}

.mobile-record__value {
  display: block;
  margin-top: var(--space-1);
  font-weight: 700;
}

.mobile-record__actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
}

.repeatable-list {
  display: grid;
  gap: var(--space-3);
}

.repeatable-row {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
}

.repeatable-row__remove {
  justify-self: start;
}

.feedback-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 0.0625rem solid;
  border-radius: var(--radius-md);
}

.feedback-toast--success {
  border-color: var(--color-purchased);
  background: var(--color-purchased-wash);
  color: var(--color-purchased);
}

.feedback-toast--error {
  border-color: var(--color-shortfall);
  background: var(--color-shortfall-wash);
  color: var(--color-shortfall);
}

.feedback-toast__title {
  display: block;
  font-weight: 700;
}

.feedback-toast__copy {
  display: block;
  margin-top: var(--space-1);
  color: var(--color-ink);
  font-size: var(--text-sm);
}

.empty-state {
  max-width: 34rem;
  margin: 0 auto;
  padding: var(--space-7) var(--space-4);
  text-align: center;
}

.empty-state__mark {
  display: grid;
  width: 4rem;
  height: 4rem;
  margin: 0 auto var(--space-4);
  place-items: center;
  border-radius: 50%;
  background: var(--color-transit-wash);
  color: var(--color-transit);
  font-size: var(--text-xl);
  font-weight: 700;
}

.empty-state__title {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-lg);
  font-weight: 700;
}

.empty-state__copy {
  margin: var(--space-2) 0 var(--space-4);
  color: var(--color-muted-slate);
}

.loading-state {
  display: flex;
  min-height: 7rem;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-5);
  color: var(--color-depot-navy);
  font-weight: 700;
}

.loading-state__spinner {
  width: 1.75rem;
  height: 1.75rem;
  border: 0.1875rem solid var(--color-rule);
  border-top-color: var(--color-transit);
  border-radius: 50%;
  animation: loading-spin 0.8s linear infinite;
}

@keyframes loading-spin {
  to {
    transform: rotate(360deg);
  }
}

.desktop-sidebar {
  display: none;
}

.desktop-sidebar--condensed {
  width: 5rem;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 0.0625rem solid var(--color-sidebar-edge);
  color: var(--color-counter-white);
  text-decoration: none;
}

.sidebar-brand__text {
  font-size: var(--text-md);
  font-weight: 700;
}

.sidebar-context {
  padding: var(--space-3) var(--space-4);
  border-bottom: 0.0625rem solid var(--color-sidebar-edge);
  color: var(--color-counter-white);
  font-size: var(--text-sm);
}

.sidebar-context__label {
  display: block;
  margin-bottom: 0.0625rem;
  color: var(--color-sidebar-muted);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.sidebar-nav {
  display: grid;
  gap: 0.125rem;
  margin: 0;
  padding: var(--space-2) var(--space-2);
  list-style: none;
}

/* The row is tightened so the label fills it rather than floating in it: at
   3rem around a 1rem label the list read sparse and scanned slowly. Pointer
   target only — see the token block for why this is not --tap-target. */
.sidebar-link {
  position: relative;
  display: flex;
  min-height: var(--sidebar-item-height);
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-sidebar-text);
  font-weight: 600;
  line-height: var(--line-tight);
  text-decoration: none;
}

/* Hover is a faint wash and says only "you are pointing at this". */
.sidebar-link:hover {
  background: rgb(255 255 255 / 0.08);
  color: var(--color-counter-white);
}

/* Selection is a different thing, not a stronger version of the same thing.
   A filled accent plus a left marker, so the current page is findable at a
   glance rather than by comparing two dark greys. */
.sidebar-link[aria-current="page"] {
  background: var(--color-sidebar-selected);
  color: var(--color-counter-white);
  font-weight: 700;
}

.sidebar-link[aria-current="page"]::before {
  position: absolute;
  top: 50%;
  left: 0;
  width: 0.1875rem;
  height: 1.25rem;
  border-radius: 0 var(--radius-pill) var(--radius-pill) 0;
  background: var(--color-sidebar-marker);
  content: "";
  transform: translateY(-50%);
}

/* Hovering the page you are already on must not repaint it as merely
   hovered — the accent outranks the wash. */
.sidebar-link[aria-current="page"]:hover {
  background: var(--color-sidebar-selected);
}

.sidebar-link__icon {
  display: inline-grid;
  width: 1.5rem;
  place-items: center;
}

.mobile-tabbar {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1030;
  display: grid;
  height: var(--mobile-nav-height);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 0.0625rem solid var(--color-rule);
  background: var(--color-counter-white);
  box-shadow: 0 -0.375rem 1rem rgb(23 50 77 / 0.08);
}

.mobile-tabbar__link,
.mobile-tabbar__button {
  display: flex;
  min-width: 0;
  min-height: var(--tap-target);
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-1);
  border: 0;
  background: transparent;
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
  font-weight: 700;
  text-decoration: none;
}

.mobile-tabbar__link[aria-current="page"],
.mobile-tabbar__button[aria-expanded="true"] {
  color: var(--color-depot-navy);
}

.mobile-tabbar__icon {
  font-size: var(--text-md);
  line-height: 1;
}

.mobile-more-menu {
  position: fixed;
  right: var(--space-3);
  bottom: calc(var(--mobile-nav-height) + var(--space-2));
  left: var(--space-3);
  z-index: 1040;
  display: none;
  padding: var(--space-2);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-lg);
  background: var(--color-counter-white);
  box-shadow: var(--shadow-raised);
}

.mobile-more-menu.is-open,
body[data-demo-more-open="true"] .mobile-more-menu {
  display: grid;
  gap: var(--space-1);
}

.mobile-more-menu__link {
  display: flex;
  min-height: var(--tap-target);
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  color: var(--color-depot-navy);
  font-weight: 700;
  text-decoration: none;
}

.mobile-more-menu__link:hover,
.mobile-more-menu__link:focus-visible {
  background: var(--color-ledger-grey);
}

.mobile-more-menu__badge {
  display: inline-grid;
  min-width: 1.75rem;
  height: 1.75rem;
  place-items: center;
  border-radius: var(--radius-pill);
  background: var(--color-pending-wash);
  color: var(--color-pending);
  font-size: var(--text-xs);
}

.offcanvas {
  --bs-offcanvas-width: min(19rem, 88vw);
}

.offcanvas-header {
  border-bottom: 0.0625rem solid var(--color-rule);
}

.offcanvas-nav {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: var(--space-3);
  list-style: none;
}

.offcanvas-nav__link {
  display: flex;
  min-height: var(--tap-target);
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  color: var(--color-depot-navy);
  font-weight: 700;
  text-decoration: none;
}

.offcanvas-nav__link[aria-current="page"],
.offcanvas-nav__link:hover {
  background: var(--color-transit-wash);
}

.modal-content {
  overflow: hidden;
  border: 0;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-raised);
}

.modal-header,
.modal-footer {
  border-color: var(--color-rule);
}

.modal-warning-mark {
  display: grid;
  width: 2.5rem;
  height: 2.5rem;
  flex: 0 0 auto;
  place-items: center;
  border-radius: 50%;
  background: var(--color-shortfall-wash);
  color: var(--color-shortfall);
  font-weight: 700;
}

.modal-title-group {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.shortfall-table {
  width: 100%;
  margin: var(--space-4) 0;
  border-collapse: collapse;
}

.shortfall-table th,
.shortfall-table td {
  padding: var(--space-3) 0;
  border-bottom: 0.0625rem solid var(--color-rule);
}

.shortfall-table th:last-child,
.shortfall-table td:last-child {
  color: var(--color-shortfall);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  text-align: right;
}

.component-page {
  padding-bottom: var(--space-7);
}

.component-intro {
  padding: var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--color-depot-navy);
  color: var(--color-counter-white);
}

.component-intro h1 {
  margin: 0;
  font-size: var(--text-2xl);
}

.component-intro p {
  max-width: 52rem;
  margin: var(--space-3) 0 0;
  color: rgb(255 255 255 / 0.8);
}

.component-section {
  margin-top: var(--space-6);
  scroll-margin-top: var(--space-5);
}

.component-section > h2 {
  margin: 0 0 var(--space-3);
  color: var(--color-depot-navy);
  font-size: var(--text-lg);
}

.component-demo {
  padding: var(--space-4);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-lg);
  background: var(--color-counter-white);
}

.component-demo + .component-demo {
  margin-top: var(--space-4);
}

.component-label {
  display: block;
  margin-bottom: var(--space-3);
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.component-status-grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.component-demo .desktop-sidebar {
  position: static;
  display: block;
  width: min(100%, var(--sidebar-width));
  height: auto;
  min-height: 30rem;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--color-depot-navy);
}

.component-demo .desktop-sidebar--condensed {
  width: 5rem;
  min-height: 19rem;
}

.desktop-sidebar--condensed .sidebar-brand {
  justify-content: center;
  padding-inline: var(--space-2);
}

.desktop-sidebar--condensed .sidebar-nav {
  padding-inline: var(--space-2);
}

.desktop-sidebar--condensed .sidebar-link {
  justify-content: center;
  padding-inline: var(--space-2);
}

.purchase-layout {
  display: grid;
  gap: var(--space-4);
}

.purchase-workspace {
  display: grid;
  gap: var(--space-4);
}

.school-group + .school-group {
  margin-top: var(--space-4);
}

.school-group__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 0.0625rem solid var(--color-rule);
  background: var(--color-ledger-grey);
}

.school-group__title {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
}

.school-group__count {
  flex: 0 0 auto;
  color: var(--color-pending);
  font-size: var(--text-sm);
  font-weight: 700;
}

.school-group__body {
  padding: var(--space-3);
}

.counter-summary {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

.dashboard-layout,
.dashboard-secondary-grid,
.report-layout {
  display: grid;
  gap: var(--space-4);
}

.trend-chart {
  min-height: 17rem;
  padding: var(--space-3);
}

.trend-chart svg {
  display: block;
  width: 100%;
  height: 15rem;
}

.chart-grid-line {
  stroke: var(--color-rule);
  stroke-width: 1;
}

.chart-area {
  fill: var(--color-transit-wash);
}

.chart-line {
  fill: none;
  stroke: var(--color-transit);
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 4;
}

.chart-dot {
  fill: var(--color-counter-white);
  stroke: var(--color-transit);
  stroke-width: 3;
}

.chart-label {
  fill: var(--color-muted-slate);
  font-family: var(--font-sans);
  font-size: 12px;
}

.dashboard-list {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.dashboard-list__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) 0;
  border-bottom: 0.0625rem solid var(--color-rule);
}

.dashboard-list__item:last-child {
  border-bottom: 0;
}

.dashboard-list__title {
  min-width: 0;
  font-weight: 700;
}

.dashboard-list__meta {
  grid-column: 1 / -1;
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.quantity-state {
  display: inline-flex;
  min-width: 3rem;
  justify-content: flex-end;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.quantity-state--healthy {
  color: var(--color-purchased);
}

.quantity-state--low {
  color: var(--color-pending);
}

.quantity-state--negative {
  color: var(--color-shortfall);
  text-decoration: underline double;
  text-underline-offset: 0.2em;
}

.set-availability {
  display: grid;
  gap: var(--space-3);
}

.set-availability-card {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 0.125rem solid var(--color-pending);
  border-radius: var(--radius-lg);
  background: var(--color-pending-wash);
}

.set-availability-card--blocked {
  border-color: var(--color-shortfall);
  background: var(--color-shortfall-wash);
}

.set-availability-card--blocked .set-capacity,
.set-availability-card--blocked .set-limit {
  color: var(--color-shortfall);
}

.set-availability-card__header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
}

.set-availability-card__title {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
}

.set-capacity {
  color: var(--color-pending);
  font-size: var(--text-lg);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  line-height: var(--line-tight);
}

.set-limit {
  margin: 0;
  color: var(--color-ink);
  font-weight: 700;
}

.set-entry-panel {
  padding: var(--space-4);
  border: 0.0625rem solid var(--color-transit);
  border-radius: var(--radius-md);
  background: var(--color-transit-wash);
}

.set-entry-controls {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.set-expansion {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 0.0625rem solid var(--color-rule);
}

.set-expansion__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
}

.set-expansion__count {
  color: var(--color-transit);
  font-weight: 700;
}

.entry-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-5) 0;
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
  font-weight: 700;
  text-transform: uppercase;
}

.entry-divider::before,
.entry-divider::after {
  height: 0.0625rem;
  flex: 1;
  background: var(--color-rule);
  content: "";
}

.stepper {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 0 0 var(--space-5);
  padding: 0;
  list-style: none;
}

.stepper__item {
  position: relative;
  min-width: 0;
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
  font-weight: 700;
  text-align: center;
}

.stepper__item::before {
  position: relative;
  z-index: 1;
  display: grid;
  width: 2rem;
  height: 2rem;
  margin: 0 auto var(--space-2);
  place-items: center;
  border: 0.125rem solid var(--color-rule);
  border-radius: 50%;
  background: var(--color-counter-white);
  content: attr(data-step);
}

.stepper__item::after {
  position: absolute;
  top: 0.9375rem;
  left: 50%;
  width: 100%;
  height: 0.125rem;
  background: var(--color-rule);
  content: "";
}

.stepper__item:last-child::after {
  display: none;
}

.stepper__item--active,
.stepper__item--complete {
  color: var(--color-depot-navy);
}

.stepper__item--active::before {
  border-color: var(--color-transit);
  background: var(--color-transit);
  color: var(--color-counter-white);
}

.stepper__item--complete::before,
.stepper__item--complete::after {
  border-color: var(--color-purchased);
  background: var(--color-purchased);
  color: var(--color-counter-white);
}

.file-drop {
  padding: var(--space-7) var(--space-4);
  border: 0.125rem dashed var(--color-rule);
  border-radius: var(--radius-lg);
  background: var(--color-ledger-grey);
  text-align: center;
}

.mapping-list {
  display: grid;
  gap: var(--space-3);
}

.mapping-row {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
}

.mapping-row__source {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: 700;
}

.result-strip {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-2);
}

.result-strip__item {
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-ledger-grey);
  text-align: center;
}

.result-strip__figure {
  display: block;
  color: var(--color-depot-navy);
  font-size: var(--text-lg);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.receive-list {
  display: grid;
  gap: var(--space-3);
}

.receive-row {
  padding: var(--space-4);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
}

.receive-row__title {
  margin: 0 0 var(--space-3);
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
}

.quantity-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}

.quantity-readonly {
  display: grid;
  min-height: var(--tap-target);
  place-items: center;
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-ledger-grey);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.discrepancy-field {
  margin-top: var(--space-3);
}

.report-total {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: flex-end;
  gap: var(--space-3) var(--space-5);
  padding: var(--space-4);
  border-top: 0.125rem solid var(--color-depot-navy);
  background: var(--color-ledger-grey);
}

.report-total__label {
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.report-total__figure {
  color: var(--color-depot-navy);
  font-size: var(--text-lg);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.auth-page {
  display: grid;
  min-height: 100vh;
  place-items: center;
  padding: var(--space-4);
  background: var(--color-depot-navy);
}

.auth-card {
  width: min(100%, 27rem);
  padding: var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--color-counter-white);
  box-shadow: var(--shadow-raised);
}

.auth-card__business {
  margin: var(--space-2) 0 var(--space-5);
  color: var(--color-muted-slate);
}

.invoice-page {
  min-height: 100vh;
  padding: var(--space-4);
  background: var(--color-ledger-grey);
}

.invoice-sheet {
  width: min(100%, 36.375rem);
  min-height: 51.125rem;
  margin: 0 auto;
  padding: var(--space-6);
  border: 0.0625rem solid var(--color-rule);
  background: var(--color-counter-white);
  box-shadow: var(--shadow-raised);
  page: invoice;
}

.invoice-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-5);
  border-bottom: 0.1875rem solid var(--color-depot-navy);
}

.invoice-title {
  margin: 0;
  color: var(--color-depot-navy);
  font-size: var(--text-xl);
  font-weight: 700;
}

.invoice-meta,
.invoice-party,
.invoice-totals {
  display: grid;
  gap: var(--space-2);
  margin: var(--space-5) 0;
}

.invoice-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
}

.invoice-line__label {
  color: var(--color-muted-slate);
}

.invoice-line__value {
  text-align: right;
}

.invoice-total {
  padding-top: var(--space-3);
  border-top: 0.125rem solid var(--color-depot-navy);
  color: var(--color-depot-navy);
  font-size: var(--text-lg);
  font-weight: 700;
}

.contact-sheet-grid {
  display: grid;
  gap: var(--space-3);
}

.page-card {
  display: block;
  min-height: 100%;
  padding: var(--space-4);
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
  color: var(--color-ink);
  text-decoration: none;
}

.page-card:hover {
  border-color: var(--color-transit);
  box-shadow: var(--shadow-raised);
}

.page-card__title {
  display: block;
  color: var(--color-depot-navy);
  font-size: var(--text-md);
  font-weight: 700;
}

.page-card__copy {
  display: block;
  margin-top: var(--space-2);
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.error-page {
  display: grid;
  min-height: 100vh;
  place-items: center;
  padding: var(--space-4);
}

.error-card {
  width: min(100%, 36rem);
  padding: var(--space-6);
  text-align: center;
}

.error-code {
  display: block;
  color: var(--color-shortfall);
  font-size: clamp(3.5rem, 18vw, 7rem);
  font-weight: 700;
  line-height: 1;
}

.demo-stage-switcher {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.stage-note {
  margin: 0;
  color: var(--color-muted-slate);
  font-size: var(--text-sm);
}

.compact-id {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

.text-purchased {
  color: var(--color-purchased);
}

.text-pending {
  color: var(--color-pending);
}

.text-shortfall {
  color: var(--color-shortfall);
}

@media (min-width: 36rem) {
  .page-content {
    padding: var(--space-5);
  }

  .page-header {
    flex-direction: row;
    align-items: flex-start;
    justify-content: space-between;
  }

  .page-header__actions {
    justify-content: flex-end;
  }

  .student-search-form {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .student-search-form .btn {
    min-width: 9rem;
  }

  .field-grid--two,
  .repeatable-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .repeatable-row__remove {
    grid-column: 1 / -1;
  }

  .purchased-actions {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .payment-options {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }

  .set-entry-controls {
    grid-template-columns: repeat(2, minmax(0, 1fr)) auto;
    align-items: end;
  }
}

@media (min-width: 48rem) {
  .metric-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .filter-panel__mobile-toggle {
    display: none;
  }

  .filter-panel .collapse {
    display: block;
  }

  .filter-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .filter-actions {
    grid-column: 1 / -1;
    grid-template-columns: auto auto;
    justify-content: end;
  }

  .selection-list__button {
    grid-template-columns: minmax(12rem, 1.2fr) minmax(0, 2fr);
    align-items: center;
  }

  .selection-list__meta {
    grid-template-columns: 0.8fr 0.7fr 1fr 1.5fr;
  }

  .selection-list__meta-item--wide {
    grid-column: auto;
  }

  .dashboard-secondary-grid,
  .report-layout {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .mapping-row {
    grid-template-columns: minmax(12rem, 0.8fr) minmax(0, 1.2fr);
    align-items: center;
  }

  .contact-sheet-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 62rem) {
  body.has-mobile-nav,
  body.purchase-page {
    padding-bottom: 0;
  }

  .app-shell {
    display: grid;
    grid-template-columns: var(--sidebar-width) minmax(0, 1fr);
  }

  .desktop-sidebar {
    position: sticky;
    top: 0;
    display: block;
    height: 100vh;
    overflow-y: auto;
    /* Lifted off the near-black navy so it frames the content rather than
       competing with it, with a hairline edge doing the separating that sheer
       weight used to. Its own token — never --color-depot-navy, which is the
       colour of every heading in the application. */
    border-right: 0.0625rem solid var(--color-sidebar-edge);
    background: var(--color-sidebar-surface);
  }

  .topbar,
  .mobile-tabbar,
  .mobile-more-menu {
    display: none;
  }

  .context-strip {
    grid-template-columns: auto auto;
    justify-content: end;
  }

  .context-strip__item {
    min-width: 14rem;
    padding: var(--space-3) var(--space-4);
  }

  .page-content {
    padding: var(--space-6);
  }

  .purchase-layout {
    grid-template-columns: minmax(0, 1.2fr) minmax(20rem, 0.8fr);
    align-items: start;
  }

  .purchase-layout__search {
    grid-column: 1 / -1;
  }

  .purchase-layout__student {
    position: sticky;
    top: 5.5rem;
  }

  .purchase-layout__details {
    min-width: 0;
  }

  .sticky-purchase-action {
    position: static;
    min-height: 0;
    padding: var(--space-4) 0 0;
    border-top: 0.0625rem solid var(--color-rule);
    box-shadow: none;
  }

  .sticky-purchase-action .btn {
    width: 100%;
  }

  .filter-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .modal-dialog.purchase-shortfall-dialog {
    max-width: 38rem;
  }

  .dashboard-layout {
    grid-template-columns: minmax(0, 1.65fr) minmax(18rem, 0.65fr);
  }

  .contact-sheet-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 61.98rem) {
  .purchase-shortfall-dialog {
    min-height: 100%;
    margin: 0;
    align-items: flex-end;
  }

  .purchase-shortfall-dialog .modal-content {
    max-height: 88vh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }

  .desktop-table-only {
    display: none;
  }
}

@media (min-width: 62rem) {
  .mobile-list-only {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto;
    transition-duration: 0.01ms;
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
  }
}

@media print {
  .desktop-sidebar,
  .topbar,
  .context-strip,
  .mobile-tabbar,
  .mobile-more-menu,
  .sticky-purchase-action,
  .page-header__actions {
    display: none;
  }

  body,
  .app-main {
    background: var(--color-counter-white);
  }

  .app-shell {
    display: block;
  }

  .page-content {
    max-width: none;
    padding: 0;
  }

  .invoice-page {
    min-height: 0;
    padding: 0;
    background: var(--color-counter-white);
  }

  .invoice-sheet {
    width: 148mm;
    min-height: 210mm;
    padding: 12mm;
    border: 0;
    box-shadow: none;
  }
}

@page invoice {
  size: A5 portrait;
  margin: 0;
}

body:not(:has(#mobileNavigation)) [data-bs-target="#mobileNavigation"],
body:not(:has(#ownerNavigation)) [data-bs-target="#ownerNavigation"] {
  display: none;
}

/* ==========================================================================
   Application additions
   --------------------------------------------------------------------------
   Everything below was added when converting the kit into Blade, for chrome
   the static kit did not cover. It uses only the tokens already defined at
   :root above — no new colours, sizes, radii or spacing values.
   ========================================================================== */

/* Account menu ------------------------------------------------------------
   The kit has no sign-out control on any page. On the store shell this is the
   only route to sign-out, so it lives in the top bar, which is visible at
   every width. */

.user-menu__trigger {
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.02em;
}

.user-menu__panel {
  min-width: 14rem;
  padding: 0;
  border: 0.0625rem solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-counter-white);
  box-shadow: var(--shadow-raised);
}

.user-menu__identity {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-4);
  border-bottom: 0.0625rem solid var(--color-rule);
}

.user-menu__name {
  color: var(--color-ink);
  font-size: var(--text-base);
  font-weight: 700;
}

.user-menu__meta {
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
}

.user-menu__signout {
  display: flex;
  width: 100%;
  min-height: var(--tap-target);
  align-items: center;
  padding: var(--space-2) var(--space-4);
  border: 0;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  background: transparent;
  color: var(--color-shortfall);
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: 700;
  text-align: left;
}

.user-menu__signout:hover,
.user-menu__signout:focus-visible {
  background: var(--color-shortfall-wash);
  color: var(--color-shortfall-deep);
}

/* Navigation group headings -----------------------------------------------
   The owner shell gained an Admin group in Phase 0. The heading renders only
   when at least one of its links survives the permission filter. */

.sidebar-nav__group {
  padding: var(--space-3) var(--space-3) var(--space-1);
  color: var(--color-sidebar-muted);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.offcanvas-nav__group {
  padding: var(--space-4) var(--space-4) var(--space-1);
  color: var(--color-muted-slate);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Mobile tab bar column count ---------------------------------------------
   The kit hardcodes four columns. Tabs are filtered by permission, so a
   read-only viewer may have fewer; the bar divides evenly whatever it has. */

.mobile-tabbar[data-tabs="1"] { grid-template-columns: repeat(1, minmax(0, 1fr)); }
.mobile-tabbar[data-tabs="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.mobile-tabbar[data-tabs="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.mobile-tabbar[data-tabs="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Touch targets ------------------------------------------------------------
   Found by the 360px pass (CLAUDE.md Phase 2.5, finding 3). Bootstrap's
   checkbox is 16x16 and its pagination link is 38px tall; both are well under
   the 44px a finger needs, and both repeat across every screen — 15 class
   checkboxes on a school, 40 departure checkboxes on an import result, a
   pager on every list.

   The fix is the whole row, not a giant checkbox. A 48px control would look
   absurd; a 24px control inside a 48px row whose label is also clickable
   gives a 48px-tall target the width of the surface, which is what a thumb
   actually hits. --tap-target is the kit's own token, already used by
   .icon-button and the form controls. */

.form-check {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap-target);
  padding-left: 0;
  margin-bottom: 0;
}

.form-check .form-check-input {
  flex: 0 0 auto;
  width: 1.5rem;
  height: 1.5rem;
  margin: 0;
  cursor: pointer;
}

/* The label carries the rest of the row, so the tappable area is the whole
   strip rather than the box alone. */
.form-check .form-check-label {
  flex: 1 1 auto;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: var(--tap-target);
  cursor: pointer;
}

.pagination .page-link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap-target);
  min-width: var(--tap-target);
}

/* A reason sentence on a record card. Prose, not a value: it reads as a line
   of explanation under the details grid rather than as a labelled field. */

.mobile-record__note {
  margin: 0 0 var(--space-3);
  color: var(--color-muted-slate);
}

/* Context strip on a narrow screen -----------------------------------------
   The store label is the one piece of identity this strip exists to carry,
   and at 360px "Nurpur Branch · STR-001" was being ellipsed to
   "Nurpur Branch · ST…" — a store user could not read their own store's code
   (CLAUDE.md Phase 2.5, finding 5).

   Below the tablet breakpoint the value wraps instead of truncating. Two
   short lines and a slightly taller strip cost nothing; an unreadable code
   costs a phone call to the main store. */

@media (max-width: 47.99rem) {
  .context-strip__value {
    flex-wrap: wrap;
    row-gap: 0;
  }

  .context-strip__value-text {
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

/* The remove control on an applied-filter chip is 28px of visible circle, and
   a 48px circle would swallow the chip it sits in. So the hit area is extended
   past the visible control instead: the ::after box is the target, the circle
   is the picture. Position is relative on the chip already being inline-flex,
   so this stays inside the chip's own stacking context and cannot cover the
   next chip's text. */

.filter-chip {
  position: relative;
}

.filter-chip__remove {
  position: relative;
}

.filter-chip__remove::after {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--tap-target);
  height: var(--tap-target);
  transform: translate(-50%, -50%);
  content: "";
}

/* An identifier that is also a link.
   .compact-id is usually a plain span in a table cell — an admission number, an
   invoice number — and a 44px floor on all of them would put a thumb's worth of
   air into every row of every list. But Phase 5 made one a link (the invoice on
   a reversal's screen), which the 360px pass caught at 141x19, and Phase 6's
   reports will link invoice numbers everywhere.
   So the rule is scoped to the anchor: the glyph stays the picture and the box
   becomes the target, the same ::after pattern .btn-close and
   .filter-chip__remove already use. */
a.compact-id {
  position: relative;
  display: inline-block;
}

a.compact-id::after {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  min-height: var(--tap-target);
  height: 100%;
  transform: translateY(-50%);
  content: "";
}

/* A dashboard-list row title that is also a link — the same case, one phase
   later, and caught the same way.
   .dashboard-list__title is a span everywhere the kit uses it: the low-stock
   and in-transit panels are labels beside a figure, not destinations. Phase 6's
   reports index makes it a link, and the 360px pass measured it at 282x24 — the
   width was never the problem, the height was.
   Scoped to the anchor for the reason a.compact-id is: a 44px floor on every
   .dashboard-list__title would put a thumb's worth of air into the dashboard
   panels, which are deliberately compact rows a reader scans rather than taps. */
a.dashboard-list__title {
  display: flex;
  align-items: center;
  min-height: var(--tap-target);
}

/* A metric card's secondary line, when it is a link.
   Third time this shape has appeared — a.compact-id in Phase 5,
   a.dashboard-list__title in Phase 6 Part A, and now this — and the cause is
   always the same: the kit uses a class as a label and the application turns
   one instance of it into a destination. The 360px pass caught these at 17px
   and 35px tall.
   min-height rather than the ::after hit extension the smaller controls use.
   The extension works where a glyph sits alone in white space; here three of
   these stack down a column of cards, and a 44px box centred on a 17px line
   would reach into the card below and steal its taps. Growing the line is the
   honest fix, and the grid stretches the cards to match. */
.metric-block__secondary a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
}

/* The invoice's closing line. The kit spelled it as Bootstrap utilities
   (mt-5 pt-4 border-top text-center), which the PDF cannot borrow — dompdf
   fetches nothing over the network, so it carries its own stylesheet and would
   have had to restate four utility classes to match. One named class, defined
   here and restated once in the PDF template, keeps the paper and the file
   looking like the same document. */

.invoice-footer {
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 0.0625rem solid var(--color-rule);
  text-align: center;
}

.invoice-footer p {
  margin: 0;
}

/* The invoice's own actions — print, download, WhatsApp — above the sheet and
   never on it. print:none rather than a second template, so what goes on paper
   is exactly what is on screen. */

.invoice-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  max-width: 148mm;
  margin: 0 auto var(--space-4);
}

.invoice-actions .btn {
  flex: 1 1 auto;
}

@media print {
  .invoice-actions {
    display: none;
  }
}

/* Bootstrap's .btn-close is 32px, which is under the 44px target, and it is
   the dismiss control on every dialog in the application — the shortfall
   modal now, the return and cancellation dialogs in Phase 5.

   The 360px pass never caught it before Phase 3 because no modal was ever open
   during the walk: the audit measures pages, and until the shortfall there was
   no page whose modal was server-rendered.

   Extended rather than enlarged, the same way .filter-chip__remove is: a 44px
   × drawn in a modal header looks like a mistake, so the ::after box is the
   target and the glyph stays the picture. Kept inside the button's own
   stacking context so it cannot cover the title beside it. */

.modal-header .btn-close {
  position: relative;
}

.modal-header .btn-close::after {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--tap-target);
  height: var(--tap-target);
  transform: translate(-50%, -50%);
  content: "";
}
