/* web/ui.css · the furniture, once (18 oct 2026, lane H)
 *
 * Every control and pattern of the operational spec §4
 * (reference/design_system_operational.md), on the tokens of /tokens.css.
 * briefs/2026-10-18_design_cohesion_brief.md. Link it after /tokens.css,
 * /shell.css and /marks.css, before the page's own <style>. A page's own
 * style keeps only its layout: its grid, its widths, its one special thing.
 * It places a pattern in its context (.actions .btn, #today .row) and never
 * defines one (a rule that starts at .btn, .field, .band or .row).
 *
 * Two densities (spec §7), by who uses the page: tight is the default
 * (admin, manage, invoice, bills, sales, delivery: body 14, rows 32 and up);
 * <body data-density="roomy"> for the kitchen and the counter (kitchen,
 * stock, order entry, today, pass, foh: body 15, rows 56 and up).
 *
 * Colour: tokens only. ink-3 is a line or a disabled edge, never text
 * (2.9:1): every quiet text here is ink-2 (6.2:1). Weights 400, 500, and 600
 * on mono labels only. No 700.
 *
 *   the base · the section (.band · .sec, its head, tag, title, aside) ·
 *   the three buttons (.btn · .btn-secondary · .btn-ghost, and .btn-band on
 *   the ink band) · the link · the field and its label (.field · .label ·
 *   inputs · .box and its unit · .check) · the tabs · the list row at the
 *   two densities (.row), and the glyph row (.row-glyph, lane K) · the
 *   state card (.stat) · the hero number (.hero)
 *   · the tally (.tally) · the sheet that slides up (.sheet · .scrim) · the
 *   bar fixed at the foot (.bar) · the empty none (.empty) · the loading
 *   ring (.loader, where MARKS draws the hollow dot) · the mark slot under a
 *   form (.feedback) · the hold (.row-fill)
 *   · the glance (25 oct 2026): the head's right slot (.sec-ctx), the fold
 *   (.sec.is-folded), the late edge (.sec.is-late), the column label
 *   (.col-lbl), the group band (.group · .group-band), the qty and its par
 *   (.row-qty.is-urgent · .row-of), the pair row (.row-pair · .qty-pair),
 *   the zero in the tally (.tally-num.is-zero)
 *   · the add order sheet (4 nov 2026, briefs/2026-11-04_add_order_sheet_brief.md):
 *   the toggle (.seg), the pair (.pair), the group of a sheet (.sheet-group)
 *   and the foot fixed at the sheet's bottom (.sheet-foot)
 */

