
body{font-family:var(--sans);font-variant-numeric:tabular-nums}
h1{letter-spacing:-.025em}
code,pre{font-variant-numeric:tabular-nums}
.card,section.card{border-color:var(--line)}
button,.ghost,.btnlink,.lbl,a.back,.ni,.chip{transition:background .16s ease,border-color .16s ease,
  color .16s ease,transform .12s ease,box-shadow .16s ease}
button:hover,.ghost:hover,.lbl:hover{background:var(--inset);border-color:var(--line-strong)}
button:active,.ghost:active,.lbl:active,.chip:active{transform:translateY(1px)}
:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:2px;border-radius:6px}
.ni{border-radius:8px}
.ni:hover{background:var(--inset);color:var(--ink)}
.ni.on{background:var(--rdy-bg);color:var(--rdy-ink);font-weight:600;box-shadow:inset 2px 0 0 #06d6bd}
.nitems{gap:14px}
.ngrp{display:flex;flex-direction:column;gap:1px}
.nlab{font-size:10px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-3);padding:0 10px 5px}
.nfoot{margin-top:auto}
a{transition:color .16s ease}

/* ---- muted text meets AA ----------------------------------------------
   --ink-3 measured 3.09:1 against the page - below the 4.5:1 body-text floor,
   and it is used for hints and metadata, which are read, not decoration. */
