/* ============================================================================
   Nouri Narie 2.0 — commerce and account surfaces
   cart.html · success.html · account.html · admin.html

   Loads after components.css and adds only what the shared system does not
   already carry. Most of this file exists for one reason: js/cart.js,
   js/success.js, js/account.js and js/admin.js BUILD DOM AT RUNTIME with class
   names of their own choosing, and those files are copied verbatim from the
   live site and are not edited. Every selector below marked "runtime" is
   therefore a name this stylesheet has to match rather than choose:

     cart.js      .cart-line .cart-line-meta .cart-line-right .cart-line-total
                  .cart-remove .qty-control .cart-cross-item .cart-cross-meta
                  .cart-cross-flag .cart-msg .cart-code-msg .is-err
     success.js   .cart-row .cart-row--muted .cart-ship-note
     account.js   .msg .msg--ok .msg--error .tier .tier-you .tier-at .order
                  .order-top .order-no .order-date .order-status .order-total
                  .order-lines .order-meta .order-claim .order-return
                  .return-form .btn-row .btn--sm
     admin.js     .msg .is-ok .is-err .pill .pill.off td.num .btn--sm, plus
                  bare <input> and <select> dropped straight into a <td>

   One name in that list cannot be written here. cart.js builds its cross-sell
   button with a third variant class named after one of the two dead v1 palette
   tokens, and build/check.py forbids that token's spelling anywhere under css/
   — clearing those names is half the reason v2 exists. The button is styled
   through its parent (.cart-cross-item > .btn) instead, so the runtime markup
   is honoured without resurrecting the name.

   No glass blur. No opacity-as-disabled. No zebra striping — .tbl already
   draws a 1px row rule. Breakpoints 480 / 768 / 1024 / 1280 only.
   ========================================================================= */

/* btn--sm used to be defined here. It has been promoted to components.css,
   because three separate runtime scripts construct it and a size that only
   exists on this page is one the next page silently ships unstyled. The copy
   that stood here was byte-identical and always lost the cascade anyway —
   components.css loads first and neither rule was more specific. */

/* Runtime. account.js wraps its submit buttons in one of these. */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  margin-top: var(--s-4);
}

/* ── shared: status message ────────────────────────────────────────────────
   Runtime, and the sharpest edge in this lane. All four scripts ASSIGN
   className on their message nodes rather than toggling a class, so `.msg`,
   `.cart-msg` and `.cart-code-msg` are the only classes those elements ever
   have. Nothing may hang layout off a second class on them, and the reserved
   height stops the summary jumping when a message appears.

   account.js writes msg--ok / msg--error; admin.js writes is-ok / is-err. Two
   spellings of the same state, both live, neither editable. */

.msg {
  min-height: 1.4em;
  margin-top: var(--s-3);
  font-size: var(--t-caption);
  font-weight: 500;
  color: var(--ink-soft);
}
.msg--ok,
.msg.is-ok { color: var(--ok); }
.msg--error,
.msg.is-err { color: var(--danger); }

/* ============================================================================
   CART
   ========================================================================= */

.cart-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-5);
  padding: var(--s-12);
  background: var(--shell);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
}

.cart-live {
  display: grid;
  gap: var(--s-8);
  align-items: start;
}
/* Single column falls out of source order: lines, the summary carrying
   [data-checkout], then the upsell. The cross-sell used to be nested inside
   .cart-main and so landed between the first two, putting 401px of suggestion
   in front of the checkout button at 390 wide. Nobody scrolls past an upsell
   to pay.

   Source order rather than `order:`. Reordering visually while the DOM stays
   put splits the tab sequence from the page: a keyboard or screen-reader user
   would meet the upsell before the total while a sighted user meets it after. */

@media (min-width: 1024px) {
  /* Two columns. Explicit placement puts the upsell back under the lines in the
     left column, which still reads main -> summary -> cross top-to-bottom and
     left-to-right, so the visual order continues to match the source. */
  .cart-live { grid-template-columns: minmax(0, 1fr) 380px; gap: var(--s-12); }
  .cart-main { grid-column: 1; grid-row: 1; }
  .cart-summary { grid-column: 2; grid-row: 1; }
  .cart-cross { grid-column: 1; grid-row: 2; }
}