/* ── the base ─────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
html, body { -webkit-text-size-adjust: 100%; }
body {
  min-height: 100vh;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 400;
  line-height: 1.45;
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}
body[data-density="roomy"] { font-size: 15px; }
h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; }
strong, b { font-weight: 500; }
button, input, select, textarea, a { font-family: inherit; color: inherit; }
a { text-underline-offset: 2px; }
ul, ol { list-style: none; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.num, .maki-num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ── the section: a band with a hairline, never a card (§2.5 · §4.1) ── */
.band { padding: 16px; border-bottom: 1px solid var(--rule); }
.sec { border-bottom: 1px solid var(--rule); }
.sec-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 16px 10px;
}
/* the tag: mono UPPERCASE, 11 600, 1px tracking; also every mono micro-label */
.sec-tag, .tag {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
/* the header: lowercase prose, 18 to 20 */
.sec-title { font-size: 18px; font-weight: 400; line-height: 1.2; color: var(--ink); }
/* the context, right of the tag: mono 12, ink-2 */
.sec-aside {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* the head's right slot (the glance, 25 oct 2026): the marks, the day as
   data (a .sec-aside), the count, and the fold's dot. A slot left empty
   takes no room. */
.sec-ctx { display: inline-flex; align-items: center; gap: 12px; flex-shrink: 0; }
.sec-ctx > :empty { display: none; }
.sec-n { font-family: var(--mono); font-size: 12px; font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }

/* ── the glance (25 oct 2026, briefs/2026-10-25_today_glance_brief.md, the
 * eight rules in DECISIONS 25 oct): /today/ and the stock surfaces.
 *
 * Rule 1 · an empty section folds to one 44px line: the tag, the day, the
 * count 0 in ink-2, a hollow dot (ink-2, 6.2:1; ink-3 fails as a mark). No
 * body, no empty row, no word. The dot is aria-hidden: the count says it.
 * <span class="mk mk-hollow sec-fold" aria-hidden="true"><span class="mk-dot"></span></span>
 * sits in the .sec-ctx; it shows only on a folded section. */
.sec-fold { display: none; }
.sec.is-folded .sec-head { min-height: 44px; padding-top: 0; padding-bottom: 0; align-items: center; }
.sec.is-folded .sec-n { color: var(--ink-2); font-weight: 400; }
.sec.is-folded .sec-fold { display: inline-flex; color: var(--ink-2); }
.sec.is-folded .sec-body { display: none; }
/* Rule 6 · weight by state, not by fill: a late section with rows carries
   the urgent tag and a 3px urgent rule on its left edge, the one top-level
   urgent signal §4.2 allows. No row tint. */
.sec.is-late { position: relative; }
.sec.is-late .sec-tag { color: var(--urgent); }
.sec.is-late::before { content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 3px; background: var(--urgent); }
/* Rule 4 · a column label once per section, above its rows, not on every group */
.col-lbl {
  display: flex;
  justify-content: flex-end;
  padding: 0 16px 8px;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--ink-2);
}
.col-lbl.start { justify-content: flex-start; }
/* Rule 5 · a group is a band and the air (the third cut, Nevil 25 oct 2026:
   a bordered rounded box per group is the card tell). The band: paper-1,
   full width, a hairline above and below, the mono tag with the name and
   its count, its context right. The rows under it on paper, a hairline
   under each. 20px of air before the next band. No border round the group,
   no radius, no shadow, no fill by state. The canvas names these .grp and
   .grp-band; .grp is the stocktake's own collapsible group, so .group here. */
.group + .group { margin-top: 20px; }
.group-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  padding: 0 16px;
  background: var(--paper-1);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}
.group-band .sec-tag { min-width: 0; overflow-wrap: anywhere; }
.group-band .sec-aside { display: inline-flex; align-items: center; gap: 0 14px; }
/* a link in the band is a 44 x 44 target (call is four letters), and it
   sits over the band's two hairlines, so every band is 44px tall, with
   links or without (the refute of the glance, 25 oct 2026) */
.group-band .link { min-width: 44px; justify-content: center; margin: -1px 0; }
.group > .row, .group > .row-pair { border-top: 0; border-bottom: 1px solid var(--rule); }
.sec-body > .group:last-child > .row:last-child { border-bottom: 0; }

/* ── the three buttons (§4.5) ───────────────────────────
 * The default is the primary: ink fill, paper text. One per view.
 * The secondary: the outline. The ghost: text, underlined. 8px, 500,
 * 44px and up (48 roomy). Red and amber never fill a button. */