:root{--ink-3:#6e716b}

/* ---- mobile: the in-shell rail got none of the collapse rules ----------
   The injected rail folds to a horizontal strip under 860px; the two pages
   that build the rail into their own shell never got the matching rules, so
   the grouped nav stayed a 542px column inside a 390px viewport and pushed the
   whole page sideways. Wide tables scroll inside themselves rather than
   dragging the document with them. */
@media(max-width:860px){
  /* once the shell stacks, the content column has to take the viewport rather
     than the width its widest row would like - otherwise the header row sets
     an 818px floor and drags the whole document sideways. */
  .shell{flex-direction:column}
  .col{width:100%;min-width:0;max-width:100%}
  .hrow,.hrow.toolbar,.qlead{flex-wrap:wrap;max-width:100%}
  /* the order rows are a real grid with real columns; on a phone they scroll
     inside their band rather than squeezing to illegibility or dragging the
     page. Same treatment as the wide tables above. */
  .qgrp .grows,.qgrp .colhead{overflow-x:auto}
  .rail .nitems{flex-direction:row;flex-wrap:wrap;gap:8px}
  .rail .ngrp{flex-direction:row;flex-wrap:wrap;gap:2px}
  .rail .nlab{display:none}
  .rail .nfoot{margin-top:0}
  table{display:block;overflow-x:auto;max-width:100%}
}

/* ---- the accent family, finished --------------------------------------
   --accent moved to teal but its derivatives did not, so a teal button hovered
   to indigo and every accent-tinted surface and border stayed indigo. Fifty-
   eight places referenced them. A half-migrated palette is worse than either
   whole one, because the mismatch reads as a bug rather than a choice. */
:root{
  --accent-h:#0b8f83; --accent-soft:#ecfffc; --accent-line:#6ff0e0;
  --inset:#fafaf9;
}

/* ---- one type size per role ------------------------------------------
   Page titles were 17, 18, 19, 20 and 21px across the pages - five sizes for
   one role, which is what makes the portal read as several products stitched
   together rather than one. */
h1{font-size:21px;font-weight:600;letter-spacing:-.025em}
@media(max-width:860px){h1{font-size:19px}}

/* ---- elevation is declared once --------------------------------------
   A 1px border under a wide soft shadow is the ghost card: two elevation
   systems arguing. At this density the border is the more legible of the two,
   so it keeps the job and the ambient shadow goes. Shadow is reserved for
   things that genuinely float - the armed commit bar, menus, dialogs. */
.card,section.card{box-shadow:none}
.pmenu[open] .pmenu-list{box-shadow:0 10px 30px -12px rgba(25,26,23,.28)}

/* ---- the row stripe goes ---------------------------------------------
   Each row carried a 4px coloured left edge driven by the same four states the
   bands now carry, and still on the old mapping - so a needs-you row showed a
   RED stripe inside an AMBER zone. Two encodings of one fact, already
   disagreeing. The zone is the better carrier: it groups, it labels, and it
   does not put a coloured bar on every row in the queue. */
.qgrp:has(.grph.attn) .grows article{border-left-color:var(--attn-line)}
.qgrp:has(.grph.ready) .grows article{border-left-color:var(--rdy-line)}
.qgrp:has(.grph.bought) .grows article{border-left-color:var(--blue-line)}
.qgrp:has(.grph.shipped) .grows article{border-left-color:var(--green-line)}
.grows article{box-shadow:none}

/* a booked pickup reads from its fill, not from a bar down its edge */
.booked{border-left-width:1px}

/* width animates layout; the same motion on transform does not */
.bar span{transition:transform .2s ease-out;transform-origin:left}

/* ---- queue state colours -------------------------------------------------
   One meaning per colour, never borrowed. Red is kept for things that BROKE
   (a failed push, a refused label) rather than spent on "this order needs an
   address", which is a person's job, not an alarm.
     amber  a person is needed        teal   ready to act on, and money
     blue   bought and in flight      green  done and good
   The green replaces #16a34a, a saturated success-toast green that read cheap
   beside the neutrals. This is a muted sage carrying the same meaning. */
:root{
  --attn:#f59e0b; --attn-bg:#fffbeb; --attn-line:#fde68a; --attn-ink:#b45309;
  --rdy:#06d6bd;  --rdy-bg:#ecfffc;  --rdy-line:#6ff0e0;  --rdy-ink:#0b8f83;
  --green:#4c9a72; --green-bg:#eef5f0; --green-line:#c8ddd0; --green-ink:#2c6146;
}
/* needs-you moves from red to amber, ready from amber to teal - so teal is the
   same colour as the button that spends the money, and red is free to mean broken */
.gdot.attn{background:var(--attn)}
.grph.attn{color:var(--attn-ink)}
.grph.attn .gcount{color:var(--attn-ink);background:var(--amber-bg);border-color:var(--attn-line)}
.gdot.ready{background:var(--rdy)}
.grph.ready{color:var(--rdy-ink)}
.grph.ready .gcount{color:var(--rdy-ink);background:var(--rdy-bg);border-color:var(--rdy-line)}

/* ---- each state becomes a ZONE, not a row with a dot ---- */
.qgrp{border:1px solid var(--line);border-radius:14px;padding:11px 12px 12px;background:var(--surface)}
.qgrp .grph{padding:2px 3px 9px}
.qgrp:has(.grph.attn){background:var(--attn-bg);border-color:var(--attn-line)}
.qgrp:has(.grph.ready){background:var(--rdy-bg);border-color:var(--rdy-line);
  box-shadow:0 1px 2px rgba(6,214,189,.10),0 10px 28px -12px rgba(6,214,189,.30)}
.qgrp:has(.grph.bought){background:var(--blue-bg);border-color:var(--blue-line)}
.qgrp:has(.grph.shipped){background:var(--green-bg);border-color:var(--green-line)}
/* the rows themselves stay on white so the tint reads as the container */
.qgrp .grows{background:var(--surface);border:1px solid var(--line);border-radius:10px;overflow:hidden}
.qgrp:has(.grph.attn) .grows{border-color:var(--attn-line)}
.qgrp:has(.grph.ready) .grows{border-color:var(--rdy-line)}
.qgrp:has(.grph.bought) .grows{border-color:var(--blue-line)}
.qgrp:has(.grph.shipped) .grows{border-color:var(--green-line)}

/* ---- status slots become chips instead of pipe-separated text ---- */
.hand .slot{border-right:0;margin-right:0;padding:3px 9px;border-radius:7px;
  background:var(--green-bg);color:var(--green-ink)}
.hand .slot b{color:var(--green-ink)}
.hand .slot.warn,.hand .slot.warn b{background:var(--attn-bg);color:var(--attn-ink)}
.hand .slot.na{background:transparent;color:var(--ink-3);padding-left:0}
.hand{gap:6px 6px}
.hacts{gap:6px}
.lbl.go{border-color:var(--rdy-line);color:var(--rdy-ink);background:var(--rdy-bg);font-weight:600}

/* ---- the money bar reads as a different kind of act ---- */
/* idle: the ordinary card. It becomes the dark slab only once money is at stake. */
.commit{transition:background .18s ease,border-color .18s ease,color .18s ease}

/* ---- the decision line ---- */
.qlead{display:flex;align-items:baseline;gap:13px;flex-wrap:wrap;margin:16px 26px 0;max-width:1360px}
.qlead h2{margin:0;font-size:27px;font-weight:700;letter-spacing:-.032em;line-height:1.1}
.qlead h2.attn{color:var(--attn-ink)} .qlead h2.rdy{color:var(--rdy-ink)}
.qlead span{font-size:14px;color:var(--ink-2)}
.qlead b{color:var(--ink);font-weight:600}
.qlead .mono{font-variant-numeric:tabular-nums;font-weight:600;color:var(--ink)}
@media (max-width:860px){.qlead{margin:14px 14px 0}.qlead h2{font-size:22px}}

/* An idle bar has no business being a heavy dark slab - it escalates only when
   there is money at stake, which is what makes the dark mean something. */
.commit.armed{background:var(--solid);border-color:var(--solid);color:var(--surface)}
.commit.armed .cbig,.commit.armed .cval,.commit.armed b,.commit.armed strong{color:var(--surface)}
.commit.armed .csub,.commit.armed .lbl{color:var(--out-rail);background:transparent;border:0}
.commit.armed .pay{background:var(--rdy);border-color:var(--rdy);color:var(--rdy-ink);font-weight:600}
.commit.armed .pay:hover{background:var(--accent);border-color:var(--accent)}
.commit.armed .ghost{background:transparent;border-color:var(--ink-2);color:var(--line)}
.commit.armed .ghost:hover{background:var(--solid);border-color:var(--ink-2)}

/* ---- tiles: quieter, so the sentence above them can lead ---- */
.tiles{margin-top:11px}
.tile .tn{font-size:23px}
.tile.attn{border-top-color:var(--attn)} .tile.attn .tn{color:var(--attn-ink)}
.tile.ready{border-top-color:var(--rdy)} .tile.ready .tn{color:var(--rdy-ink)}
@media (prefers-reduced-motion:reduce){*{transition-duration:.01ms!important;animation-duration:.01ms!important}}