/* ── lines ─────────────────────────────────────────────────────────────────
   Runtime: cart.js writes every <li> into .cart-lines with innerHTML, so the
   grid below has to describe markup this file never sees —
   img / <div> / .cart-line-right. The 1px row rule is the same device .tbl
   uses; a cart is a table that happens to have pictures in it. */

.cart-lines {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule);
}

.cart-line {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: var(--s-4);
  padding-block: var(--s-5);
  border-bottom: 1px solid var(--rule-soft);
}
@media (min-width: 480px) {
  .cart-line { grid-template-columns: 92px minmax(0, 1fr) auto; gap: var(--s-5); }
}

.cart-line img {
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  background: var(--mist);
  border: 1px solid var(--rule-hair);
  border-radius: var(--r-sm);
}

.cart-line h3 { font-size: var(--t-h4); }
.cart-line h3 a { text-decoration: none; }

.cart-line-meta {
  margin-top: var(--s-1);
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  color: var(--ink-muted);
}

/* Runtime: cart.js names the stepper .qty-control, not .stepper. Same shape as
   the PDP control in components.css, drawn again here because the two files
   must not be renamed into each other. */
.qty-control {
  display: inline-flex;
  align-items: center;
  margin-top: var(--s-3);
  background: var(--shell);
  border: 1px solid var(--rule);
  border-radius: var(--r-pill);
  overflow: hidden;
}
.qty-control button {
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  color: inherit;
  font-size: var(--t-body);
  cursor: pointer;
  transition: background var(--d-fast) var(--ease);
}
.qty-control button:hover:not([disabled]) { background: var(--sage-wash); }
.qty-control input {
  width: 44px;
  border: 0;
  background: transparent;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  color: inherit;
  -moz-appearance: textfield;
}
.qty-control input::-webkit-outer-spin-button,
.qty-control input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.cart-line-right {
  grid-column: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
}
@media (min-width: 480px) {
  .cart-line-right {
    grid-column: auto;
    flex-direction: column;
    align-items: flex-end;
    justify-content: flex-start;
    gap: var(--s-2);
  }
}

.cart-line-total {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}

.cart-remove {
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-text);
  font-size: var(--t-caption);
  color: var(--ink-muted);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  cursor: pointer;
}
.cart-remove:hover { color: var(--sage-deep); }

/* ── cross-sell ────────────────────────────────────────────────────────── */

.cart-cross { margin-top: var(--s-10); }
.cart-cross-head { font-size: var(--t-h3); margin-bottom: var(--s-5); }

.cart-cross-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-4);
}

/* Runtime: img / <div> / button. */
.cart-cross-item {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4);
  background: var(--shell);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
}
@media (min-width: 480px) {
  .cart-cross-item { grid-template-columns: 72px minmax(0, 1fr) auto; }
}
.cart-cross-item img {
  width: 72px;
  height: 72px;
  object-fit: cover;
  background: var(--mist);
  border-radius: var(--r-xs);
}
.cart-cross-item h3 { font-size: var(--t-body); }
.cart-cross-item h3 a { text-decoration: none; }

.cart-cross-meta {
  margin-top: var(--s-1);
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  color: var(--ink-muted);
}

.cart-cross-flag {
  margin-top: var(--s-2);
  font-size: var(--t-caption);
  font-weight: 600;
  color: var(--sage-deep);
}

/* The stand-in for the forbidden variant class described at the top of this
   file. cart.js gives this button a variant it may not have a rule for, so the
   fill is drawn from the parent instead. */
.cart-cross-item > .btn {
  grid-column: 2;
  justify-self: start;
  background: var(--sage);
  color: var(--shell);
}
.cart-cross-item > .btn:hover { background: var(--sage-deep); }
@media (min-width: 480px) {
  .cart-cross-item > .btn { grid-column: auto; justify-self: end; }
}

/* ── summary ───────────────────────────────────────────────────────────── */