.btn {
  position: relative;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 44px;
  min-width: 44px;
  padding: 0 16px;
  border: 1px solid var(--ink);
  border-radius: var(--r-2);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  transition: background-color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
body[data-density="roomy"] .btn { min-height: 48px; font-size: 15px; }
.btn-primary { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.btn:active { background: var(--ink-2); border-color: var(--ink-2); }
.btn-secondary { background: var(--paper); color: var(--ink); border-color: var(--ink); }
.btn-secondary:active { background: var(--paper-2); border-color: var(--ink); }
.btn-secondary[aria-pressed="true"], .btn-secondary.is-on { background: var(--paper-2); }
.btn-ghost {
  min-width: 0;
  padding: 0 4px;
  border-color: transparent;
  background: transparent;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.btn-ghost:active { background: transparent; border-color: transparent; text-decoration-thickness: 2px; }
/* a button in the ink band (refresh, + add bill): paper on ink, an 8.1:1 edge */
.btn-band { background: transparent; color: var(--paper); border-color: var(--rule-strong); }
.btn-band:active { background: color-mix(in srgb, var(--paper) 12%, transparent); border-color: var(--rule-strong); }
.btn-full { width: 100%; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }
.btn.disabled-link { opacity: 0.5; pointer-events: none; }
@media (hover: hover) and (pointer: fine) {
  .btn-secondary:not(:disabled):hover { background: var(--paper-1); }
  .btn-secondary[aria-pressed="true"]:not(:disabled):hover { background: var(--paper-2); }
  .btn-ghost:not(:disabled):hover { background: transparent; text-decoration-thickness: 2px; }
  .btn-band:not(:disabled):hover { background: color-mix(in srgb, var(--paper) 8%, transparent); }
}

/* ── the link: ink, underlined, a 44px target ─────────── */
.link, .back-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0;
  border: 0;
  background: none;
  font-size: inherit;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.back-link { padding: 8px 16px 0; }
.link:disabled { opacity: 0.5; cursor: not-allowed; }
@media (hover: hover) and (pointer: fine) {
  .link:not(:disabled):hover, .back-link:hover { text-decoration-thickness: 2px; }
}

/* ── the field and its label (§4.6) ─────────────────────
 * The label above: mono UPPERCASE 11, ink-2. The input: 16px type (no iOS
 * zoom), 44px and up (48 roomy), 1px edge, 8px corners, focus 2px ink. */
.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
fieldset.field { border: 0; }
.field + .field { margin-top: 12px; }
.label, .field label, .field legend {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  line-height: 1.4;
  text-transform: uppercase;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}
input[type="text"], input[type="number"], input[type="date"], input[type="month"], input[type="time"], input[type="tel"],
input[type="email"], input[type="search"], input[type="url"], input:not([type]), select, textarea {
  width: 100%;
  min-width: 0;
  height: 44px;
  padding: 0 12px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-2);
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color var(--fast) var(--ease);
}
body[data-density="roomy"] input[type="text"], body[data-density="roomy"] input[type="number"],
body[data-density="roomy"] input[type="date"], body[data-density="roomy"] input[type="month"], body[data-density="roomy"] input[type="time"],
body[data-density="roomy"] input[type="tel"], body[data-density="roomy"] input[type="email"],
body[data-density="roomy"] input[type="search"], body[data-density="roomy"] input:not([type]),
body[data-density="roomy"] select { height: 48px; }
input[type="number"], input[inputmode="decimal"], input[inputmode="numeric"], input.num { font-variant-numeric: tabular-nums; }
input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* the month field: the delivery export (lane G), joined at the merge of lane H */
input[type="date"], input[type="month"] { text-align: left; font-variant-numeric: tabular-nums; }
input[type="date"]::-webkit-date-and-time-value, input[type="month"]::-webkit-date-and-time-value { text-align: left; }
textarea { height: auto; min-height: 96px; padding: 12px; line-height: 1.45; resize: vertical; }
select {
  padding-right: 34px;
  text-overflow: ellipsis;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%234C6472' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
/* 16px on every field, the file and the read-only ones too (the lane H fix round): no field is under 16 */
input[type="file"] { width: 100%; min-height: 44px; padding: 10px 12px; border: 1px solid var(--rule-strong); border-radius: var(--r-2); font-size: 16px; }
input:focus, select:focus, textarea:focus { border-color: var(--ink); }
input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
input:disabled, select:disabled, textarea:disabled { background-color: var(--paper-1); color: var(--ink-2); }
input[readonly] { background-color: var(--paper-1); font-family: var(--mono); font-size: 16px; }
::placeholder { color: var(--ink-2); opacity: 1; }

/* the boxed field: an edge round an input and its unit (a qty, a search) */
.box {
  display: flex;
  align-items: stretch;
  min-width: 0;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-2);
  background: var(--paper);
  overflow: hidden;
  transition: border-color var(--fast) var(--ease);
}
.box:focus-within { border-color: var(--ink); }
.box > input, .box > select, .box input, .box select {
  flex: 1;
  min-width: 0;
  border: 0;
  border-radius: 0;
  background-color: transparent;
}
.box > input:focus-visible, .box > select:focus-visible { outline: 0; }
.box:focus-within:has(:focus-visible) { outline: 2px solid var(--ink); outline-offset: 2px; }
.box-unit {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  padding: 0 12px;
  border-left: 1px solid var(--rule);
  background: var(--paper-1);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--ink-2);
  white-space: nowrap;
}
.box-unit.pre { order: -1; border-left: 0; border-right: 1px solid var(--rule); }
.box-unit:empty { display: none; }
.box-clear {
  flex-shrink: 0;
  width: 44px;
  border: 0;
  border-left: 1px solid var(--rule);
  background: transparent;
  font-size: 18px;
  color: var(--ink-2);
  cursor: pointer;
}
/* a refused boxed field: the edge goes urgent, the mark under it (marks.css) */
.box.bad, .box:has(.mk-invalid) { border-color: var(--urgent); border-bottom-width: 2px; }
.box .mk-invalid { border-bottom: 0 !important; }

/* a check: a 20px box, the whole row the 44px target */
.check {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  cursor: pointer;
  user-select: none;
}
.check input { width: 20px; height: 20px; flex-shrink: 0; margin: 0; accent-color: var(--ink); cursor: pointer; }

/* the toggle (4 nov 2026, the add order sheet, rule 2): a choice of two or
 * three, every option in view, one tap. One row of equal buttons, 44px, a
 * hairline between, the edge and corners of a field. The pressed one is ink
 * with paper type, the rest paper with ink type. The row is a group
 * (role="group", its name in aria-label or a .label); each option a
 * <button type="button" aria-pressed>. Refused, it takes .mk-invalid as a
 * field does. A select stays for a list the config writes. The edge is on
 * the buttons, so the row is 44px, the buttons' own height. */
.seg {
  display: flex;
  min-width: 0;
  border-radius: var(--r-2);
}
.seg > button {
  flex: 1 1 0;
  min-width: 0;
  min-height: 44px;
  margin: 0;
  padding: 0 8px;
  border: 1px solid var(--rule-strong);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  transition: background-color var(--fast) var(--ease), color var(--fast) var(--ease);
}
.seg > button + button { border-left-width: 0; }
.seg > button:first-child { border-radius: var(--r-2) 0 0 var(--r-2); }
.seg > button:last-child { border-radius: 0 var(--r-2) var(--r-2) 0; }
.seg > button:only-child { border-radius: var(--r-2); }
.seg > button[aria-pressed="true"] { border-color: var(--ink); background: var(--ink); color: var(--paper); }
.seg > button:active { background: var(--paper-2); }
.seg > button[aria-pressed="true"]:active { background: var(--ink-2); }
.seg > button:focus-visible { outline: 2px solid var(--ink); outline-offset: -3px; }
.seg > button[aria-pressed="true"]:focus-visible { outline-color: var(--paper); }
.seg > button:disabled { opacity: 0.5; cursor: not-allowed; }
/* refused: the field's urgent edge, on the buttons (marks.css draws it on the row) */
.seg.mk-invalid { border-bottom: 0 !important; }
.seg.mk-invalid > button { border-bottom: 2px solid var(--urgent); }
@media (hover: hover) and (pointer: fine) {
  .seg > button:not([aria-pressed="true"]):not(:disabled):hover { background: var(--paper-1); }
}

/* the pair (4 nov 2026, the add order sheet, rule 6): two short fields on
 * one row, 3 : 2, 12px between (name · phone, date · slot, pin · pincode,
 * two ticks). A child the page hides leaves the other the whole row. */
.pair { display: flex; align-items: flex-start; gap: 12px; min-width: 0; }
.pair > * { flex: 3 1 0; min-width: 0; }
.pair > * + * { flex-grow: 2; }
.pair > .field + .field { margin-top: 0; }

/* the drop list under a search field (the kitchen's and order entry's) */
.dropdown {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  display: none;
  flex-direction: column;
  max-height: 264px;
  overflow-y: auto;
  border: 1px solid var(--rule-strong);
  border-radius: var(--r-2);
  background: var(--paper);
}
.dropdown.open { display: flex; }
.opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 48px;
  padding: 8px 12px;
  border: 0;
  border-bottom: 1px solid var(--rule);
  background: transparent;
  font-size: 16px;
  text-align: left;
  overflow-wrap: anywhere;
  cursor: pointer;
}
.opt:last-child { border-bottom: 0; }
.opt:active { background: var(--paper-2); }
@media (hover: hover) and (pointer: fine) { .opt:hover { background: var(--paper-1); } }
.opt-meta {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ── the tabs: two to four views on a hairline ────────── */
.tabs { display: flex; gap: 24px; padding: 0 16px; border-bottom: 1px solid var(--rule); }
.tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 48px;
  margin-bottom: -1px;
  padding: 0;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  font-size: 15px;
  font-weight: 500;
  color: var(--ink-2);
  cursor: pointer;
}
.tab[aria-selected="true"], .tab[aria-pressed="true"], .tab.active { color: var(--ink); border-bottom-color: var(--ink); }
@media (hover: hover) and (pointer: fine) { .tab:hover { color: var(--ink); } }