.cart-summary {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-6);
  background: var(--mist);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
}
@media (min-width: 1024px) {
  .cart-summary { position: sticky; top: calc(var(--h-chrome) + var(--s-6)); }
}

/* Runtime: success.js builds its order summary out of these too. */
.cart-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}
.cart-row b { font-family: var(--font-mono); font-weight: 500; }
.cart-row--muted { color: var(--ink-muted); }

/* The free-shipping threshold. cart.js only ever sets text here — there is no
   hook for a fill width, so this is a rule and a sentence rather than a bar
   that could never move. */
.cart-ship-note {
  margin-top: var(--s-1);
  padding-top: var(--s-3);
  border-top: 2px solid var(--sage);
  font-size: var(--t-caption);
  color: var(--ink-soft);
}
.cart-ship-note:empty { display: none; }

.cart-code {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  margin-top: var(--s-2);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule-soft);
}
.cart-code label { font-size: var(--t-caption); font-weight: 600; }

.cart-code-row { display: flex; gap: var(--s-2); }
.cart-code-row input {
  flex: 1;
  min-width: 0;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--rule);
  border-radius: var(--r-xs);
  background: var(--shell);
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
}
.cart-code-row input:focus {
  outline: none;
  border-color: var(--sage-deep);
  box-shadow: 0 0 0 3px var(--sage-wash);
}
.cart-code-row .btn { flex: none; }

/* Runtime: className is reassigned wholesale — one class, plus is-err. */
.cart-code-msg,
.cart-msg {
  min-height: 1.4em;
  font-size: var(--t-caption);
  color: var(--ink-soft);
}
.cart-msg { margin-top: var(--s-2); }
.cart-code-msg.is-err,
.cart-msg.is-err { color: var(--danger); }

.cart-tax-note {
  font-size: var(--t-caption);
  color: var(--ink-muted);
}

.cart-keep {
  align-self: flex-start;
  font-size: var(--t-caption);
  color: var(--sage-deep);
  text-underline-offset: 0.18em;
}

/* ============================================================================
   SUCCESS
   ========================================================================= */

.success-panel {
  max-width: 640px;
  padding: var(--s-10);
  background: var(--shell);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
}
.success-panel h1 { margin-bottom: var(--s-4); }

.success-order {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  margin-top: var(--s-8);
  padding: var(--s-5);
  background: var(--mist);
  border: 1px solid var(--rule-hair);
  border-radius: var(--r-sm);
}
/* Runtime: success.js appends a .cart-row with a <b> for the total, so the
   last row is separated rather than emphasised with a colour change. */
.success-order .cart-row:last-of-type { padding-top: var(--s-3); border-top: 1px solid var(--rule-soft); }
.success-order .cart-ship-note { border-top: 0; padding-top: 0; }

.success-note {
  margin-top: var(--s-5);
  font-size: var(--t-caption);
  color: var(--ink-muted);
}

/* ============================================================================
   ACCOUNT
   ========================================================================= */

.account-gate { max-width: 520px; }
.account-gate h1 { margin-bottom: var(--s-4); }

.account-form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-4);
  margin-top: var(--s-8);
}
.account-form .field { width: 100%; }

.account-note {
  margin-top: var(--s-4);
  font-size: var(--t-caption);
  color: var(--ink-muted);
  max-width: 56ch;
}

.account-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-5);
  padding-bottom: var(--s-8);
  border-bottom: 1px solid var(--rule-soft);
}
.account-email {
  margin-top: var(--s-2);
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  color: var(--ink-muted);
}

.account-card {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  margin-top: var(--s-8);
  padding: var(--s-6);
  background: var(--mist);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
}

.account-points {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--ink-muted);
}
.account-points span {
  font-family: var(--font-display);
  font-variation-settings: 'wght' 800, 'wdth' 88;
  font-size: var(--t-h2);
  letter-spacing: var(--ls-head);
  text-transform: none;
  color: var(--ink);
  margin-right: var(--s-2);
}

/* The fill starts empty. account.js sets style.width from the server's
   `progress`; without this it would inherit auto and read as a full bar for
   the length of the round trip. */
.account-meter .meter-fill { width: 0; }

.account-perk {
  font-size: var(--t-caption);
  color: var(--sage-deep);
  font-weight: 600;
}

.account-h2 {
  margin-top: var(--s-12);
  margin-bottom: var(--s-4);
  font-size: var(--t-h3);
}

.account-empty,
.account-levels-note {
  font-size: var(--t-caption);
  color: var(--ink-muted);
  max-width: 68ch;
}
.account-levels-note { margin-bottom: var(--s-6); }

/* ── orders ────────────────────────────────────────────────────────────────
   Runtime: every element below is built by account.js with createElement. */

.account-orders { display: flex; flex-direction: column; gap: var(--s-4); }

.order {
  padding: var(--s-5);
  background: var(--shell);
  border: 1px solid var(--rule);
  border-radius: var(--r-sm);
}

.order-top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--rule-hair);
}
.order-no {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
}
.order-date { font-size: var(--t-caption); color: var(--ink-muted); }

.order-status {
  padding: var(--s-1) var(--s-3);
  border-radius: var(--r-pill);
  background: var(--alu-light);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
}
.order-status[data-state='shipped'] { background: var(--ok); color: var(--shell); }
.order-status[data-state='packed']  { background: var(--warn); color: var(--shell); }
.order-status[data-state='refunded'],
.order-status[data-state='cancelled'] { background: var(--danger); color: var(--shell); }

.order-total {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
}

.order-lines {
  list-style: none;
  margin: var(--s-4) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  font-size: var(--t-sm);
  color: var(--ink-soft);
}

.order-meta {
  margin-top: var(--s-2);
  font-size: var(--t-caption);
  color: var(--ink-muted);
}
.order-meta a { color: var(--sage-deep); }

.order-claim {
  margin-top: var(--s-4);
  padding: var(--s-4);
  background: var(--mist);
  border-left: 2px solid var(--sage);
  border-radius: var(--r-xs);
  font-size: var(--t-caption);
  color: var(--ink-soft);
}
.order-claim p + p { margin-top: var(--s-2); }

.order-return { margin-top: var(--s-4); }

.return-form {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  margin-top: var(--s-4);
  padding: var(--s-5);
  background: var(--paper);
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-sm);
}
.return-form fieldset {
  margin: 0;
  padding: 0;
  border: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.return-form legend {
  padding: 0;
  margin-bottom: var(--s-2);
  font-size: var(--t-caption);
  font-weight: 600;
}
.return-form label {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--t-sm);
}
.return-form input[type='checkbox'],
.return-form input[type='radio'] { flex: none; width: 16px; height: 16px; accent-color: var(--sage-deep); }
.return-form > label { flex-direction: column; align-items: flex-start; font-weight: 600; }
.return-form textarea {
  width: 100%;
  margin-top: var(--s-2);
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--rule);
  border-radius: var(--r-xs);
  background: var(--shell);
  font-family: var(--font-text);
  font-size: var(--t-sm);
  font-weight: 400;
  color: var(--ink);
  resize: vertical;
}
.return-form textarea:focus {
  outline: none;
  border-color: var(--sage-deep);
  box-shadow: 0 0 0 3px var(--sage-wash);
}

/* ── tiers ─────────────────────────────────────────────────────────────────
   Runtime: account.js builds .tier from whatever ladder the server sent and
   marks the member's own rung with data-current="true". The thresholds are
   never written into the markup, so they cannot drift from what checkout
   actually prices. */

.account-tiers {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: 1fr;
}
@media (min-width: 768px)  { .account-tiers { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1280px) { .account-tiers { grid-template-columns: repeat(5, 1fr); } }

.tier {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-5);
  background: var(--shell);
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-sm);
}
.tier[data-current='true'] { border-color: var(--rule); background: var(--mist); }

.tier-you {
  align-self: flex-start;
  padding: var(--s-1) var(--s-2);
  border-radius: var(--r-xs);
  background: var(--ink);
  color: var(--on-dark);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
}