/* ── the list row (§4.2) ────────────────────────────────
 * Data stays crisp: no fill, no tint by state, a hairline on top. Tight:
 * 32px and up. Roomy: 56px and up, the name leads by size. */
.row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 32px;
  padding: 8px 16px;
  border-top: 1px solid var(--rule);
  color: var(--ink);
  text-decoration: none;
}
body[data-density="roomy"] .row { gap: 14px; min-height: 56px; padding: 12px 16px; }
.row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.row-name { font-size: 15px; font-weight: 500; line-height: 1.25; color: var(--ink); overflow-wrap: anywhere; }
body[data-density="roomy"] .row-name { font-size: 17px; }
.row-meta, .row-ann {
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.row-qty {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
body[data-density="roomy"] .row-qty { font-size: 16px; }
/* a unit prints lowercase, as typed after the unit rule (the glance, rule 8,
   25 oct 2026): no uppercase, no tracking */
.row-unit {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
}
/* done: the row recedes to ink-2 in place, the name struck (state flip, §5) */
.row.is-done .row-name, .row.is-done .row-qty, .row.is-done .row-meta, .row.is-done .row-ann, .row.is-done .row-unit { color: var(--ink-2); }
.row.is-done .row-name { text-decoration: line-through; text-decoration-thickness: 1px; }
/* the glyph row (lane K, 20 oct 2026, board C, briefs/2026-10-20_kitchen_glyphs_brief.md):
 * the kitchen's make list. The glyph leads (web/icons/glyphs.js; no glyph,
 * the slot stays empty), the name and its meta, the count big at the right
 * with its unit under it. Weight is the state, never colour: today bold,
 * tomorrow (.is-ahead) regular, done (.is-done) the fill glyph and ink-2. */
.glyph { display: block; width: 32px; height: 32px; flex-shrink: 0; fill: currentColor; color: var(--ink); }
.row.row-glyph,
body[data-density="roomy"] .row.row-glyph { align-items: center; gap: 14px; min-height: 88px; padding: 10px 16px; }
.row-glyph > .glyph, .row-glyph > .row-main, .row-glyph > .row-end { position: relative; z-index: 1; }   /* over the hold's sweep */
.row.row-glyph .row-main { gap: 0; }
.row.row-glyph .row-name { font-size: 20px; font-weight: 500; line-height: 1.15; }
.row.row-glyph .row-ann { margin-top: 6px; }
.row-end { display: flex; flex-direction: column; align-items: flex-end; flex-shrink: 0; }
.row-count { font-size: 30px; font-weight: 500; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.row.row-glyph .row-unit { margin-top: 5px; font-weight: 500; text-align: right; }
.row.row-glyph.is-ahead .row-name, .row.row-glyph.is-ahead .row-count { font-weight: 400; }
.row.is-done .glyph, .row.is-done .row-count { color: var(--ink-2); }
a.row, button.row { width: 100%; background: transparent; border-left: 0; border-right: 0; border-bottom: 0; text-align: left; cursor: pointer; transition: background-color var(--fast) var(--ease); }
a.row:active, button.row:active { background: var(--paper-1); }
@media (hover: hover) and (pointer: fine) { a.row:hover, button.row:hover { background: var(--paper-1); } }
/* the glance, rule 3 · a zero is a number: the qty in its state's ink, the
   par after it in ink-2 ("0" then "/ 2 kg"). A dot carries a state only,
   never a quantity. */
.row-qty-wrap { display: flex; align-items: baseline; gap: 6px; flex-shrink: 0; }
.row-qty.is-urgent { color: var(--urgent); }
.row-qty.is-watch { color: var(--watch); }
.row-of { font-family: var(--mono); font-size: 12px; font-weight: 400; color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* the glance, rule 6 · tomorrow's names in ink-2, today's in ink. The
   kitchen's glyph row keeps its own rule, weight (lane K). */
.row.is-ahead:not(.row-glyph) .row-name, .row.is-ahead:not(.row-glyph) .glyph { color: var(--ink-2); }
/* the glance, rule 7 · the pair row (the order list): the name, then one
   mono pair "0 / 2 kg" with its flag on the same line; the qty box right,
   48px (roomy), the unit inside it. One voice per layer. */
.row-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 128px;
  align-items: center;
  gap: 4px 14px;
  min-height: 64px;
  padding: 10px 16px;
  border-top: 1px solid var(--rule);
}
.row-pair-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.row-pair .row-name { font-size: 17px; }
.qty-pair {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.qty-pair .qty-of { white-space: nowrap; }
.qty-pair .n { font-weight: 500; color: var(--ink); }
.qty-pair .n.is-urgent { color: var(--urgent); }
.qty-pair .n.is-watch { color: var(--watch); }

/* ── the state card (§4.4): a mono label, the number, a delta ── */
.stat { min-width: 0; padding: 14px 16px 16px; background: var(--paper); }
.stat-label {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-2);
}
.stat-num {
  margin-top: 8px;
  font-size: 26px;
  font-weight: 500;
  line-height: 1.05;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.stat-delta { margin-top: 6px; font-family: var(--mono); font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.stat-delta.up { color: var(--ok); }
.stat-delta.down { color: var(--urgent); }

/* ── the hero number: one count leads, Archivo 500, 28 ── */
.hero { padding: 20px 16px; border-bottom: 1px solid var(--rule); }
.hero-read { display: flex; flex-wrap: wrap; align-items: baseline; gap: 12px; }
.hero-num { font-size: 28px; font-weight: 500; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.hero-sub { font-family: var(--mono); font-size: 12px; line-height: 1.4; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.hero-bar { height: 3px; margin-top: 12px; background: var(--rule); overflow: hidden; }
.hero-bar-fill { height: 100%; width: 0%; background: var(--ink); transition: width var(--base) var(--ease); }

/* ── the tally: counts side by side, a hairline between ── */
.tally { display: grid; grid-auto-columns: minmax(0, 1fr); grid-auto-flow: column; border-top: 1px solid var(--rule); }
.tally-cell {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  padding: 14px 16px 16px;
  border-left: 1px solid var(--rule);
}
.tally-cell:first-child { border-left: 0; }
.tally-lbl {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tally-num { font-size: 24px; font-weight: 500; line-height: 1.05; color: var(--ink); font-variant-numeric: tabular-nums; }
.tally-num.urgent { color: var(--urgent); }
/* the glance · a zero in the tally is a relief: ink-2, the number kept */
.tally-num.is-zero { color: var(--ink-2); }

/* ── the sheet that slides up: the one shadow (§2.5) ──── */
.scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--ink) 24%, transparent);
}
.sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 41;
  max-width: 560px;
  max-height: 88vh;
  margin: 0 auto;
  overflow-y: auto;
  background: var(--paper);
  border-radius: var(--r-3) var(--r-3) 0 0;
  box-shadow: 0 8px 24px color-mix(in srgb, var(--ink) 16%, transparent);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px;
  border-bottom: 1px solid var(--rule);
}
.sheet-title { font-size: 18px; font-weight: 500; line-height: 1.2; }
.sheet-close {
  width: 44px;
  height: 44px;
  margin: -10px -10px -10px 0;
  border: 0;
  border-radius: var(--r-2);
  background: transparent;
  font-size: 20px;
  color: var(--ink-2);
  cursor: pointer;
}
.sheet-body { display: flex; flex-direction: column; gap: 16px; padding: 16px; }
/* the group of a sheet (4 nov 2026, the add order sheet, rule 1): the
 * fields of one question 8px apart; 20px of air and a hairline before the
 * next group, then the group's own 8. No label, no band, no box: the first
 * control names the group. A sheet of groups sets its own gaps. */
.sheet-body:has(> .sheet-group) { gap: 0; padding: 12px 16px 8px; }
.sheet-group { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.sheet-group > .field + .field { margin-top: 0; }
.sheet-group + .sheet-group { margin-top: 20px; padding-top: 8px; border-top: 1px solid var(--rule); }
/* the foot fixed at the sheet's bottom (4 nov 2026, rule 7): paper on a
 * hairline, the sum at the left, the mark slot and the action at the right,
 * in reach on every scroll. It sits after .sheet-body, inside .sheet. A
 * sheet with a foot holds its head too, so × stays in reach and nothing
 * shows half cut under the corner; a focused field scrolls clear of both.
 * The foot is one row, always (the fix round of 4 nov 2026): the sum and
 * the action keep their width, the mark slot takes the room between and a
 * long mark breaks inside it, its code over its field, within the action's
 * 44px. So the foot's height never moves and the scroll padding holds. */
/* A sheet with a foot is a form: it takes the screen but a 40px strip of
 * the page above it (the fix round of 4 nov 2026), so a short entry fits
 * with no scroll on a 390 x 844 phone. */
.sheet:has(> .sheet-foot) { max-height: calc(100vh - 40px); max-height: calc(100dvh - 40px); padding-bottom: 0; scroll-padding: 76px 0 84px; }
.sheet:has(> .sheet-foot) > .sheet-head { position: sticky; top: 0; z-index: 1; background: var(--paper); }
.sheet-foot {
  position: sticky;
  bottom: 0;
  z-index: 1;
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--paper);
  border-top: 1px solid var(--rule);
}
.sheet-foot > :first-child { flex: none; }
.sheet-foot-end { display: flex; flex: 1 1 auto; align-items: center; justify-content: flex-end; gap: 12px; min-width: 0; margin-left: auto; }
.sheet-foot-end > .feedback { flex: 0 1 auto; flex-wrap: wrap; justify-content: flex-end; min-width: 0; }
.sheet-foot-end > .btn { flex: none; }

/* ── the bar fixed at the foot: the page's actions ─────── */
.bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px max(16px, calc((100% - var(--page, 100%)) / 2 + 16px)) calc(10px + env(safe-area-inset-bottom, 0px));
  background: var(--paper);
  border-top: 1px solid var(--rule);
}

/* ── the empty none (§4.7): the count or one word, nothing more. A section
   that empties folds instead (.sec.is-folded above, the glance, 25 oct). ── */
.empty {
  padding: 12px 16px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* ── the loading ring (§4.8): where MARKS draws the hollow dot ── */
.loader {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px 16px;
  padding: 72px 16px;
}
.loader:empty { display: none; }

/* ── the mark slot under a form or beside a button ─────── */
.feedback { display: flex; align-items: center; min-height: 17px; }
.feedback:empty { min-height: 0; }

/* ── the hold: a fill sweeps the control (kitchen, pass, foh) ── */
.row-fill {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--rule-strong);           /* ink reads on it: 8.1:1 */
  transform: scaleX(0);
  transform-origin: left center;
  pointer-events: none;
}
.btn:not(.btn-secondary):not(.btn-ghost) .row-fill { background: var(--ink-2); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}