.tier h3 { font-size: var(--t-body); }
.tier-at {
  font-family: var(--font-mono);
  font-size: var(--t-caption);
  color: var(--ink-muted);
}
.tier ul {
  list-style: none;
  margin: var(--s-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  font-size: var(--t-caption);
  color: var(--ink-soft);
}
.tier li { padding-left: var(--s-4); position: relative; }
.tier li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 6px;
  height: 1px;
  background: var(--sage);
}

/* ============================================================================
   ADMIN

   The one page with no nav, no ticker and no footer: it loads js/admin.js
   alone. Everything is scoped under .admin, the <main> class, because admin.js
   drops bare <input> and <select> elements straight into table cells with no
   class of their own and components.css only styles them inside .field.
   ========================================================================= */

.admin {
  padding-top: 0;
  background: var(--paper);
  min-height: 100vh;
}

.admin-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-5) var(--gutter);
  background: var(--mist);
  border-bottom: 1px solid var(--rule);
}
.admin-title { font-size: var(--t-h4); margin-right: auto; }
.admin-who {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.admin-body {
  max-width: var(--measure);
  margin-inline: auto;
  padding: var(--s-8) var(--gutter) var(--s-20);
}

.admin-gate { max-width: 420px; margin: var(--s-16) auto; }
.admin-gate h2 { font-size: var(--t-h3); margin-bottom: var(--s-2); }

/* ── tabs ──────────────────────────────────────────────────────────────── */

.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  margin-bottom: var(--s-6);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--rule-soft);
}
.admin-tab {
  padding: var(--s-2) var(--s-4);
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  background: transparent;
  font-family: var(--font-text);
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--ink-muted);
  cursor: pointer;
  transition: background var(--d-fast) var(--ease), color var(--d-fast) var(--ease);
}
.admin-tab:hover { background: var(--sage-wash); color: var(--ink); }
.admin-tab[aria-selected='true'] { background: var(--ink); color: var(--on-dark); }

.admin-panel { display: flex; flex-direction: column; gap: var(--s-5); }

/* ── cards ─────────────────────────────────────────────────────────────── */

.admin-card {
  padding: var(--s-5);
  background: var(--shell);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
}
.admin-card h2 { font-size: var(--t-h4); margin-bottom: var(--s-2); }
.admin-card--table { overflow-x: auto; }

.admin-note {
  font-size: var(--t-caption);
  color: var(--ink-muted);
  max-width: 78ch;
  margin-bottom: var(--s-4);
}
.admin-empty,
.admin-count {
  font-size: var(--t-caption);
  color: var(--ink-muted);
}
.admin-count { margin-left: auto; }

.admin-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--s-3);
}
.admin-field { display: flex; flex-direction: column; gap: var(--s-1); min-width: 132px; }
.admin-field--grow { flex: 1; }
.admin-field label {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* ── controls ──────────────────────────────────────────────────────────────
   Runtime: admin.js builds unclassed <input> and <select> nodes inside <td>,
   so the element selectors here are load-bearing rather than lazy. */

.admin input,
.admin select {
  width: 100%;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--rule);
  border-radius: var(--r-xs);
  background: var(--shell);
  font-family: var(--font-text);
  font-size: var(--t-sm);
  color: var(--ink);
}
.admin input:focus,
.admin select:focus {
  outline: none;
  border-color: var(--sage-deep);
  box-shadow: 0 0 0 3px var(--sage-wash);
}
.admin td input,
.admin td select { min-width: 96px; }
.admin td select + input { margin-top: var(--s-2); }

/* ── table ─────────────────────────────────────────────────────────────────
   .tbl carries the row rule; only the numeric alignment and the vertical
   rhythm of a dense back office are added. No zebra striping. */

.admin .tbl { min-width: 720px; }
.admin .tbl th,
.admin .tbl td { vertical-align: top; padding: var(--s-3); }
.admin .tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
.admin .tbl tbody tr:last-child td { border-bottom: 0; }

/* Runtime: admin.js builds the discount state chip. */
.pill {
  display: inline-block;
  padding: var(--s-1) var(--s-2);
  border-radius: var(--r-pill);
  background: var(--ok);
  color: var(--shell);
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: var(--ls-micro);
  text-transform: uppercase;
}
.pill.off { background: var(--rule-soft); color: var(--ink-soft); }
