:root {
  color-scheme: light;
  font-family: Geist, Inter, system-ui, sans-serif;
  color: #111827;
  background: #fffaf5;
  --orange: #ea580c;
  /*
   * The same accent, darkened until small text passes WCAG AA.
   *
   * `--orange` is the brand colour and stays exactly as specified, but measured
   * against this product's three real backgrounds — warm white `#fffaf5`, a 70%
   * white panel over it, and the 22% peach of a ready row — it lands at 3.43,
   * 3.52, and 3.15 to 1. That clears AA for large type only, and every text use
   * of the accent in this stylesheet is 11–18px: eyebrows, steps, links,
   * countdowns, badges, the Recipient code. So the accent splits by *size*
   * rather than by surface. `--orange` keeps large display type, borders, and
   * fills, where 3:1 is the applicable threshold; `--orange-text` takes anything
   * set small, at 4.99, 5.12, and 4.59 to 1.
   *
   * `#c2410c` is orange-700 from the same ramp and already in this file as a
   * border colour, so this darkens the accent rather than introducing a hue.
   */
  --orange-text: #c2410c;
  --peach: #fdba74;
  --rose: #e11d48;
  --surface: #191c21;
  --muted: #4b5563;
  --border: #e5e7eb;

  /*
   * The V2 presentation foundation (#90).
   *
   * These extend the palette above; they do not replace it. `--orange`,
   * `--orange-text`, `--peach`, `--rose`, `--surface`, `--muted`, `--border`
   * and the warm white `#fffaf5` remain the Auralis/Neuform language, and the
   * size split explained above still decides which of the two oranges a rule
   * may use — a V2 route setting the accent at 11-18px still takes
   * `--orange-text`.
   *
   * What is new here is only what every redesigned route needs to state the
   * same way: the minimum target, the control radius, the panel fill and its
   * border, the page gutter, the focus ring, and the refusal colour.
   */
  --v2-target: 44px;
  --v2-radius: 8px;
  --v2-panel: rgb(255 255 255 / 0.8);
  --v2-panel-border: rgb(229 231 235 / 0.9);
  --v2-gutter: clamp(20px, 6vw, 32px);
  /*
   * A focus indicator has to clear 3:1 against what it sits on (WCAG 2.2 AA,
   * 1.4.11). The 30%-alpha orange used by the older `:focus-visible` rule in
   * this file blends to about 1.5:1 over the warm white, so V2 focus uses the
   * solid darkened accent instead: `#c2410c` measures 5.06:1 over `#fffaf5`.
   * It is the same hue, so nothing about the language changes.
   */
  --v2-focus-ring: 3px solid var(--orange-text);
  --v2-focus-offset: 3px;
  /*
   * The refusal colour already used by `.error-text` and `.status.error`,
   * named rather than repeated. 7.8:1 over the warm white.
   */
  --v2-danger-text: #9f1239;
}

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  background:
    linear-gradient(100deg, rgb(255 255 255 / 0.96) 0 52%, transparent 78%),
    #fffaf5;
}

.atmosphere {
  position: fixed;
  z-index: -1;
  inset: -15% -18% auto 45%;
  height: 70vh;
  border-radius: 45% 55% 62% 38%;
  background:
    radial-gradient(circle at 62% 25%, #fef3c7 0 8%, transparent 30%),
    radial-gradient(circle at 70% 65%, #fda4af 0 12%, transparent 40%),
    radial-gradient(circle at 30% 60%, var(--peach) 0 18%, transparent 48%),
    linear-gradient(145deg, #fb923c, #fecdd3 58%, #fff7ed);
  filter: blur(18px);
  animation: breathe 12s ease-in-out infinite alternate;
}

header,
main {
  width: min(100% - 48px, 1280px);
  margin-inline: auto;
}

header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: 28px;
}

/*
 * The brand is a real link home, so it is sized like a real target rather than
 * left as inline text that only clears 44px when it happens to wrap.
 */
.brand {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: inherit;
  font-size: 18px;
  letter-spacing: -0.04em;
  text-decoration: none;
  text-transform: uppercase;
}

.brand span {
  color: var(--orange-text);
}

.role,
.eyebrow,
.step,
.event-meta {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.role,
.hint,
.help {
  color: var(--muted);
}

.header-nav {
  display: flex;
  align-items: center;
  gap: 18px;
}

.settings-link {
  color: var(--surface);
  font-size: 14px;
  font-weight: 700;
  text-underline-offset: 4px;
}

main {
  padding-block: 70px 100px;
}

.intro {
  max-width: 720px;
}

.eyebrow {
  color: var(--orange-text);
}

h1 {
  margin: 16px 0;
  font-size: clamp(48px, 7vw, 88px);
  font-weight: 300;
  line-height: 0.98;
  letter-spacing: -0.065em;
}

h1 em {
  color: transparent;
  font-style: normal;
  background: linear-gradient(90deg, var(--orange), var(--rose));
  background-clip: text;
}

.intro > p:last-child {
  max-width: 590px;
  color: var(--muted);
  font-size: 18px;
  line-height: 1.65;
}

.workspace {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 20px;
  margin-top: 64px;
}

.panel {
  position: relative;
  padding: clamp(26px, 4vw, 48px);
  border: 1px solid rgb(229 231 235 / 0.9);
  background: rgb(255 255 255 / 0.8);
  box-shadow: 0 28px 70px -55px rgb(25 28 33 / 0.6);
  backdrop-filter: blur(20px);
}

.step {
  position: absolute;
  top: 20px;
  right: 24px;
  color: var(--orange-text);
}

h2 {
  margin: 0;
  font-size: clamp(24px, 3vw, 36px);
  font-weight: 400;
  letter-spacing: -0.04em;
}

.hint {
  margin: 10px 0 30px;
  max-width: 570px;
  line-height: 1.55;
}

form,
label {
  display: grid;
  gap: 8px;
}

form {
  gap: 20px;
}

label,
legend {
  font-size: 14px;
  font-weight: 600;
}

input,
select,
textarea {
  width: 100%;
  min-height: 46px;
  padding: 11px 13px;
  color: var(--surface);
  border: 1px solid #d1d5db;
  border-radius: 8px;
  background: rgb(255 255 255 / 0.88);
  font: inherit;
}

textarea {
  resize: vertical;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
  line-height: 1.5;
}

input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible,
a:focus-visible {
  outline: 3px solid rgb(234 88 12 / 0.3);
  outline-offset: 2px;
}

fieldset {
  display: flex;
  gap: 20px;
  margin: 0;
  padding: 0;
  border: 0;
}

legend {
  margin-bottom: 10px;
}

.choice {
  display: flex;
  align-items: center;
  gap: 7px;
  font-weight: 400;
}

.choice input {
  width: 18px;
  min-height: 18px;
}

.help {
  margin: -12px 0 0;
  font-size: 12px;
  line-height: 1.5;
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
}

button {
  min-height: 48px;
  padding: 0 24px;
  border: 0;
  font: inherit;
  cursor: pointer;
}

.primary {
  color: white;
  background: var(--surface);
}

.primary:hover {
  background: #000;
}

.clipped,
.event-state {
  clip-path: polygon(
    9px 0,
    100% 0,
    100% calc(100% - 9px),
    calc(100% - 9px) 100%,
    0 100%,
    0 9px
  );
}

.text-button {
  min-height: 40px;
  padding: 0;
  color: var(--orange-text);
  background: transparent;
}

.events {
  display: grid;
  grid-template-columns: minmax(190px, 0.35fr) 1fr;
  gap: 40px;
  margin-top: 64px;
  padding-top: 38px;
  border-top: 1px solid var(--border);
}

[hidden] {
  display: none !important;
}

.service-setup {
  margin-top: 64px;
  padding-top: 38px;
  border-top: 1px solid var(--border);
}

.service-grid {
  display: grid;
  grid-template-columns: 0.75fr 1.25fr;
  gap: 20px;
  margin-top: 28px;
}

h3 {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.03em;
}

#board-list,
.menu-list,
.ingredient-list {
  display: grid;
  gap: 14px;
}

.board-row,
.menu-row,
.ingredient-row {
  display: grid;
  min-width: 0;
  min-inline-size: 0;
  gap: 14px;
  padding: 18px;
  border: 1px solid var(--border);
}

.board-row legend {
  padding-inline: 5px;
  color: var(--orange-text);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  text-transform: uppercase;
}

.stall-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
}

.board-link {
  color: var(--orange-text);
  font-size: 14px;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.staff-sign-in,
.staff-workspace {
  max-width: 1040px;
  margin-top: 48px;
}

.staff-workspace {
  display: grid;
  width: 100%;
  min-width: 0;
  gap: 24px;
}

.staff-workspace > *,
.active-stall {
  min-width: 0;
}

.active-stall {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: 8px 20px;
  padding: 0 0 24px 20px;
  border-left: 6px solid var(--stall-color, var(--orange));
  border-bottom: 1px solid var(--border);
}

.queue-counts {
  display: flex;
  grid-column: 1 / -1;
  flex-wrap: wrap;
  gap: 8px 18px;
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
  font-weight: 600;
}

.active-stall .eyebrow {
  grid-column: 1 / -1;
  margin: 0;
}

.capacity-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.capacity-controls legend {
  width: 100%;
  color: var(--muted);
}

/*
 * WCAG 2.2 AA target size (#39). This was 42px, and the role-scoped Capacity
 * State panel carried a 44px override to clear the gate on its own screens
 * while the shared rule stayed non-conforming. Raising the shared rule fixes
 * every surface that uses it and makes the override redundant.
 */
.capacity-controls button {
  min-height: 44px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgb(255 255 255 / 0.8);
}

.capacity-controls button[aria-pressed="true"] {
  color: white;
  border-color: var(--surface);
  background: var(--surface);
}

.fulfillment-queues {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

.queue-panel {
  min-width: 0;
  padding: clamp(22px, 3vw, 34px);
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.78);
  backdrop-filter: blur(20px);
}

.queue-panel .eyebrow {
  margin-top: 0;
}

.queue-list {
  display: grid;
  gap: 12px;
  margin-top: 20px;
  color: var(--muted);
}

.queue-card {
  padding: 18px;
  color: var(--surface);
  border: 1px solid var(--border);
  border-left: 5px solid var(--orange);
  background: white;
}

.queue-card.new-arrival {
  border-color: var(--orange);
  background: #fff7ed;
  animation: queue-arrival 700ms ease-out;
}

.queue-card h4,
.queue-card p {
  margin: 0;
}

.queue-card h4 {
  font-size: 18px;
}

.queue-age {
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
}

.queue-card ul {
  margin-bottom: 0;
  padding-left: 20px;
}

.queue-actions,
.line-cancellation {
  display: grid;
  gap: 10px;
  margin-top: 14px;
}

.line-cancellation {
  padding: 12px;
  border-left: 3px solid var(--border);
}

.queue-actions button,
.line-cancellation button {
  justify-self: start;
}

.ready-pending,
.handoff-pending,
.ready-badge {
  color: var(--orange-text);
  font-weight: 700;
}

.handoff-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
}

.active-stall h2 {
  font-size: clamp(36px, 6vw, 64px);
}

.stall-switcher {
  max-width: 420px;
}

.runner-alerts {
  padding: 24px;
  color: white;
  background: var(--surface);
}

#runner-alert-list {
  display: grid;
  gap: 12px;
}

.runner-alert {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px 18px;
  padding: 16px;
  border: 1px solid rgb(255 255 255 / 0.2);
}

.runner-alert h3,
.runner-alert p {
  margin: 0;
}

.runner-alert input {
  grid-column: 1 / 2;
}

.menu-row {
  grid-template-columns: 1.2fr 0.7fr;
}

.menu-row legend,
.ingredient-row legend,
.readiness-status .warning {
  color: var(--orange-text);
}

.menu-row .choice,
.menu-row .text-button {
  align-self: end;
}

.recipe-fields,
.stock-actions {
  display: grid;
  min-width: 0;
  gap: 12px;
}

.recipe-fields > *,
.stock-actions > * {
  min-width: 0;
}

.recipe-fields,
.stock-actions,
.stock-counts,
.ingredient-row > .hint {
  grid-column: 1 / -1;
}

.stock-actions {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.stock-alert {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--rose);
  font-weight: 700;
}

.stock-counts {
  margin: 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-weight: 700;
}

.enable-orders {
  color: var(--surface);
  border: 1px solid var(--orange);
  background: #fff7ed;
}

.readiness-status:not(:empty) {
  padding: 18px 20px;
  border-left: 4px solid var(--orange);
  background: rgb(255 247 237 / 0.8);
}

.readiness-status p {
  margin: 0;
}

.readiness-status ul {
  margin-bottom: 0;
}

.board-page {
  height: 100vh;
  overflow: hidden;
  color: #332317;
  background:
    radial-gradient(circle at 82% 8%, rgb(255 186 124 / 0.22), transparent 30%),
    #fff8ed;
}

/*
 * The one surface nobody holds: a TV on a wall, in landscape, read from twenty
 * feet by someone who will not walk closer. So it fills the screen rather than
 * centring a card in it — F2's real wall-mounted board carries roughly eight rows
 * per column edge to edge, where a centred column of tiles wastes the two thirds
 * of a 1920×1080 display that carries no information.
 */
.board-main {
  display: grid;
  /* One row per child — header, columns, info bar — with the slack given to the
     columns, so the orders begin under the title and the info bar sits on the
     floor. Naming fewer rows than there are children puts the `1fr` on the wrong
     element and the whole board drifts downward. */
  grid-template-rows: auto 1fr auto;
  box-sizing: border-box;
  width: 100%;
  height: 100vh;
  min-height: 0;
  overflow: hidden;
  padding: 30px clamp(34px, 4vw, 76px) 24px;
}

/* The board's name identifies the screen; it is not the thing being read. F2 gives
   its heading one line and spends everything else on orders, so all three
   identifying values share that line and the stall list absorbs the slack. */
.board-head {
  display: flex;

  /* The global `header` rule centres a 1280px column and pads it — right for a
     phone workspace inside a page, wrong here, where this is a band across a wall
     display and the board's own gutter is the only margin there should be. */
  width: 100%;
  margin-inline: 0;
  gap: clamp(16px, 2vw, 32px);
  align-items: end;
  justify-content: space-between;
  padding-block: 0;
  border-bottom: 2px solid #ef7926;
}

.board-main h1 {
  margin: 0 0 12px;
  color: #e96118;
  font-size: clamp(46px, 4.3vw, 76px);
  line-height: 0.95;
  letter-spacing: -0.04em;
}

/* Dark surface, so the accent inverts rather than darkens — same reason as the
   Guest's balance and Basket panels. At twenty feet (rule 24) a 3.30-to-1 label
   is the first thing to disappear. */
.board-head .eyebrow {
  margin: 0 0 8px;
  color: #765845;
  font-size: clamp(14px, 1.1vw, 20px);
  letter-spacing: 0.12em;
}

.board-stalls {
  overflow: hidden;
  margin: 0;
  color: #4f392c;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  /* Truncated rather than wrapped: a board carrying eight stalls must not buy a
     second header line at the cost of a row of orders. */
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

/*
 * Order Ready is wider than In Progress, and deliberately. A Guest crossing a
 * hall is looking for one question — is mine ready — and F2's board answers it
 * with the Ready column given the dominant share of the screen. Rule 24 forbids
 * leaning on colour to carry readiness, so the distinction is *size and position*
 * first: readable as a shape before any hue resolves, and still readable to
 * someone who cannot distinguish the two greens at all.
 */
.board-columns {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
  gap: clamp(32px, 4vw, 74px);
  align-content: start;
  min-height: 0;
  margin-top: clamp(24px, 3vh, 42px);
}

.board-columns > section {
  display: grid;
  grid-template-rows: auto 1fr;
  min-height: 0;
}

.board-columns > section > h2 {
  margin: 0 0 18px;
  color: #554238;
  font-size: clamp(24px, 2.3vw, 38px);
  letter-spacing: -0.025em;
}

/* The Ready heading earns the larger type for the same reason its column is
   wider: it is the answer the Guest walked over to read. */
.board-columns > section:last-child > h2 {
  color: #d95012;
  font-size: clamp(34px, 3.2vw, 54px);
}

/*
 * Rows share out the height the column actually has, rather than each taking its
 * natural height and the last few falling off the bottom edge. A twelfth row that
 * renders below the screen is invisible and unannounced — worse than pagination,
 * because the Guest has no way to know to wait for a rotation. `--rows` is set by
 * `board.js` from the rendered count, so the height is divided by what is really
 * there and a board with three orders does not stretch them to fill a TV.
 */
.board-orders {
  /* Replaced by `board.js` from the column's measured height. A guessed constant
     for the surrounding chrome was wrong by enough to clip the last row. */
  --row-height: 64px;

  /* How many stall groups stand side by side, set by `board.js` from the group
     count. Rule 26 pins the page at 12, and 12 rows in a single stack on a 1080p
     screen resolve to ~32px numerals — legible at arm's length, not from twenty
     feet, which is this surface's entire purpose. The rule wins over the reference,
     so the 12 gain width rather than losing members: two stalls beside each other
     are six rows apiece and roughly double the type. */
  --sub-columns: 1;

  /* Derived from *this* column's height, not the page's. `board.js` measures a
     column by setting `--row-height` on it and reading where the last row lands, so
     anything sized off a page-level variable does not move while the column is being
     measured — the number is the tallest thing in a row, and a row whose tallest
     element ignores the property makes the measurement meaningless. That is not a
     tidiness point: it is what made the fit return type at its floor. */
  /* A full page never reaches this ceiling — `--row-height * 0.62` is what binds at
     twelve rows — so it bounds only the sparse case. */
  --ready-number: max(
    28px,
    min(clamp(36px, 7vw, 132px), var(--row-height) * 0.62)
  );

  display: grid;
  grid-template-columns: repeat(var(--sub-columns), minmax(0, 1fr));
  align-content: start;
  align-items: start;
  /* Both bounds track the row, so enlarged type does not keep a dense board's gaps. */
  gap: min(max(10px, calc(var(--row-height) * 0.16)), 64px);
  min-height: 0;

  /* A third of the height the fitted rows did not need, set by `board.js` after the
     fit. Measured slack, so it cannot push a row off-screen; on a full page it
     resolves under two pixels. */
  padding-top: var(--column-slack, 0px);
}

.board-orders section {
  display: grid;
  /* The query container for the row text below: a name and a heading are sized
     against the sub-column they occupy, not the width of the wall. */
  container-type: inline-size;
  align-content: start;
  gap: min(max(8px, calc(var(--row-height) * 0.07)), 40px);
  padding-left: clamp(10px, 1vw, 18px);
  border-left: 3px solid #dda981;
  min-width: 0;
}

/*
 * The 28px floor is rule 27 at twenty feet: on a full page the heading is the only
 * thing separating two stalls both showing order number 1, so it may never be the
 * text that shrinks. A dense row's `0.16` is well under 28, so `max()` holds it there.
 */
.board-orders h3 {
  margin: 0;
  color: #765845;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: max(
    28px,
    min(clamp(28px, 9cqw, 56px), calc(var(--row-height) * 0.16))
  );
  letter-spacing: 0.08em;
  /* Wraps rather than running out over the next sub-column. Not truncated: rule 27
     wants the heading readable, and "CHAAT COR…" beside "CHAAT COU…" is not. */
  overflow-wrap: break-word;
  text-transform: uppercase;
}

/*
 * A row, not a tile. F2's board puts the name and the number on one line and
 * stacks eight of them per column, because a Guest scans a *list* — one saccade
 * down a left edge — where a grid of large tiles has to be read cell by cell.
 * Eight rows also mean the common case never paginates, and rule 26's rotation
 * stays the exception rather than the way the board normally behaves.
 */
.board-orders span {
  display: flex;
  gap: clamp(12px, 1.5vw, 28px);
  align-items: baseline;
  justify-content: space-between;
  padding: min(clamp(8px, 1.2vh, 16px), calc(var(--row-height) * 0.14))
    clamp(14px, 1.4vw, 24px);
  border: 2px solid #c8b6a8;
  border-radius: 4px;
  background: rgb(255 255 255 / 0.62);
  /* A flex item's `min-width` is `auto`, so without this a row grows to fit its whole
     name and overhangs the next sub-column instead of the name yielding. */
  min-width: 0;
}

.board-columns > section:first-child .board-orders span {
  flex-direction: column;
  gap: 2px;
  align-items: flex-start;
  justify-content: center;
}

.board-columns > section:first-child .board-orders small {
  max-width: 100%;
  font-size: max(15px, min(6cqw, 24px));
  text-align: left;
}

/*
 * Every size is bounded by the height its own row was given, so a full page
 * compresses instead of spilling past the bottom edge. The floor keeps a
 * compressed row legible: if 12 rows cannot be read at distance the answer is a
 * smaller page, not type nobody can see.
 *
 * In Progress is additionally capped *below* Order Ready's number, via a ceiling
 * `board.js` publishes on the page once the ready column has been fitted. A full
 * ready column beside a near-empty In Progress column would otherwise compress the
 * ready numbers under the in-progress ones and invert the one hierarchy this surface
 * has — the frame caught exactly that.
 */
.board-orders b {
  font-size: min(
    max(24px, min(clamp(28px, 4.6vw, 88px), var(--row-height) * 0.62)),
    var(--number-ceiling, 132px)
  );
  font-variant-numeric: tabular-nums;
  font-weight: inherit;
  line-height: 1.05;
  /* Never the thing that yields: order 12 clipped to "1" is a different order. */
  flex-shrink: 0;
}

/* Order Ready's numbers are larger, so the answer is legible from further back
   than the question. Size, not colour — rule 24. */
.board-columns > section:last-child .board-orders b {
  font-size: var(--ready-number);
}

.board-columns > section:last-child .board-orders span {
  position: relative;
  overflow: hidden;
  border: 0;
  border-radius: 0;
  color: #fffaf3;
  background: #be420e;
  clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 0 100%);
  box-shadow: inset 0 -3px 0 rgb(112 46 13 / 0.18);
}

/* Names are set at roughly half the number: legible to a Guest who has walked up,
   subordinate to the number a volunteer calls across the hall. `0.4` is what binds on
   a full page, so only a sparse board grows. */
.board-orders small {
  overflow: hidden;
  color: #765845;
  /* `cqw`, not `vw`: sized off the viewport, a name truncated to "Mi…" in the narrow
     In Progress column while the wide Ready column had room to spare. */
  font-size: max(15px, min(clamp(18px, 10cqw, 64px), var(--row-height) * 0.4));
  line-height: 1.2;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.board-orders[style*="--sub-columns: 3"] small {
  font-size: max(
    15px,
    min(clamp(17px, 7cqw, 42px), calc(var(--row-height) * 0.34))
  );
}

.board-columns > section:last-child .board-orders small {
  color: #fff4e7;
}

.board-empty {
  margin: clamp(26px, 6vh, 72px) 0 0;
  color: #765845;
  font-size: clamp(24px, 2.1vw, 36px);
  line-height: 1.25;
}

/* Toast's information bar: status on the left, freshness on the right, one
   baseline, separated from the columns by a rule so it reads as chrome rather
   than as another order. */
.board-info {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  align-items: baseline;
  justify-content: space-between;
  /* The separation is mostly padding, so most of the bar's footprint falls inside
     its own `offsetHeight`, which is what the row budget in `board.js` measures.
     The remaining margin is read explicitly there. */
  padding-top: 16px;
  margin-top: 18px;
  border-top: 1px solid #d9c8b9;
}

.board-assignment {
  display: flex;
  gap: 10px 16px;
  align-items: baseline;
  margin: 0;
  color: #765845;
  font-size: clamp(16px, 1.15vw, 22px);
}

.board-assignment strong {
  overflow: hidden;
  max-width: 56vw;
  color: #332317;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  text-overflow: ellipsis;
  text-transform: uppercase;
  white-space: nowrap;
}

.board-assignment #board-name:not(:empty)::before {
  content: "· ";
}

.board-status {
  margin: 0;
  color: #765845;
  font-size: clamp(16px, 1.3vw, 24px);
}

.board-freshness {
  margin: 0 0 14px;
  padding: 8px 14px;
  color: #7c3a13;
  border: 1px solid #efaa76;
  border-radius: 999px;
  background: #fff0df;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: clamp(16px, 1.3vw, 24px);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.board-freshness:empty {
  display: none;
}

.board-page.board-loading .board-assignment {
  visibility: hidden;
}

/*
 * Rule 25's message is the whole screen when it appears. An empty board reads as
 * "nothing is ready", which is a lie, so the correction has to be as legible as
 * the orders it replaces — at 24px on a wall-mounted 1080p display it is not, and
 * a Guest twenty feet away sees a blank board and walks to a counter.
 */
.board-page.board-outage .board-info {
  place-content: center;
  text-align: center;
}

.board-page.board-outage .board-assignment,
.board-page.board-no-open .board-assignment {
  display: none;
}

.board-page.board-outage .board-status,
.board-page.board-no-open .board-status {
  max-width: 24ch;
  color: #8a3211;
  font-size: clamp(24px, 3.4vw, 56px);
  line-height: 1.08;
}

.board-page.board-no-open .board-columns,
.board-page.board-outage .board-columns {
  display: none;
}

.board-page.board-no-open .board-main,
.board-page.board-outage .board-main {
  grid-template-rows: auto 1fr;
}

.board-page.board-no-open .board-info,
.board-page.board-outage .board-info {
  display: grid;
  place-content: center;
  min-height: 0;
  margin-top: 0;
  border-top: 0;
  text-align: center;
}

/* A board assignment remains the provenance after Close. This is a terminal
   public state, not an outage: identity stays visible, order lists are absent,
   and the irreversible result takes the screen at distance-reading scale. */
.board-page.board-closed .board-columns {
  display: none;
}

.board-page.board-closed .board-main {
  grid-template-rows: auto 1fr;
}

.board-page.board-closed .board-info {
  display: grid;
  place-content: center;
  gap: clamp(18px, 3vh, 36px);
  min-height: 0;
  margin-top: 0;
  text-align: center;
}

.board-page.board-closed .board-status {
  max-width: 22ch;
  color: #8a3211;
  font-size: clamp(48px, 5.5vw, 96px);
  line-height: 1.02;
  letter-spacing: -0.035em;
}

.board-page.board-closed .board-freshness {
  color: #765845;
  font-size: clamp(20px, 1.8vw, 32px);
  white-space: normal;
}

#event-list {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

#event-list li {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 20px;
  min-height: 78px;
  padding: 18px 20px;
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.72);
}

.event-name {
  display: block;
  margin-bottom: 6px;
  font-size: 17px;
  font-weight: 600;
}

.event-meta {
  color: var(--muted);
}

.event-state {
  padding: 8px 12px;
  color: var(--orange-text);
  background: #fff7ed;
  font-size: 12px;
}

/*
 * The one live region every Role Workspace announces through, and it must be
 * *gone* when it has nothing to say rather than merely mostly gone.
 *
 * A percentage translate resolves against the element's own height, so
 * `translateY(140%)` moved an empty region — 28px of padding, no text — by only
 * 39.2px, when leaving the screen costs its height plus its own 24px offset. It
 * sat 29px into the viewport as an unlabelled dark rectangle at the bottom
 * right, on all six surfaces. On a 390px phone showing four ready orders it
 * covered a Pickup Code, which is the single thing on that surface a Guest
 * cannot do without. Two earlier frames showed the rectangle and I read it as a
 * capture artefact; the Codex visual check named it, and `elementFromPoint`
 * settled it.
 *
 * So the hidden state is expressed in a unit that does not depend on how much
 * text the region happens to hold: `bottom` is the offset it must cross, and
 * `100%` its own height. `calc` keeps the two honest even if either changes, and
 * the region can carry one line or four without the geometry needing rechecking.
 *
 * `visibility` is what actually removes it from hit-testing — a fully
 * translated element is still a target, and this one overlaps real content. It
 * is deliberately not `display: none`: an assistive technology must keep
 * observing the node for `aria-live` to announce into it at all, and toggling
 * `display` would re-create rather than update it.
 */
.status {
  position: fixed;
  right: 24px;
  bottom: 24px;
  max-width: min(420px, calc(100% - 48px));
  padding: 14px 18px;
  color: white;
  background: var(--surface);
  box-shadow: 0 16px 35px -18px rgb(0 0 0 / 0.6);
  transform: translateY(calc(100% + 24px));
  visibility: hidden;
  transition:
    transform 180ms ease,
    visibility 180ms;
}

.status.visible {
  transform: translateY(0);
  visibility: visible;
}

.status.error {
  background: #9f1239;
}

/* Event Close has one persistent visual authority: `.event-lock`. The shared
   live region still announces the transition, but it must not remain as a
   second card or toast beside the terminal state after that card is visible. */
body:has(.event-lock:not([hidden])) [data-live-region] {
  position: fixed !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0 0 0 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
  box-shadow: none !important;
  transform: none !important;
  visibility: visible !important;
}

/* Connectivity has already yielded to authoritative Closed state. Removing
   this redundant alert from layout also removes its alert semantics, leaving
   the clipped shared live region as the one announcement. */
body:has(.event-lock:not([hidden])) .connectivity-status {
  display: none !important;
}

/*
 * Desk feedback stays in the document flow. A fixed notice had only six pixels
 * of clearance above the greeting at 390px; one extra wrapped line on Linux
 * covered it. Flow layout makes every message reserve its actual height.
 */
.desk-page .status {
  position: static;
  max-width: 100%;
  margin: 0 0 16px;
  transform: none;
}

.desk-page .status.visible {
  transform: none;
}

.desk-page .status:empty {
  margin: 0;
  padding: 0;
  visibility: hidden;
}

.connectivity-status {
  max-width: 72rem;
  margin: 0 auto 1rem;
  padding: 0.9rem 1rem;
  border: 1px solid #c2410c;
  background: #fff7ed;
  color: #7c2d12;
  font-weight: 650;
}

@keyframes breathe {
  to {
    transform: rotate(4deg) scale(1.04);
  }
}

.registration {
  margin-top: 64px;
  padding-top: 38px;
  border-top: 1px solid var(--border);
}

.audit {
  margin-top: 64px;
  padding-top: 38px;
  border-top: 1px solid var(--border);
}

.audit-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  margin-top: 24px;
}

.audit-grid > * {
  min-width: 0;
}

#event-close-form,
#report-access-form {
  margin-top: 24px;
}

#close-blockers:not(:empty) {
  padding: 12px;
  border-left: 5px solid var(--orange);
  background: #fff7ed;
}

.confirmation {
  border-left: 5px solid var(--orange);
  background: #fff7ed;
}

.report-scroll {
  margin-top: 20px;
  overflow: auto;
}

#report-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

#report-table caption,
#report-table th,
#report-table td {
  padding: 10px;
  border: 1px solid var(--border);
  text-align: left;
}

#report-table caption {
  border-bottom: 0;
}

.registration-workspace {
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 20px;
  margin-top: 24px;
}

.registration-tools {
  display: grid;
  gap: 20px;
}

.registration h3 {
  margin: 0 0 20px;
  font-size: 24px;
  font-weight: 500;
}

.access-qr {
  width: min(240px, 100%);
  padding: 10px;
  border: 1px solid var(--border);
  background: white;
}

.access-qr svg {
  display: block;
  width: 100%;
  height: auto;
}

.balance-line {
  margin: 20px 0 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 14px;
}

.balance-line output {
  font-size: 24px;
  font-weight: 700;
}

#recovery-form {
  margin-top: 28px;
  padding-top: 28px;
  border-top: 1px solid var(--border);
}

#recovery-form fieldset {
  display: grid;
  gap: 10px;
}

.hidden {
  display: none !important;
}

.onboarding-settings {
  display: grid;
  gap: 24px;
  margin-top: 72px;
}

.onboarding-settings details {
  padding-block: 18px;
  border-bottom: 1px solid var(--border);
}

.onboarding-settings summary {
  cursor: pointer;
  font-weight: 700;
}

.onboarding-settings li {
  margin-block: 10px;
  line-height: 1.55;
}

.onboarding-settings summary:focus-visible {
  outline: 3px solid rgb(234 88 12 / 0.3);
  outline-offset: 4px;
}

.guest-shell {
  max-width: 760px;
}

.guest-status,
.balance-panel,
.activity-panel {
  margin-top: 36px;
}

.credit-tools {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: 20px;
  margin-top: 20px;
}

.receive-panel,
.transfer-panel {
  padding: clamp(24px, 4vw, 38px);
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.8);
  backdrop-filter: blur(20px);
}

.recipient-code {
  display: block;
  margin: 8px 0 16px;
  overflow-wrap: anywhere;
  color: var(--orange-text);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-weight: 700;
}

/*
 * A refused transfer field. It carries the same duty as `.handoff-error` — a
 * refusal written next to the field it was made in, staying there until the
 * Guest changes something — so it takes the same treatment rather than
 * inventing a second dialect for the same idea.
 */
.transfer-error {
  margin: 0;
  padding: 8px 10px;
  border-left: 3px solid #b91c1c;
  background: #fef2f2;
  color: #7f1d1d;
  font-weight: 600;
  overflow-wrap: anywhere;
}

#transfer-amount[aria-invalid="true"],
#transfer-recipient[aria-invalid="true"] {
  border-color: #b91c1c;
  outline: 2px solid #b91c1c;
  outline-offset: 1px;
}

.transfer-review {
  margin-top: 24px;
  padding: 20px;
  border-left: 4px solid var(--orange);
  background: #fff7ed;
}

.ordering {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(280px, 0.85fr);
  gap: 48px;
  margin-top: 64px;
}

.stall-list {
  display: grid;
  gap: 0;
  margin-top: 24px;
  border-top: 1px solid var(--border);
}

.stall-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px 24px;
  padding: 28px 0 28px 20px;
  border-bottom: 1px solid var(--border);
  border-left: 5px solid var(--orange);
}

.stall-row h3,
.stall-row p {
  margin: 0;
}

.capacity,
.orders-ahead {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
}

.orders-ahead {
  color: var(--muted);
}

.orders-ahead.busy {
  color: var(--rose);
  font-size: 14px;
  font-weight: 700;
}

.guest-menu {
  display: grid;
  grid-column: 1 / -1;
  gap: 10px;
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}

.guest-menu li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.guest-menu button {
  /* WCAG 2.2 AA target size, on the control a Guest uses most, one-handed. */
  min-height: 44px;
  padding-inline: 18px;
}

/*
 * Rule 33, stated where it bites. The Basket panel carries the same rule in its own
 * words, but at 390px the two regions stack and the panel sits hundreds of pixels
 * below the Add controls this explains — so the reason has to travel to them. Prose
 * rather than a compact mono status label, because it names an escape and where to
 * find it: the mono voice on this surface is for state, not for instructions.
 */
.ordering-blocked {
  margin: 0;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  border-left: 5px solid var(--orange);
  background: rgb(253 186 116 / 22%);
  line-height: 1.5;
}

/* ------------------------------------------------------------------ *
 * Guest — Ready for Pickup and the Undo Window (#36)
 * ------------------------------------------------------------------ */

.ready-panel,
.undo-panel {
  padding: clamp(20px, 4vw, 32px);
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgb(255 255 255 / 70%);
}

@media (max-width: 480px) {
  .ready-panel {
    padding: 14px 12px;
  }
}

/* Let the Guest atmosphere show through a lighter directional wash. */
body:has(.guest-shell) {
  background: linear-gradient(
    100deg,
    rgb(255 255 255 / 0.88) 0 34%,
    transparent 72%
  );
}

.undo-panel {
  border-color: var(--orange);
}

.ready-list {
  display: grid;
  gap: 8px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

/* Fixed columns keep every identifier pair on one line at phone width. */
.ready-row {
  padding: 12px 14px;
  border-left: 5px solid var(--orange);
  background: linear-gradient(
    100deg,
    rgb(253 186 116 / 18%),
    rgb(253 164 175 / 14%) 78%,
    rgb(255 247 237 / 90%)
  );
}

.ready-row strong {
  display: block;
}

.ready-total {
  color: var(--orange-text);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0;
  white-space: nowrap;
}

/*
 * The two numerals a Guest has to say out loud, at the scale of the thing they
 * are for. F3's Disney pickup screen gives the order number the whole display,
 * because it is read at a counter with somebody waiting — this surface had it at
 * 16px inside a sentence while the Credit balance below took 52px.
 *
 * Side by side rather than stacked: they are stated together, and the pair is
 * what identifies the Stall Order. Mono so the digits are unambiguous, and each
 * carries its own label so a three-digit code is never mistaken for an order
 * number. They wrap to one per line only when the row is too narrow to hold
 * both without shrinking the digits.
 */
.ready-stall {
  font-size: 16px;
  letter-spacing: -0.02em;
}

.ready-figures {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 2px 16px;
  margin: 6px 0 0;
}

.ready-figure {
  display: grid;
  gap: 1px;
}

.ready-figure-label {
  color: var(--orange-text);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Pickup identifiers outrank balance and greeting on phones. */
.ready-figure-value {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: min(13vw, 44px);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

.ready-instruction {
  display: block;
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.4;
}

.ready-empty {
  color: var(--muted);
}

/*
 * The bounded period as a shape, filling toward the order being sent rather than
 * draining toward a loss. `--elapsed` is a 0–1 fraction set by `guest.js` each
 * second; the transition covers the gap between ticks so it reads as a sweep rather
 * than as a stutter.
 *
 * It carries no text and is `aria-hidden`, because the line beneath it says the same
 * thing in words — and this surface has exactly one live region, which speaks twice.
 * A second announcing element here would bury both.
 */
.undo-progress {
  height: 6px;
  margin: 14px 0 10px;
  border-radius: 3px;
  background: rgb(234 88 12 / 18%);
}

.undo-progress::before {
  display: block;
  width: calc(var(--elapsed, 0) * 100%);
  height: 100%;
  border-radius: inherit;
  background: var(--orange);
  content: "";
  transition: width 1s linear;
}

/* A Guest who has stopped watching should not find a bar frozen mid-sweep: once the
   countdown stops, it reads as full. `:has()` and not a sibling combinator, because
   the bar precedes the countdown in the DOM — the state lives downstream of the
   element it has to style. */
.undo-panel:has(.undo-countdown[data-expired="true"]) .undo-progress::before {
  width: 100%;
}

/* The sweep is decoration on top of a line of text that already says the same
   thing, so it is the first thing to go when motion is unwelcome. */
@media (prefers-reduced-motion: reduce) {
  .undo-progress::before {
    transition: none;
  }
}

/*
 * One timer node, updated in place. It is deliberately not a live region: the
 * workspace's single polite region announces at three seconds and at expiry,
 * so nobody is read a number once a second.
 */
.undo-countdown {
  margin: 8px 0 4px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 1.1rem;
  color: var(--orange-text);
}

.undo-countdown[data-expired="true"] {
  color: var(--muted);
}

.undo-panel button {
  min-height: 44px;
  margin-top: 12px;
}

.basket-panel {
  align-self: start;
  padding: clamp(24px, 4vw, 40px);
  color: white;
  background: var(--surface);
}

/*
 * On `--surface` the accent inverts rather than darkens.
 *
 * `--orange-text` exists to pass AA on this product's *light* backgrounds, and
 * on the dark panels it does the opposite — `#c2410c` on `#191c21` is 3.30 to 1,
 * worse than the `#ea580c` it replaced. Contrast is a property of the pair, so a
 * single darker accent cannot serve both directions. Peach is the same ramp read
 * from the other end, at 10.13 to 1.
 *
 * Both dark panels are listed together so a third one cannot be added without
 * this decision being visible.
 */
.basket-panel .eyebrow,
.basket-panel a,
.balance-panel .eyebrow {
  color: var(--peach);
}

#basket-lines {
  display: grid;
  gap: 18px;
  margin-block: 28px;
  padding: 0;
  list-style: none;
}

.basket-line {
  display: grid;
  gap: 8px;
  padding-bottom: 18px;
  border-bottom: 1px solid rgb(255 255 255 / 0.2);
}

.basket-warning {
  color: #fed7aa;
  font-size: 13px;
  line-height: 1.5;
}

.remove-item {
  justify-self: start;
  min-height: 40px;
  padding: 0;
  color: #fdba74;
  background: transparent;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 4px;
}

#basket-total {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-weight: 700;
}

#basket-status {
  color: #fed7aa;
  line-height: 1.5;
}

.place-order {
  width: 100%;
  margin-top: 12px;
}

.order-panel {
  margin-top: 36px;
  padding: clamp(24px, 4vw, 40px);
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.8);
  backdrop-filter: blur(20px);
}

#order-list {
  display: grid;
  gap: 16px;
}

.order-card {
  padding: 20px;
  border-left: 5px solid var(--orange);
  background: #fff7ed;
}

.order-card h3,
.order-card p {
  margin: 0 0 10px;
}

.order-card ul {
  padding-left: 20px;
}

/*
 * A retained Stall Order, held on the device through an outage.
 *
 * It gives up the orange left border and the warm fill a live `.order-card`
 * carries, because that accent is what live state looks like everywhere else on
 * this surface — and the one thing rule 31 cannot afford is a cached number
 * reading as a current one. Neutral border, no fill: present and legible, and
 * visibly not the same kind of fact as a live row.
 */
.retained-order {
  border-left: 5px solid var(--border);
  background: none;
}

.retained-note {
  margin: 0 0 4px;
  max-width: none;
}

/*
 * The number and the code in the mono face this surface already uses for a value
 * that gets read aloud — the Ready row's Pickup Code and the Recipient code both
 * do the same. A Guest stating this at a counter is transcribing it, so the
 * digits are set for reading rather than for prose.
 */
.retained-identity {
  margin: 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-weight: 650;
  letter-spacing: 0.01em;
}

.balance-panel {
  padding: clamp(24px, 5vw, 52px);
  color: white;
  background: var(--surface);
}

#guest-balance {
  display: block;
  margin-block: 8px 18px;
  font-size: clamp(52px, 12vw, 96px);
  font-weight: 300;
  letter-spacing: -0.06em;
}

@media (max-width: 480px) {
  .guest-shell > h1 {
    font-size: min(9vw, 34px);
  }

  #guest-balance {
    font-size: min(8vw, 30px);
  }
}

.activity-panel ul {
  display: grid;
  gap: 10px;
  padding-left: 20px;
}

.error-text {
  color: #9f1239;
  font-weight: 600;
}

@media (max-width: 820px) {
  header,
  main {
    width: min(100% - 32px, 1280px);
  }

  main {
    padding-top: 42px;
  }

  .workspace,
  .service-grid,
  .registration-workspace,
  .audit-grid,
  .credit-tools,
  .ordering,
  .fulfillment-queues,
  .events {
    grid-template-columns: 1fr;
  }

  .workspace {
    margin-top: 42px;
  }

  .events {
    gap: 24px;
  }

  .menu-row,
  .ingredient-row,
  .stock-actions,
  .runner-alert,
  .handoff-form {
    grid-template-columns: 1fr;
  }

  .runner-alert input {
    grid-column: auto;
  }

  /*
   * The board is a wall-mounted landscape display, but it is a plain URL and
   * someone will open it on a phone — to check it, or because the TV failed. Two
   * narrow columns at 390px would leave neither legible, so they stack, and the
   * ready column keeps its larger type.
   */
  .board-main {
    padding-inline: 16px;
  }

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

/*
 * Action Feedback (ADR 0003 points 6, 7, 10, 11). A persistent record anchored
 * immediately after the immutable row it acted on. Never fixed, never
 * overlaid, never auto-dismissed — it is deliberately not a toast.
 */
.action-feedback {
  position: static;
  box-sizing: border-box;
  max-width: 100%;
  min-width: 0;
  overflow-wrap: anywhere;
  margin: 0.75rem 0 1rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--border);
  border-left: 4px solid var(--orange);
  border-start-start-radius: 0;
  border-end-end-radius: 0;
  background: #fffdfb;
  color: var(--surface);
  font-size: 0.9rem;
}

.action-feedback:focus-visible {
  outline: 3px solid var(--orange);
  outline-offset: 3px;
}

.action-feedback-heading {
  margin: 0 0 0.25rem;
  font-size: 0.95rem;
  font-weight: 650;
  letter-spacing: -0.01em;
}

.action-feedback-status {
  margin: 0 0 0.6rem;
  font-weight: 600;
}

.action-feedback-detail {
  display: grid;
  grid-template-columns: minmax(6rem, 12rem) minmax(0, 1fr);
  gap: 0.2rem 0.9rem;
  margin: 0;
  min-width: 0;
}

.action-feedback-detail dt {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.action-feedback-detail dt,
.action-feedback-detail dd {
  min-width: 0;
  overflow-wrap: anywhere;
}

.action-feedback-detail dd {
  margin: 0;
}

.action-feedback-dismiss {
  min-height: 44px;
  min-width: 44px;
  margin-top: 0.8rem;
  padding: 0 1rem;
  border: 1px solid var(--surface);
  background: transparent;
  color: var(--surface);
  font: inherit;
}

.action-feedback-summary {
  margin: 0.75rem 0 1rem;
  border: 1px solid var(--border);
  background: #fffdfb;
}

.action-feedback-summary > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.45rem 0.75rem;
  cursor: pointer;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
}

.action-feedback-summary > .action-feedback {
  margin-inline: 0.75rem;
}

.action-feedback[data-state="pending"],
.action-feedback[data-state="checking"] {
  border-left-color: #b45309;
  background: #fffbeb;
}

.action-feedback[data-state="committed"] {
  border-left-color: #15803d;
  background: #f6fdf8;
}

/*
  A record whose origin row is no longer shown keeps its own state colour and
  reads as displaced rather than as a new kind of thing: same card, dashed edge,
  parked at the end of the workspace.
*/
.action-feedback[data-anchor="detached"] {
  border-left-style: dashed;
}

.action-feedback[data-state="validation"],
.action-feedback[data-state="failure"],
.action-feedback[data-state="not-submitted"],
.action-feedback[data-state="blocked"],
.action-feedback[data-state="offline"],
.action-feedback[data-state="closed-event"] {
  border-left-color: var(--rose);
  background: #fff5f7;
}

/* ------------------------------------------------------------------ *
 * Role Workspaces (#32 Event Overseer, and the siblings that follow)
 * ------------------------------------------------------------------ */

.role-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 20px;
}

.role-nav .role {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

/* 44px targets apply to navigation as much as to buttons. */
.role-nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: 2px;
  color: inherit;
  text-decoration: none;
  border-bottom: 2px solid transparent;
}

.role-nav-link:hover {
  border-bottom-color: var(--peach);
}

.role-nav-link[aria-current="page"] {
  border-bottom-color: var(--orange);
}

.role-nav .text-button {
  min-height: 44px;
}

.role-sign-in {
  max-width: 32rem;
}

.closed-event-history {
  max-width: 32rem;
  margin-top: 24px;
}

.closed-event-history > summary {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-content: center;
  min-height: var(--v2-target);
  padding-inline: 2px;
  color: var(--orange-text);
  cursor: pointer;
  font-weight: 700;
  list-style-position: inside;
}

.closed-event-history > summary::after {
  content: "+";
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  padding-left: 12px;
  font-size: 1.35rem;
  font-weight: 400;
}

.closed-event-history[open] > summary::after {
  content: "−";
}

.closed-event-history :is(summary, input, button):focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

.closed-event-history > summary small {
  grid-column: 1;
  margin: 3px 0 0;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 400;
}

.closed-history-panel {
  margin-top: 12px;
  padding: clamp(22px, 5vw, 32px);
}

.closed-history-result {
  min-height: 0;
  margin: 18px 0 0;
  line-height: 1.5;
}

.closed-history-result:empty {
  display: none;
}

.closed-history-result[data-state="error"] {
  padding-left: 12px;
  border-left: 3px solid var(--rose);
  color: var(--v2-danger-text);
}

/*
 * Closed Event history keeps its visible result beside the controls that need
 * correction. The shared live region still announces the same sentence, but
 * this route scopes it to an assistive-only copy so it cannot become a second
 * fixed overlay above the history form. Any ordinary workspace announcement
 * removes this class and keeps the shared toast behavior unchanged.
 */
#closed-event-history ~ #status.history-announcement {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  visibility: visible;
  border: 0;
  transform: none;
  transition: none;
}

#closed-history-authentication-form {
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}

#closed-history-events {
  display: grid;
  gap: 8px;
  margin-top: 10px;
}

.closed-history-choice {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--v2-target);
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--v2-radius);
  background: rgb(255 255 255 / 0.72);
}

.closed-history-choice input {
  width: 20px;
  min-height: 20px;
  margin: 0;
}

.overseer-workspace,
.overseer-settings {
  display: flex;
  flex-direction: column;
  gap: 44px;
  margin-top: 48px;
  min-width: 0;
}

.health-totals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 2px;
  margin: 18px 0 0;
  border: 1px solid var(--border);
  background: var(--border);
}

.health-totals > div {
  padding: 18px 20px;
  background: #fffdfb;
}

.health-totals dt {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.health-totals dd {
  margin: 6px 0 0;
  font-size: 2.1rem;
  font-weight: 300;
  letter-spacing: -0.04em;
}

/*
 * O4: the comparison sits under the count it belongs to, at supporting weight,
 * so the absolute number stays what the eye lands on. It is a second `<dd>` for
 * the same `<dt>`, which is what a definition list is for — a share is another
 * statement about Received, not a separate metric.
 *
 * The `dd` rule above sets 2.1rem and -0.04em, so both are overridden here
 * rather than left to inherit a display size onto supporting text.
 */
.health-totals .total-share {
  margin: 4px 0 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.4;
  color: var(--muted);
}

.health-basis {
  margin: 14px 0 0;
  font-size: 13px;
}

.exception-list,
.stall-health-list,
.credential-list,
.report-list,
.correction-list {
  margin: 18px 0 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}

.exception,
.correction-row {
  padding: 16px 18px;
  border-left: 3px solid var(--orange);
  background: #fffdfb;
  margin-bottom: 12px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.exception.empty {
  border-left-color: var(--border);
  color: var(--muted);
}

.exception-summary {
  margin: 0 0 4px;
  font-weight: 600;
}

.exception p:last-child,
.correction-row p:last-child {
  margin-bottom: 0;
}

.stall-health-row {
  padding: 20px 0;
  border-top: 1px solid var(--border);
  min-width: 0;
}

.stall-health-row h3 {
  margin: 0 0 8px;
}

.stall-health-row .queue-counts {
  margin: 10px 0 0;
}

/*
 * O4: this stall against the fair's own current median, directly under the
 * counts it is derived from.
 *
 * `data-load` tints the rule on the left, and that is all it does. The sentence
 * itself names the busiest and the quietest end, because colour is never the
 * sole carrier of meaning — remove every colour here and the row still says
 * which end of the fair it is on.
 */
.stall-health-row .stall-comparison {
  margin: 8px 0 0;
  padding-left: 10px;
  border-left: 3px solid var(--border);
  font-size: 13px;
}

.stall-comparison[data-load="high"] {
  border-left-color: var(--orange);
}

.stall-comparison[data-load="low"] {
  border-left-color: #9ca3af;
}

.stall-health-row .event-state[data-capacity-state="Open"] {
  background: #dcfce7;
}

/*
 * O6: the Pause form stacks, because rule 18's reason now carries a visible
 * label and a statement of what naming it does, and neither belongs squeezed
 * beside a button. A row was a flex line built for a field plus a button; the
 * requirement is a third thing and reads before the action, not beside it.
 */
.pause-exception {
  display: grid;
  gap: 12px;
  margin-top: 16px;
  min-width: 0;
}

.pause-exception label {
  min-width: 0;
}

.pause-exception input {
  width: 100%;
}

/* The shared `.hint` carries a 30px bottom margin; the grid gap owns spacing here. */
.pause-requirement {
  margin: 0;
  max-width: 46ch;
  font-size: 13px;
}

.pause-exception .pause-stall {
  justify-self: start;
}

.pause-stall {
  min-height: 48px;
  border: 1px solid var(--surface);
  background: transparent;
  color: var(--surface);
}

.pause-stall:hover {
  background: var(--surface);
  color: white;
}

.settings-outbound {
  padding-top: 24px;
  border-top: 1px solid var(--border);
  color: var(--muted);
}

/*
 * A link that leaves this surface is a real target, so it is sized like one
 * rather than left as inline prose.
 */
.outbound-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--orange-text);
}

.credential-row {
  padding-block: 20px;
  border-top: 1px solid var(--border);
  min-width: 0;
}

.credential-row h3 {
  margin: 0;
}

/*
 * The blast radius of a rotation, stated before the act. It carries the guarded
 * rose the Event Close panel uses, because it is the same kind of statement — an
 * irreversible consequence named in advance — but as an inline rule rather than
 * a whole guarded panel: rotating a credential is routine setup work an Overseer
 * is expected to do, not an act to be discouraged.
 *
 * The two spans stack so "what this ends" and "what it spares" read as separate
 * facts. Colour is never the only carrier: the rule, the indent, and the two
 * distinct sentences all survive a monochrome screen.
 */
.credential-radius {
  display: grid;
  gap: 4px;
  margin: 10px 0 0;
  padding-left: 14px;
  border-left: 2px solid var(--rose);
  font-size: 0.85rem;
  line-height: 1.5;
  min-width: 0;
  overflow-wrap: anywhere;
}

/*
 * What the rotation ends inherits the root text colour rather than the muted
 * one: it is the consequence, and it should not read as a footnote beside the
 * reassurance below it.
 */
.credential-spares {
  color: var(--muted);
}

.report-list li {
  padding-block: 4px;
}

.report-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--orange-text);
}

/*
 * The label is the target for a checkbox, so it is the thing sized to 44px.
 */
.overseer-settings .choice {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
}

.overseer-settings .board-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.close-reconciliation {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 6px 20px;
  margin: 18px 0 0;
  min-width: 0;
}

.close-reconciliation dt {
  color: var(--muted);
  overflow-wrap: anywhere;
}

.close-reconciliation dd {
  margin: 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  text-align: right;
}

/*
 * Event Close is visually guarded so it can never be mistaken for routine
 * setup, without relying on colour alone to say so.
 *
 * What survives a monochrome screen had to be checked rather than assumed, and
 * two of the five declarations below turned out to carry nothing. `.panel`
 * (line 145) sets no `border-radius`, so both `radius: 0` lines are no-ops
 * against it; the 1px border matches `.panel`'s own width and the background is
 * a near-white against `.panel`'s near-white. Strip the hue and the only thing
 * left distinguishing the most destructive act in the application from the
 * Ready Board name field above it was the word "Irreversible".
 *
 * So the weight is structural now: a 4px inline-start rule the panel above does
 * not have, and heavier padding at that edge. Both survive greyscale, both
 * survive a forced-colours mode that discards the background entirely, and the
 * rose is left doing what colour should do — reinforcing a distinction that is
 * already legible without it.
 */
.panel.guarded {
  border: 1px solid var(--rose);
  border-inline-start: 4px solid var(--rose);
  background: #fff5f7;
  padding: 26px;
  padding-inline-start: 22px;
}

/* Small rose text needs rose-800 on the guarded panel; `--rose` is 4.40:1. */
.guarded-eyebrow {
  color: #9f1239;
}

/* Opaque states avoid the user agent's 1.98:1 disabled composite. */
.danger {
  color: white;
  background: #9f1239;
}

.danger:disabled {
  color: var(--muted);
  background: var(--border);
  cursor: not-allowed;
}

.close-blockers-panel {
  margin: 24px 0;
  padding-top: 20px;
  border-top: 1px solid var(--rose);
}

.close-blockers-panel h3 {
  margin: 0 0 12px;
}

.close-blockers {
  display: grid;
  gap: 10px;
  margin: 0;
  padding-left: 20px;
}

/*
 * The blast radius, immediately above the confirmation (rule 22).
 *
 * It takes the same rose rule O7 gave `.credential-radius`, because it is the
 * same kind of statement — an irreversible consequence named in advance — and an
 * Overseer who has read one should recognise the other. What differs is weight:
 * this one is not a footnote, so it keeps root text colour and full size. Every
 * line here is a consequence; none of them is a reassurance.
 *
 * Nothing depends on the rose. The heading, the rule, the indent, and the list
 * markers all survive greyscale, and the sentences say in words what the colour
 * only emphasises.
 */
.close-radius-panel {
  margin: 24px 0;
  padding-top: 20px;
  border-top: 1px solid var(--rose);
}

.close-radius-panel h3 {
  margin: 0 0 12px;
}

.close-radius {
  display: grid;
  gap: 10px;
  margin: 0;
  padding-left: 20px;
  line-height: 1.5;
  min-width: 0;
  overflow-wrap: anywhere;
}

/*
 * The Event-level lock (#38).
 *
 * Rendered by the shared Role Workspace shell, so it looks the same on all six
 * Role Workspaces. It carries the same guarded rose the Event Close panel does
 * — a Closed Event is the same irreversible fact seen from the other side —
 * and it never relies on colour alone: it is a heading and a sentence.
 */
.event-lock {
  max-width: 72rem;
  margin: 0 auto 24px;
  padding: 20px clamp(20px, 3vw, 32px);
  border: 1px solid var(--rose);
  border-start-start-radius: 0;
  border-end-end-radius: 0;
  background: #fff5f7;
}

.event-lock-title {
  margin: 0;
  font-size: clamp(20px, 2.4vw, 28px);
}

.event-lock-detail {
  margin: 10px 0 0;
  max-width: 570px;
  line-height: 1.55;
}

/* ------------------------------------------------------------------ *
 * Registration Desk Role Workspace (#33), as a sequence (D2)
 *
 * One vertical lane, in the same rhythm as the Event Overseer's. A desk
 * volunteer works down the screen in the order the queue moves — find, then
 * load, then hand over — so nothing here is laid out as a grid of equal cards
 * that would invite reading it in any other order.
 *
 * The sequence goes further than order: exactly one step is dominant, and the
 * other two collapse to what they resolved to. Rule 49 is the reason. This is
 * the one surface where a volunteer alternates between looking up at a person
 * and down at a phone, and a screen of four equal panels makes them re-find
 * their place in the task on every glance back down.
 * ------------------------------------------------------------------ */

/*
 * The masthead, sized for a surface worked standing up.
 *
 * `main` opens with 70px of padding and `.intro` puts a 48px display heading and
 * a lede under it, which is right on a page somebody reads and wrong on one they
 * *work*. Measured on a 390x844 phone it spent 517px — 61% of the viewport —
 * before the current step began, and left the step's own primary control at
 * 878px, below the fold. Rule 49 makes that the defining defect of this surface
 * rather than a matter of taste: the volunteer alternates between a person's
 * face and a phone screen, so anything they must scroll to reach costs them the
 * glance back up.
 *
 * The greeting stays, because arriving at a desk that says "Welcome each Guest"
 * is the tone this product wants and it is one line. It just stops being a
 * display heading.
 */
/* The eyebrow above the greeting was what kept it clear of the fixed sign-in
   notice; without it the two met at y149. This is that clearance, made its own
   rather than a side effect of a label. */
.desk-intro {
  padding-top: 12px;
  margin-bottom: 4px;
}

.desk-intro h1 {
  margin: 4px 0 0;
  font-size: 26px;
  font-weight: 400;
  letter-spacing: -0.03em;
}

.desk-workspace {
  display: flex;
  flex-direction: column;
  gap: 44px;
  margin-top: 28px;
  min-width: 0;
}

/*
 * The sequence is named for a screen reader and for anyone reading the page
 * cold, but the step headings carry the actual hierarchy — so this sits at the
 * scale of a label rather than competing with the step a volunteer is on.
 */
.sequence-heading {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/*
 * The identified Guest, held above the steps. It is deliberately compact: rule
 * 4 wants the immutable target visible wherever the volunteer acts, and rule 49
 * wants the current step to dominate — so this states who without becoming
 * something to read.
 */
.guest-strip {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px 20px;
  border: 1px solid var(--border);
  border-start-start-radius: 0;
  border-end-end-radius: 0;
  background: rgb(255 255 255 / 0.6);
  min-width: 0;
}

.desk-page .guest-strip:focus-visible {
  outline: 3px solid var(--surface);
  outline-offset: 4px;
}

/* The Desk uses the opaque V2 focus token. The shared legacy ring is
   translucent and falls below the visual distinction this busy workflow
   needs when an operator returns to the keyboard. */
.desk-page input:focus-visible,
.desk-page select:focus-visible,
.desk-page textarea:focus-visible,
.desk-page button:focus-visible,
.desk-page a:focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

.strip-eyebrow {
  margin: 0;
  color: var(--orange-text);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.strip-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
}

.desk-sequence {
  display: flex;
  flex-direction: column;
  gap: 28px;
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}

/*
 * A step is a step whether or not it is the current one; what changes is its
 * weight. `data-state` carries that, so no JavaScript sets an inline style and
 * the three states can be read off the DOM.
 */
.sequence-step {
  padding-top: 24px;
  border-top: 1px solid var(--border);
  min-width: 0;
}

/*
 * The current step. The orange left edge is the only place this surface spends
 * the accent on structure, and it is spent here because "which step am I on" is
 * the question the volunteer asks on every glance back down.
 */
.sequence-step[data-state="current"] {
  padding: 24px;
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--orange);
  background: #fffaf5;
}

/* Never colour alone: the index and the summary say the state in words. */
.sequence-step[data-state="waiting"] .step-index,
.sequence-step[data-state="waiting"] .step-name {
  color: var(--muted);
}

/*
 * Progress carried the smallest type on the surface at 11px, so a returning
 * glance could name the task but not place it in the three. 14px is the
 * arm-length floor; all three rise equally, so the current step's 28px heading
 * stays dominant against the collapsed steps' 20px.
 */
.step-index {
  margin: 0 0 6px;
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.sequence-step[data-state="current"] .step-index {
  color: var(--orange-text);
}

.step-name {
  margin: 0;
}

/*
 * The current step's own heading is the largest thing on the screen — which this
 * comment claimed before it was true. `clamp(24px, 3vw, 32px)` resolves on its
 * *minimum* at every phone width, because 3vw of 390px is 11.7px, so the step a
 * volunteer is working measured 24px against a 48px page greeting. The scale said
 * the greeting mattered twice as much as the task.
 *
 * A fixed floor of 28px instead, and the `vw` term is what escalates on a
 * tablet rather than what decides the phone. With the masthead now at 26px this
 * heading is the largest thing on a 390px screen, as rule 49 asks and as the
 * surface already said of itself.
 *
 * A collapsed step keeps its heading at ordinary `h3` size, so the difference
 * between "here" and "already done" is legible without reading either.
 */
.sequence-step[data-state="current"] .step-name {
  font-size: clamp(28px, 3vw, 32px);
  font-weight: 400;
  letter-spacing: -0.04em;
}

.step-summary {
  margin: 8px 0 0;
  color: var(--muted);
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.step-body {
  display: flex;
  flex-direction: column;
  gap: 24px;
  margin-top: 20px;
  min-width: 0;
}

.step-resume {
  margin-top: 6px;
}

/* The one line the control order cannot say by itself, after the lookup rather
   than in front of it. Zero margin: the shared `.hint` 30px is what let the
   branch read as a paragraph. */
.branch-guidance {
  margin: 0;
  color: var(--muted);
}

.desk-read-state {
  margin: 0;
  padding: 10px 12px;
  border-inline-start: 3px solid var(--orange);
  background: rgb(253 186 116 / 0.16);
  color: var(--surface);
}

.desk-read-state[data-state="failure"],
.desk-read-state[data-state="validation"] {
  border-inline-start-color: var(--rose);
  background: #fff5f7;
}

/*
 * The branch. It is inset under the lookup that failed, because a Guest nobody
 * holds is the other half of step one rather than a second way in — the whole
 * point of D3.
 */
.register-branch {
  padding-inline-start: 16px;
  border-inline-start: 3px solid var(--peach);
  min-width: 0;
}

.branch-reason {
  margin: 10px 0 20px;
  max-width: 570px;
  line-height: 1.55;
}

/*
 * The Guest record, opened from the strip. Shopify shows this as a sheet over a
 * persistent sale; at 390px there is no width for two regions at once, so ours
 * replaces the sequence and returns to it. That divergence is recorded in
 * `registration-desk.md`.
 */
.guest-record {
  display: flex;
  flex-direction: column;
  gap: 28px;
  padding: 24px;
  border: 1px solid var(--surface);
  min-width: 0;
}

.record-heading {
  margin: 0;
  font-size: clamp(24px, 3vw, 32px);
  font-weight: 400;
  letter-spacing: -0.04em;
}

.record-subject {
  margin: -20px 0 0;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.desk-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  min-width: 0;
}

.desk-form h3 {
  margin: 0;
}

/*
 * The review is the pause between typing a person in and committing them. It
 * is set apart so it reads as a distinct step rather than as more of the form
 * above it.
 */
.registration-review {
  padding: 24px;
  border: 1px solid var(--orange);
  background: #fffaf5;
  min-width: 0;
}

.registration-review h3 {
  margin: 0 0 14px;
}

.review-detail,
.guest-detail {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: 6px 20px;
  margin: 0;
  min-width: 0;
}

.review-detail > div,
.guest-detail > div {
  display: contents;
}

.review-detail dt,
.guest-detail dt {
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  align-self: center;
}

.review-detail dd,
.guest-detail dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.review-duplicate {
  margin: 16px 0 0;
  padding-inline-start: 14px;
  border-inline-start: 3px solid var(--rose);
  color: var(--surface);
}

/*
 * Three separate targets, stacked. They are never crowded onto one row,
 * because using an existing Guest and correcting a typo must not be adjacent
 * enough to hit by accident.
 */
.review-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin-top: 20px;
}

.use-existing {
  border: 1px solid var(--surface);
  background: transparent;
  color: var(--surface);
}

.use-existing:hover {
  background: var(--surface);
  color: white;
}

.credit-load,
.access-qr-panel,
.guest-recovery {
  min-width: 0;
}

/* A recovered Credit request remains visibly locked while its committed
   result is checked. Dashed edges supply a non-colour unavailable cue, while
   opaque neutral fills keep the typed amount and action readable. */
.desk-page .credit-load input:disabled {
  opacity: 1;
  color: #374151;
  border-color: #6b7280;
  border-style: dashed;
  background: #e5e7eb;
  cursor: not-allowed;
}

.desk-page .credit-load button:disabled {
  opacity: 1;
  color: #4b5563;
  border: 2px dashed #6b7280;
  background: #d1d5db;
  box-shadow: inset 0 0 0 1px #9ca3af;
  cursor: not-allowed;
}

.guest-strip .guest-detail {
  gap: 4px 20px;
}

.access-details {
  margin-top: 20px;
}

.access-countdown {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.85rem;
  color: var(--muted);
}

/* Expiry is said in words, never by colour alone. */
.access-countdown[data-expired="true"] {
  color: var(--rose);
}

/*
 * A text button here is still a target a volunteer hits with a thumb while
 * holding a cash box, so it is sized like every other one.
 */
.desk-workspace .text-button {
  min-height: 44px;
}

.guest-recovery fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}

.guest-recovery legend {
  padding: 0;
  color: var(--muted);
}

/* The label is the target for a radio, so the label is what is sized. */
.guest-recovery .choice {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
}

@media (max-width: 640px) {
  .desk-page .guest-strip .guest-detail {
    grid-template-columns: minmax(0, 1fr);
    gap: 2px;
  }

  .desk-page .guest-strip .guest-detail dd {
    margin-bottom: 8px;
  }

  .desk-page .guest-strip .guest-detail > div:last-child dd {
    margin-bottom: 0;
  }

  .action-feedback-detail {
    grid-template-columns: 1fr;
    gap: 0 0;
  }

  .action-feedback-detail dd {
    margin-bottom: 0.45rem;
  }
}

/* ------------------------------------------------------------------ *
 * Stall Staff — My Stall (#34)
 * ------------------------------------------------------------------ */

.my-stall-workspace {
  display: flex;
  flex-direction: column;
  gap: 44px;
  margin-top: 48px;
  min-width: 0;
}

.stall-panel {
  display: flex;
  flex-direction: column;
  gap: 34px;
  min-width: 0;
}

.stall-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

.active-stall-picker h2,
.stall-panel h3 {
  margin: 0 0 12px;
}

/*
 * Each blocker names its own stall, so it is set apart rather than run
 * together: a volunteer reads one outstanding item at a time.
 */
.blocker-list {
  margin: 0 0 22px;
  padding: 0;
  list-style: none;
  min-width: 0;
}

.blocker {
  padding: 14px 18px;
  margin-bottom: 10px;
  border-left: 3px solid var(--orange);
  background: #fffdfb;
  min-width: 0;
  overflow-wrap: anywhere;
}

.blocker[data-blocker-code="readiness-unconfirmed"] {
  border-left-color: var(--surface);
}

/*
 * Enable Orders is visually its own decision, arriving in its own bordered
 * panel after readiness is confirmed. It is never adjacent to the readiness
 * control in a way that reads as one step with two buttons.
 */
.enable-orders-panel {
  margin-top: 24px;
  padding: 22px;
  border: 1px solid var(--orange);
  background: #fffaf5;
  min-width: 0;
}

.enable-orders-panel .hint {
  margin: 0 0 16px;
}

.capacity-panel .capacity-controls {
  margin-top: 16px;
}

.stall-queues {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}

.stall-queues .queue-panel h4 {
  margin: 0 0 12px;
}

.stall-queues .queue-list,
.setup-list {
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}

.queue-row,
.setup-row {
  padding: 14px 0;
  border-top: 1px solid var(--border);
  min-width: 0;
  overflow-wrap: anywhere;
}

.menu-setup details {
  margin-top: 16px;
}

.menu-setup summary {
  display: flex;
  align-items: center;
  width: fit-content;
  min-height: 44px;
  font-weight: 700;
  cursor: pointer;
}

.menu-setup details[open] summary {
  margin-bottom: 12px;
}

.menu-setup form {
  max-width: 32rem;
  padding: 16px;
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.72);
}

.menu-setup form > .hint,
.menu-setup label > .hint {
  margin: 0;
}

.menu-enabled-option {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
}

.menu-enabled-option input {
  width: auto;
}

/*
 * An ingredient card is read at arm's length in one hand, and the thing being
 * reached for is the field at the bottom of it. So the block above that field
 * is kept to what a volunteer has to know before typing — the name, the two
 * counts, the threshold, and any alert — and nothing in it is given room it
 * does not use. At 390×844 the padding, the gaps and the name all come down
 * together, because trimming any one of them alone just moves the field a few
 * pixels and leaves it below the fold.
 */
.ingredient-stock-card {
  display: grid;
  min-width: 0;
  gap: 10px;
  padding: clamp(14px, 3vw, 28px);
  border: 1px solid var(--border);
  border-left: 5px solid var(--surface);
  background: rgb(255 255 255 / 0.82);
}

.ingredient-stock-card[data-ingredient-status="Low Stock"] {
  border-left-color: var(--rose);
}

.ingredient-stock-card[data-ingredient-status="Not entered"] {
  border-left-color: var(--orange);
}

.ingredient-stock-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 18px;
}

.ingredient-stock-name,
.ingredient-stock-card p {
  margin: 0;
}

.ingredient-stock-name {
  font-size: clamp(19px, 3vw, 30px);
  line-height: 1.2;
}

/*
 * The counts are the reading, not the caption. They were set smaller than the
 * ingredient's name, which put the largest type on the word a volunteer already
 * knows — they are standing in front of the potatoes — and the smallest on the
 * two numbers they came to the card to check. Available and Reserved lead now,
 * tabular so a column of ingredients lines up digit for digit, and the
 * threshold below stays a hint because it is the number that does not move.
 */
.ingredient-stock-card .stock-counts {
  font-size: clamp(15px, 2vw, 17px);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.ingredient-threshold {
  font-size: 13px;
}

.ingredient-stock-status {
  padding: 5px 9px;
  border: 1px solid currentColor;
  border-radius: 999px;
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
}

.ingredient-stock-card[data-ingredient-status="Low Stock"]
  .ingredient-stock-status {
  color: #9f1239;
}

.ingredient-stock-card[data-ingredient-status="Not entered"]
  .ingredient-stock-status {
  color: var(--orange-text);
}

/*
 * An active Restock Alert is the loudest thing on the card, and it is the only
 * thing on the card whose whole panel is tinted. The card's own left border is
 * left to say *which* state this ingredient is in; the alert says there is
 * something to do about it. Two rose left borders — the card's and the panel's —
 * read as one stripe with a gap in it at 390px, so the panel does not draw a
 * second one.
 */
.restock-alert {
  display: grid;
  gap: 8px;
  padding: 12px 14px;
  border: 1px solid #fecdd3;
  background: #fff1f2;
  color: #881337;
}

.restock-alert .eyebrow {
  margin: 0;
  font-weight: 700;
}

.restock-alert-text {
  font-weight: 500;
}

/*
 * Acknowledged is quieter and still present. It has to stay on the card: seen is
 * not fixed, and the alert clears only when Available rises above the threshold,
 * so a treatment that removed the panel would be telling a volunteer the
 * shortage was dealt with by looking at it.
 */
.restock-alert[data-acknowledged="true"] {
  border-color: #fed7aa;
  background: #fff7ed;
  color: #7c2d12;
}

.restock-alert .eyebrow,
.restock-alert .text-button {
  color: currentColor;
}

.restock-alert .text-button {
  justify-self: start;
  min-height: 44px;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.ingredient-stock-card .stock-actions {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
}

/*
 * The two writes stay two forms, side by side where there is room. Adding units
 * and replacing the count are different acts with different consequences, and a
 * single form with a mode switch would be one control that does both.
 */
.stock-form {
  display: grid;
  min-width: 0;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.72);
}

.stock-form-title,
.stock-field-label {
  font-weight: 700;
}

.stock-field-label {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.stock-form input,
.stock-form textarea {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
}

.stock-form button {
  justify-self: start;
  min-height: 44px;
}

@media (max-width: 820px) {
  .ingredient-stock-card .stock-actions {
    grid-template-columns: minmax(0, 1fr);
  }
}

/*
 * 390×844, one hand, and the measurement this section has to meet: the field and
 * the button that submits it are on screen together, without the volunteer
 * scrolling between typing a number and recording it.
 *
 * The savings come from the space around the reading, not from the reading. Every
 * guidance line, both counts, the threshold and the whole alert are still here
 * and still legible; what goes is the heading's gap, the card's padding, the gaps
 * between rows inside it, and the form's own padding. Nothing here reduces a tap
 * target below 44px, and the guidance keeps the body size the rest of the surface
 * uses — a stall in sun is the wrong place to save pixels on prose.
 */
@media (max-width: 480px) {
  .stall-setup-review:has(#ingredient-list) > .hint {
    margin: 0 0 12px;
  }

  #ingredient-list {
    display: grid;
    gap: 14px;
  }

  /* The section heading and its guidance are the last gap before the cards. */
  .stall-setup-review:has(#ingredient-list) h3 {
    margin: 0 0 8px;
  }

  #ingredient-list .ingredient-stock-card {
    gap: 8px;
    padding: 12px 14px;
  }

  /*
   * The status pill sits under the name rather than beside it. At 390px the two
   * of them competed for one line, and the name — the longest string on the card
   * — was the one that wrapped, putting a two-line ingredient name above a pill
   * that had space of its own all along.
   */
  .ingredient-stock-heading {
    gap: 4px 12px;
  }

  .ingredient-stock-card .stock-counts {
    font-size: 15px;
  }

  .ingredient-threshold {
    font-size: 12px;
  }

  /*
   * The hint above the button is what stood between the field and the submit.
   * It keeps its size and its wording and loses only the space around it.
   */
  .stock-form {
    gap: 6px;
    padding: 10px 12px;
  }

  .stock-form .stock-form-hint {
    line-height: 1.4;
  }

  .stock-form button {
    width: 100%;
    margin-top: 2px;
  }

  .restock-alert {
    padding: 10px 12px;
    gap: 6px;
  }
}

.queue-number {
  margin: 0 0 4px;
  font-weight: 600;
}

.queue-lines {
  margin: 0 0 4px;
}

.queue-age {
  margin: 0;
  color: var(--surface);
  font-size: 13px;
  font-weight: 700;
}

.queue-empty {
  padding: 14px 0;
  border-top: 1px solid var(--border);
}

.stall-panel .event-state[data-capacity-state="Open"] {
  background: #dcfce7;
}

@media (min-width: 720px) {
  .stall-queues {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

/* ------------------------------------------------------------------ *
 * Stall Staff — All Stalls (#35)
 * ------------------------------------------------------------------ */

/*
 * The queue is the first operational task, so this surface spends as little
 * height as it can before reaching it: at 390x844 a Received Stall Order's
 * action has to be reachable without scrolling.
 */
.compact-intro {
  margin-bottom: 0;
}

.compact-intro h1 {
  margin-bottom: 0;
}

.all-stalls-workspace {
  display: flex;
  flex-direction: column;
  gap: 22px;
  margin-top: 20px;
  min-width: 0;
}

/*
 * Keep the one poll-safe live region with Stall Staff's work. A second region
 * would break ADR 0003 point 11; moving this one into either workspace would
 * let polling destroy an announcement mid-read.
 */
#status:has(~ #my-stall-workspace),
#status:has(~ #all-stalls-workspace) {
  position: sticky;
  z-index: 2;
  top: 12px;
  right: auto;
  bottom: auto;
  max-width: 100%;
  margin: 0 0 16px;
  transform: none;
  /*
   * Here the region is a *record*, not a toast, so it is visible whenever it
   * holds anything — including after the five-second `visible` class comes off,
   * which the shared rule uses to slide a toast away and this surface must
   * survive. Stall Staff reads an arrival while both hands are busy; an
   * announcement that withdrew itself on a timer would be gone by the time they
   * looked up. `:empty` below is what hides it when there is nothing to record.
   */
  visibility: visible;
  color: var(--text);
  background: #fffaf5;
  border: 1px solid var(--border);
  border-left: 3px solid var(--orange);
  box-shadow: none;
  opacity: 1;
  transition: none;
}

#status.error:has(~ #my-stall-workspace),
#status.error:has(~ #all-stalls-workspace) {
  color: #7f1d1d;
  background: #fef2f2;
  border-left-color: #b91c1c;
}

#status:empty:has(~ #my-stall-workspace),
#status:empty:has(~ #all-stalls-workspace) {
  margin-bottom: 0;
  padding: 0;
  border: 0;
  /* Nothing recorded, nothing shown — and nothing left to hit-test either. The
     node stays in the tree because `aria-live` announces into it. */
  visibility: hidden;
}

/*
 * Compact selection. One line and one control — an always-expanded selector
 * obscured the queue in the prototype audit, and the selector itself lives in
 * the dialog behind Change stalls.
 */
.monitoring {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  padding: 12px 18px;
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.78);
  min-width: 0;
}

.monitoring-summary {
  margin: 0;
  min-width: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.monitoring button {
  min-height: 44px;
  padding: 0 18px;
  border: 1px solid var(--surface);
  background: rgb(255 255 255 / 0.9);
}

.setup-empty {
  padding: 22px;
  border: 1px solid var(--orange);
  background: #fffaf5;
  min-width: 0;
}

.setup-empty h3 {
  margin: 0 0 10px;
}

.setup-empty .hint {
  margin: 0;
}

.stall-dialog {
  width: min(30rem, calc(100vw - 32px));
  padding: clamp(20px, 4vw, 30px);
  border: 1px solid var(--border);
  background: #fffaf5;
  color: var(--text);
}

.stall-dialog::backdrop {
  background: rgb(17 24 39 / 0.45);
}

.stall-dialog h2 {
  margin: 0 0 10px;
}

.stall-choices {
  margin: 18px 0;
  padding: 0;
  border: 0;
}

.stall-choices legend {
  padding: 0;
  color: var(--muted);
}

/* 44px targets: the label is what the operator actually hits. */
.stall-choice {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 4px 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}

.stall-choice input {
  width: 22px;
  height: 22px;
  accent-color: var(--orange);
}

.stall-dialog-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.stall-dialog-actions .clipped:not(.primary) {
  border: 1px solid var(--surface);
  background: transparent;
}

/*
 * One swimlane per selected stall. The lane is the action boundary, so it is
 * drawn as a boundary: its own bordered field, headed by its own stall's name.
 */
.swimlanes {
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 0;
}

.stall-lane {
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-left: 5px solid var(--orange);
  background: rgb(255 255 255 / 0.85);
  min-width: 0;
}

.stall-lane-name {
  margin: 0;
  font-size: clamp(20px, 4vw, 24px);
  letter-spacing: -0.01em;
}

.stall-lane-counts {
  margin: 2px 0 12px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  color: var(--muted);
}

.lane-queue + .lane-queue {
  margin-top: 14px;
}

.lane-queue h3 {
  margin: 0 0 8px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.lane-list {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}

.stall-order-card {
  padding: 12px 14px;
  border: 1px solid var(--border);
  background: white;
  min-width: 0;
  overflow-wrap: anywhere;
}

/*
 * The whole safety property in one line of markup: the stall's name and the
 * Stall Order number are one string, on the card, above the action. Two stalls
 * both holding Stall Order 42 are never told apart by number alone.
 */
.stall-order-title {
  margin: 0;
  font-size: 17px;
}

.stall-order-lines {
  margin: 4px 0 0;
}

.stall-order-age {
  margin: 2px 0 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 13px;
  font-weight: 700;
  color: var(--surface);
}

.stall-order-actions {
  display: grid;
  gap: 8px;
  margin-top: 10px;
}

.stall-order-actions button {
  min-height: 44px;
  padding: 8px 14px;
  font-size: 14px;
  line-height: 1.25;
  text-align: left;
}

.ready-underway,
.lane-empty {
  margin: 0;
}

.duty-note {
  margin: 0;
}

.role-nav-link[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

@media (min-width: 720px) {
  .stall-lane {
    padding: 22px 24px;
  }

  .lane-queue + .lane-queue {
    margin-top: 18px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    animation: none !important;
    transition: none !important;
  }
}

/* ------------------------------------------------------------------ *
 * Stall Staff — safe handoff (#37)
 *
 * Shared by My Stall and All Stalls. Nothing here renders, masks, blurs, or
 * reveals an expected Pickup Code: the surface has never been sent one, so
 * there is no styling decision to get wrong.
 * ------------------------------------------------------------------ */

.handoff {
  min-width: 0;
}

.queue-row .handoff {
  margin-top: 10px;
}

.handoff-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
  margin: 0;
}

.handoff-label {
  font-weight: 600;
  font-size: 14px;
}

.handoff-form input.stated-pickup-code {
  min-height: 44px;
  max-width: 9ch;
  padding: 0 12px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 18px;
  letter-spacing: 0.25em;
}

.handoff-form input.stated-pickup-code[aria-invalid="true"] {
  border-color: #b91c1c;
  outline: 2px solid #b91c1c;
  outline-offset: 1px;
}

.handoff-hint,
.handoff-error {
  margin: 0;
}

.handoff-error {
  padding: 8px 10px;
  border-left: 3px solid #b91c1c;
  background: #fef2f2;
  color: #7f1d1d;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.handoff-form button.confirm-handoff {
  min-height: 44px;
  justify-self: start;
  padding: 8px 18px;
  text-align: left;
}

/*
 * The Handoff Grace Period. It is loud because it is short and reversible:
 * ten seconds is exactly as long as an operator has to notice a mistake.
 */
.handoff-grace {
  display: grid;
  gap: 8px;
  padding: 12px;
  border: 1px solid var(--orange);
  background: #fff7ed;
  min-width: 0;
}

/* The one node that counts down, and the one node that replaces it. */
.handoff-countdown {
  margin: 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 13px;
  font-weight: 700;
  color: var(--orange-text);
  overflow-wrap: anywhere;
}

.handoff-countdown[data-expired] {
  color: var(--text);
}

.handoff-grace button.undo-handoff {
  min-height: 44px;
  justify-self: start;
  padding: 8px 18px;
  border: 1px solid var(--surface);
  background: rgb(255 255 255 / 0.9);
  text-align: left;
}

.handed-off-row {
  padding: 10px 0;
  border-top: 1px solid var(--border);
  border-left: 3px solid #15803d;
  background: #f0fdf4;
  min-width: 0;
  overflow-wrap: anywhere;
  color: var(--muted);
}

.lane-handed-off .handed-off-row {
  padding: 8px 10px;
  border: 1px solid var(--border);
  background: rgb(255 255 255 / 0.7);
}

/*
 * Stall Staff fulfilment controls, shared by My Stall and All Stalls.
 *
 * These lived in a `<style>` block in each page, on the reasoning that they
 * belong to two surfaces rather than to every role. They never rendered: the
 * server sends `style-src 'self'` with no `unsafe-inline` (`src/server.js`), so
 * the browser refuses an inline block outright and both pages ran with this
 * file as their only stylesheet. The rules are here now because here is where a
 * rule takes effect.
 *
 * What they answer for is one measurement no other surface has to meet: a 44px
 * target held in one hand at 390×844, in noise, in sun.
 */
.fulfilment-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.75rem;
  min-width: 0;
}

.fulfilment-control,
.fulfilment-confirm,
.fulfilment-abandon,
.exceptional-disclose {
  min-height: 44px;
  width: 100%;
  box-sizing: border-box;
  padding: 0.6rem 0.9rem;
  text-align: left;
  white-space: normal;
  overflow-wrap: anywhere;
  line-height: 1.35;
}

.fulfilment-control {
  background: #fffaf5;
  border: 1px solid #e5e7eb;
  color: #111827;
  font: inherit;
  cursor: pointer;
}

.fulfilment-control:hover:not(:disabled) {
  border-color: #fdba74;
}

.fulfilment-control:disabled {
  color: #4b5563;
  cursor: not-allowed;
  opacity: 0.55;
}

/*
 * Cancelling a line and sending food backwards are not the same weight as
 * marking one ready, and the surface says so before the confirmation does.
 */
.cancel-line,
.return-received {
  border-left: 3px solid #b91c1c;
}

.undo-ready {
  border-left: 3px solid #ea580c;
}

.fulfilment-panel {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.5rem;
  padding: 0.75rem;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: #fffaf5;
  min-width: 0;
}

.fulfilment-question,
.fulfilment-reason-label,
.exceptional-name-label,
.exceptional-contact-label {
  margin: 0;
  font-weight: 500;
  color: #111827;
  overflow-wrap: anywhere;
}

.fulfilment-reason,
.exceptional-name,
.exceptional-contact {
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;
  padding: 0.6rem;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  font: inherit;
  color: #111827;
  background: #ffffff;
  resize: vertical;
}

.fulfilment-reason:focus-visible,
.exceptional-name:focus-visible,
.exceptional-contact:focus-visible {
  outline: 2px solid #ea580c;
  outline-offset: 2px;
}

.fulfilment-reason[aria-invalid="true"],
.exceptional-name[aria-invalid="true"],
.exceptional-contact[aria-invalid="true"] {
  border-color: #b91c1c;
}

.fulfilment-hint,
.exceptional-hint {
  margin: 0;
}

/*
 * A refusal is not a toast: it is written next to the field it was made in and
 * it stays there until the operator changes something. `.handoff-error` carries
 * the same duty and is styled above; it keeps the treatment it has been
 * rendering with rather than adopting this one.
 */
.fulfilment-error,
.exceptional-error {
  margin: 0;
  color: #b91c1c;
  overflow-wrap: anywhere;
}

.handoff-exceptional {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px dashed #e5e7eb;
  min-width: 0;
}

.exceptional-disclose {
  background: transparent;
  border: 1px solid #e5e7eb;
  color: #4b5563;
  font: inherit;
  cursor: pointer;
}

.exceptional-disclose[aria-expanded="true"] {
  color: #111827;
  border-color: #fdba74;
}

.exceptional-form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.5rem;
  min-width: 0;
}

/* Toast flags a reopened ticket at the top of the ticket. So does this. */
.recalled-flag {
  margin: 0 0 0.35rem;
  padding: 0.25rem 0.5rem;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: #b91c1c;
  background: #fef2f2;
  border-left: 3px solid #b91c1c;
  overflow-wrap: anywhere;
}

/*
 * The arrival cue's visible half, for My Stall's `.queue-row` and All Stalls'
 * `.stall-order-card` alike. Position and colour rather than an announcement:
 * ADR 0003 point 11 allows one polite atomic live region per Role Workspace,
 * the announcement goes through the `#status` region each page already owns,
 * and this half is a treatment that says nothing to a screen reader at all.
 *
 * It lives here rather than in a per-page `<style>` block because the server
 * sends `style-src 'self'` with no `unsafe-inline`, so an inline block is
 * refused by the browser and the cue silently does not render. Last in the
 * file so the border wins against `.stall-order-card`'s own border shorthand
 * without needing a louder selector.
 */
[data-arrived] {
  border-left: 3px solid #ea580c;
  background: linear-gradient(90deg, #fff7ed, transparent 60%);
}

@media (prefers-reduced-motion: no-preference) {
  @keyframes stall-order-arrived {
    from {
      background-color: #fdba74;
    }
    to {
      background-color: transparent;
    }
  }

  [data-arrived] {
    animation: stall-order-arrived 1.2s ease-out 1;
  }
}

/* ------------------------------------------------------------------ *
 * Registration Desk — Credit history on the Guest record (D4)
 *
 * Shopify holds a balance and its movements together on the customer profile.
 * The transferable part is the pairing: a balance a volunteer can be challenged
 * on needs its movements adjacent, not on another screen.
 *
 * The balance is the largest thing here because it is what a Guest disputes. The
 * movements below it are compact and monospaced so two loads line up digit for
 * digit — a running balance that does not align is a column nobody can check at
 * arm's length (rule 49).
 * ------------------------------------------------------------------ */

.credit-history {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  min-width: 0;
}

.credit-history h3 {
  margin: 0;
}

.record-balance-line {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
}

.record-balance-label {
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.record-balance {
  font-size: clamp(28px, 4vw, 38px);
  font-weight: 400;
  letter-spacing: -0.04em;
  line-height: 1.1;
}

.credit-movements {
  display: flex;
  flex-direction: column;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  min-width: 0;
}

/*
 * One movement per row. The amount leads because a Guest disputing a balance
 * names an amount first; the balance it produced follows, so the column reads
 * as the arithmetic the volunteer is being asked to defend.
 */
.credit-movement {
  display: grid;
  grid-template-columns: minmax(0, auto) minmax(0, 1fr);
  gap: 2px 14px;
  padding: 12px 0;
  border-top: 1px solid var(--border);
  min-width: 0;
}

.credit-movement:first-child {
  border-top: 0;
}

.movement-amount {
  grid-column: 1;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--orange-text);
}

.movement-kind {
  grid-column: 2;
}

.movement-balance {
  grid-column: 1 / -1;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.movement-time {
  grid-column: 1 / -1;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  color: var(--muted);
}

/*
 * The scope note. It is muted but never hidden: this desk cannot read a Guest's
 * spending, so a list that looked complete would be the misleading part.
 */
.credit-history-scope {
  padding-inline-start: 14px;
  border-inline-start: 3px solid var(--peach);
}

/* ------------------------------------------------------------------ *
 * Registration Desk — the review reads back every contact (D5)
 * ------------------------------------------------------------------ */

/*
 * A contact row is a `<div>` inside `.review-detail`, so it already inherits the
 * `display: contents` above that flattens it into the two-column grid. What it
 * adds is the value itself, set in mono: a volunteer reading a phone number or
 * an email back against the person in front of them is comparing characters, and
 * proportional digits are the wrong tool for that.
 */
.review-contact {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.86rem;
  font-variant-numeric: tabular-nums;
}

/* ==================================================================== *
 * V2 route sections (#89)
 *
 * This file is one stylesheet shared by every surface, and the V2 redesign
 * lands one route at a time. Each route owns exactly one section below, in
 * route order, and adds nothing outside it. Two builders working on
 * different routes therefore never append to the same place, and a rule
 * cannot leak: every selector in a section is scoped by that route's own id
 * or route-level class — `#access-route` and `.access-page` below — never by
 * a bare element and never by a class another surface also carries.
 *
 * The scoping is not tidiness. `.status` is shared by all six existing
 * surfaces, and `header`, `main`, `h1`, `h2`, `h3`, `form`, `label`,
 * `fieldset`, `legend`, `input`, `select`, `textarea` and `button` are all
 * styled bare at the top of this file. A new structural element therefore
 * arrives already styled by rules nobody wrote for it, and an unscoped rule
 * added here changes screens its author never opened. Check the bare-element
 * selectors before styling a new element, and override every property they
 * set rather than the one that looked wrong.
 *
 * A section stays empty apart from its marker until its route's ticket
 * lands. Do not move, reorder, merge, or rename the markers.
 * ==================================================================== */

/* ==== V2 route section: /access ==== */

/*
 * Access QR Redemption (#90).
 *
 * The reader is a Guest holding a phone at arm's length in a crowd, one
 * second after pointing a camera at a volunteer's screen. So the route is a
 * waypoint rather than a workspace: one centred card, one sentence, and no
 * controls at all. `main`'s 1280px column and its 70px/100px workspace
 * padding are both wrong here and are both overridden — an id beats the bare
 * `main` rule and the 820px media query that narrows it.
 */
.access-page {
  background:
    linear-gradient(100deg, rgb(255 255 255 / 0.9) 0 32%, transparent 72%),
    #fffaf5;
}

/* The brand keeps its 44px target; only the workspace-sized padding goes. */
.access-page header {
  padding-block: 20px 0;
}

#access-route {
  display: grid;
  align-content: center;
  justify-items: center;
  width: min(100% - (2 * var(--v2-gutter)), 460px);
  min-height: calc(100vh - 180px);
  margin-inline: auto;
  padding-block: 24px 56px;
  text-align: center;
}

.access-card {
  display: grid;
  justify-items: center;
  width: 100%;
  min-width: 0;
}

#access-route .eyebrow {
  margin: 0 0 24px;
}

/*
 * The state mark. It is `aria-hidden`, and every distinction it draws —
 * hue, glyph, and ring style — is already stated in words directly beneath
 * it, so nothing here is the only carrier of a meaning.
 */
.access-mark {
  display: grid;
  place-items: center;
  width: 96px;
  height: 96px;
  margin: 0 0 30px;
  border: 1px solid rgb(234 88 12 / 0.28);
  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 50%,
    rgb(253 186 116 / 0.24),
    rgb(255 255 255 / 0.5)
  );
}

.access-mark-glyph {
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  border: 2px solid var(--orange);
  border-radius: 50%;
  color: var(--orange-text);
  font-size: 26px;
  line-height: 1;
}

/*
 * Loading is a ring with one open quadrant, turning. The global
 * `prefers-reduced-motion: reduce` block earlier in this file cancels every
 * animation with `!important`, so this stops there and the ring simply sits
 * with its gap — the state is still named in the heading either way.
 */
#access-route[data-state="loading"] .access-mark-glyph {
  border-top-color: transparent;
  animation: access-mark-turn 1.1s linear infinite;
}

@keyframes access-mark-turn {
  to {
    transform: rotate(360deg);
  }
}

#access-route[data-state="committed"] .access-mark-glyph::before {
  content: "✓";
}

#access-route[data-state="failure"] .access-mark-glyph::before,
#access-route[data-state="offline"] .access-mark-glyph::before {
  content: "!";
}

#access-route[data-state="failure"] .access-mark,
#access-route[data-state="offline"] .access-mark {
  border-color: rgb(159 18 57 / 0.28);
  background: radial-gradient(
    circle at 50% 50%,
    rgb(225 29 72 / 0.14),
    rgb(255 255 255 / 0.5)
  );
}

#access-route[data-state="failure"] .access-mark-glyph,
#access-route[data-state="offline"] .access-mark-glyph {
  border-color: var(--v2-danger-text);
  color: var(--v2-danger-text);
}

/* Offline is the one state the Guest can clear without walking anywhere, so
   its ring is drawn as provisional rather than settled. */
#access-route[data-state="offline"] .access-mark-glyph {
  border-style: dashed;
}

.access-live {
  display: grid;
  justify-items: center;
  width: 100%;
}

#access-heading {
  margin: 0;
  font-size: clamp(30px, 8.4vw, 40px);
  font-weight: 300;
  line-height: 1.12;
  letter-spacing: -0.045em;
}

#access-status {
  max-width: 34ch;
  margin: 14px auto 0;
  color: var(--muted);
  font-size: 16px;
  line-height: 1.6;
}

/* `.error-text` is defined earlier in this file, so the id above would win
   on specificity and quietly mute a refusal. This restores it. */
#access-status.error-text {
  color: var(--v2-danger-text);
}

.access-help {
  margin: 32px 0 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
}

/* A refusal carries exactly one instruction. Both sentences below already
   name the Registration Desk, so the standing note underneath would be a
   second, weaker copy of the thing the Guest has just been told to do. */
#access-route[data-state="failure"] .access-help,
#access-route[data-state="offline"] .access-help {
  display: none;
}

.access-page a:focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

/* ==== V2 route section: /guest ==== */

.guest-page {
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.96), transparent 32%), #fffaf5;
}

.guest-page .atmosphere {
  inset: -28% -60% auto 58%;
  height: 52vh;
  opacity: 0.48;
}

.guest-page > header {
  width: min(100% - 24px, 680px);
  padding-block: 8px;
  border-bottom: 1px solid var(--v2-panel-border);
}

.guest-page .brand {
  min-height: var(--v2-target);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-transform: none;
}

.guest-page .role {
  font-size: 10px;
}

.guest-page .guest-shell {
  display: grid;
  gap: 12px;
  width: min(100% - 16px, 680px);
  max-width: 680px;
  padding-block: 8px 72px;
}

.guest-page .guest-route-state,
.guest-page .role-sign-in {
  width: min(calc(100% - 24px), 720px);
  margin: 18px auto;
  padding: 24px;
}

.guest-page .guest-route-state[data-state="loading"] {
  border-color: var(--v2-panel-border);
}

.guest-page .guest-route-state[data-state="failure"],
.guest-page .guest-route-state[data-state="expired-session"] {
  border-color: var(--v2-danger-text);
}

.guest-page .guest-shell > .eyebrow,
.guest-page .guest-greeting {
  margin: 0;
}

.guest-page .guest-credit-label {
  margin-top: 4px;
}

.guest-page .guest-greeting {
  font-size: 20px;
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.04em;
}

.guest-page .ready-panel,
.guest-page .undo-panel {
  padding: 14px;
  border: 0;
  border-radius: 0;
  clip-path: polygon(
    10px 0,
    100% 0,
    100% calc(100% - 10px),
    calc(100% - 10px) 100%,
    0 100%,
    0 10px
  );
}

.guest-page .ready-panel {
  padding-bottom: 44px;
  color: white;
  background: var(--orange-text);
}

.guest-page .ready-panel .eyebrow,
.guest-page .ready-total {
  color: #ffedd5;
}

.guest-page .ready-panel h2 {
  font-size: 24px;
  font-weight: 600;
  line-height: 1.1;
}

.guest-page .ready-instruction,
.guest-page .ready-empty {
  color: white;
}

.guest-page .ready-row {
  padding: 10px 12px;
  border-left: 0;
  background-image: linear-gradient(100deg, rgb(154 52 18), rgb(124 45 18));
}

.guest-page .ready-list {
  gap: 6px;
  margin-top: 8px;
}

.guest-page .ready-stall {
  font-size: 15px;
}

.guest-page .ready-figure-label {
  color: white;
  font-size: 12px;
}

.guest-page .ready-figure-value {
  color: white;
  font-size: min(10vw, 36px);
}

.guest-page .balance-panel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr));
  gap: 12px;
  margin-top: 0;
  padding: 12px 14px;
  color: var(--surface);
  border: 1px solid rgb(234 88 12 / 0.22);
  border-radius: var(--v2-radius);
  background: rgb(255 237 229 / 0.9);
}

.guest-page .balance-panel .eyebrow {
  margin: 0 0 4px;
  color: var(--orange-text);
  font-size: 10px;
}

.guest-page #guest-balance {
  margin: 0;
  color: var(--orange-text);
  font-size: 26px;
  font-weight: 650;
  letter-spacing: -0.04em;
}

.guest-page #guest-balance::after {
  content: " Credit";
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
}

.guest-page #event-disclosure {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.35;
}

.guest-page .credit-preview {
  min-width: 0;
  padding-left: 12px;
  border-left: 1px solid rgb(194 65 12 / 0.22);
}

.guest-page #credit-summary {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.guest-page #credit-summary li {
  display: flex;
  gap: 6px;
  justify-content: space-between;
  min-width: 0;
  font-size: 11px;
}

.guest-page #credit-summary span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.guest-page #credit-summary strong {
  flex: 0 0 auto;
  color: var(--orange-text);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 10px;
}

.guest-page .ordering {
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  margin-top: 8px;
}

.guest-page .ordering h2,
.guest-page .basket-panel h2,
.guest-page .order-panel h2 {
  font-size: 22px;
  font-weight: 600;
}

.guest-page .stall-list {
  gap: 8px;
  margin-top: 10px;
  border-top: 0;
}

.guest-page .stall-row {
  grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr));
  gap: 4px 12px;
  padding: 11px 12px;
  border: 1px solid var(--v2-panel-border);
  border-left: 1px solid var(--v2-panel-border);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
}

.guest-page .stall-row h3 {
  font-size: 15px;
  font-weight: 650;
}

.guest-page .capacity {
  color: var(--orange-text);
  font-weight: 700;
}

.guest-page .orders-ahead {
  grid-column: 1 / -1;
  font-size: 11px;
}

.guest-page .orders-ahead.busy {
  color: var(--v2-danger-text);
  font-size: 12px;
}

.guest-page .guest-menu {
  gap: 6px;
  margin-top: 4px;
}

.guest-page .guest-menu li {
  min-height: var(--v2-target);
  padding-top: 6px;
  border-top: 1px solid var(--border);
  font-size: 13px;
}

.guest-page .guest-menu button {
  min-width: 64px;
  min-height: var(--v2-target);
  padding-inline: 12px;
}

.guest-page .basket-panel {
  margin-top: 2px;
  padding: 16px;
  border-radius: var(--v2-radius);
}

.guest-page #basket-lines {
  gap: 12px;
  margin-block: 14px;
}

.guest-page .basket-line {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px 12px;
  padding-bottom: 12px;
}

.guest-page .basket-description,
.guest-page .basket-warning {
  grid-column: 1 / -1;
}

.guest-page .remove-item {
  justify-self: end;
}

.guest-page #basket-total,
.guest-page #basket-status {
  margin-block: 8px;
}

.guest-page .basket-review {
  margin-top: 16px;
  padding: 16px;
  border: 1px solid var(--v2-panel-border);
  border-radius: var(--v2-radius);
  color: var(--surface);
  background: #fff7ed;
  box-shadow: inset 4px 0 0 var(--v2-accent);
}

.guest-page .basket-review .eyebrow {
  color: var(--orange-text);
}

.guest-page .basket-review h3 {
  margin: 4px 0 8px;
  font-size: 20px;
}

.guest-page .review-lines {
  display: grid;
  gap: 8px;
  margin: 14px 0;
  padding: 0;
  list-style: none;
}

.guest-page .review-lines li {
  padding-bottom: 8px;
  border-bottom: 1px solid var(--v2-panel-border);
  font-size: 13px;
}

.guest-page .review-total {
  margin: 12px 0;
  color: var(--orange-text);
  font-family: var(--mono);
  font-weight: 800;
}

.guest-page .review-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.guest-page .review-actions button {
  min-height: var(--v2-target);
  padding-inline: 10px;
}

@media (max-width: 360px) {
  .guest-page .review-actions {
    grid-template-columns: 1fr;
  }
}

.guest-page .order-panel,
.guest-page .credit-tools,
.guest-page .activity-panel {
  margin-top: 8px;
}

.guest-page .order-panel {
  padding: 16px;
}

.guest-page .order-card {
  padding: 14px;
}

.guest-page .credit-tools {
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
}

.guest-page .receive-panel,
.guest-page .transfer-panel,
.guest-page .activity-panel {
  min-width: 0;
  padding: 16px;
  border: 1px solid var(--v2-panel-border);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
  backdrop-filter: none;
}

.guest-page .receive-panel h2,
.guest-page .transfer-panel h2,
.guest-page .activity-panel h2 {
  margin: 4px 0 8px;
  font-size: 22px;
  font-weight: 600;
}

.guest-page .receive-panel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(112px, 100%), 1fr));
  gap: 8px 14px;
  align-items: start;
}

.guest-page .receive-panel > .eyebrow,
.guest-page .receive-panel > h2,
.guest-page .receive-panel > .hint {
  grid-column: 1 / -1;
}

.guest-page .receive-panel .access-qr {
  grid-row: span 3;
  width: 100%;
  max-width: 160px;
  padding: 8px;
}

.guest-page .receive-panel .help,
.guest-page .receive-panel .recipient-code,
.guest-page .receive-panel .outbound-link {
  min-width: 0;
  margin: 0;
}

.guest-page .receive-panel .outbound-link {
  align-self: end;
  overflow-wrap: anywhere;
}

.guest-page .transfer-panel form,
.guest-page #dispute-form {
  gap: 12px;
  margin-top: 14px;
}

.guest-page .transfer-review {
  margin-top: 14px;
  padding: 14px;
  border: 1px solid rgb(234 88 12 / 0.3);
  border-left: 4px solid var(--orange);
  border-radius: var(--v2-radius);
}

.guest-page .transfer-review .form-actions {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, auto);
  gap: 8px;
}

.guest-page .transfer-review button,
.guest-page .transfer-panel form > button,
.guest-page #dispute-form > button {
  min-height: var(--v2-target);
}

.guest-page #dispute-entry-fieldset {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.guest-page #credit-activity {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.guest-page .activity-entry {
  min-width: 0;
  padding: 10px;
  border: 1px solid var(--v2-panel-border);
  border-radius: var(--v2-radius);
  background: #fffaf5;
  font-size: 12px;
  line-height: 1.45;
}

.guest-page .activity-entry-summary {
  overflow-wrap: anywhere;
}

.guest-page .dispute-entry {
  grid-template-columns: var(--v2-target) minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  margin: -10px;
  padding: 10px;
  cursor: pointer;
}

.guest-page .dispute-entry input[type="checkbox"] {
  width: var(--v2-target);
  min-width: var(--v2-target);
  height: var(--v2-target);
  min-height: var(--v2-target);
  margin: 0;
}

.guest-page .dispute-entry-copy {
  display: grid;
  gap: 3px;
  min-width: 0;
  font-weight: 400;
}

.guest-page .dispute-entry-copy strong {
  color: var(--surface);
  overflow-wrap: anywhere;
}

.guest-page .dispute-entry-copy span,
.guest-page .dispute-evidence-claim {
  color: var(--muted);
}

.guest-page .dispute-evidence-status {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 3px 8px;
  border: 1px solid rgb(234 88 12 / 0.34);
  border-radius: 999px;
  color: var(--orange-text);
  background: #ffedd5;
}

.guest-page .dispute-evidence-claim {
  margin: 8px 0 0;
  padding-top: 8px;
  border-top: 1px solid var(--v2-panel-border);
  overflow-wrap: anywhere;
}

.guest-page .dispute-details-label {
  margin: 4px 0 -6px;
}

.guest-page #dispute-issue-type,
.guest-page #dispute-form > button {
  min-height: var(--v2-target);
}

.guest-page #dispute-entry-fieldset[aria-invalid="true"],
.guest-page #dispute-issue-type[aria-invalid="true"],
.guest-page #dispute-claim[aria-invalid="true"] {
  border-color: #b91c1c;
  outline: 2px solid #b91c1c;
  outline-offset: 1px;
}

.guest-page .order-status-summaries {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0;
  padding: 0;
  list-style: none;
}

.guest-page .order-status-summary {
  padding: 6px 9px;
  border: 1px solid var(--v2-panel-border);
  border-radius: 999px;
  color: var(--orange-text);
  background: var(--v2-panel);
  font-size: 11px;
  font-weight: 700;
}

.guest-shell .basket-quantity {
  display: grid;
  grid-template-columns: var(--v2-target) minmax(88px, 1fr) var(--v2-target);
  align-items: center;
  width: min(100%, 220px);
  overflow: hidden;
  border: 1px solid rgb(255 255 255 / 0.28);
  border-radius: var(--v2-radius);
}

.guest-shell .quantity-control {
  display: grid;
  place-items: center;
  width: var(--v2-target);
  min-width: var(--v2-target);
  min-height: var(--v2-target);
  padding: 0;
  color: white;
  background: rgb(255 255 255 / 0.1);
  font-size: 22px;
}

.guest-shell .quantity-control:disabled {
  color: rgb(255 255 255 / 0.45);
  cursor: not-allowed;
}

.guest-shell .basket-quantity-value {
  min-width: 0;
  color: white;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.guest-shell .remove-item {
  min-width: var(--v2-target);
  min-height: var(--v2-target);
}

.guest-shell #basket-total::after {
  content: " Credit";
}

.guest-shell button:focus-visible,
.guest-shell a:focus-visible,
.guest-shell input:focus-visible,
.guest-shell select:focus-visible,
.guest-shell textarea:focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

/*
 * A recovered Guest mutation is more than a semantic lock. Native disabled
 * compositing made restored Transfer and Dispute controls look writable at
 * 390px, so the Guest surface uses an opaque neutral treatment plus a dashed
 * field edge. The shape change keeps the state legible without relying on hue.
 */
.guest-page .guest-shell input:disabled,
.guest-page .guest-shell select:disabled,
.guest-page .guest-shell textarea:disabled {
  opacity: 1;
  color: #374151;
  border-color: #6b7280;
  border-style: dashed;
  background: #e5e7eb;
  cursor: not-allowed;
}

.guest-page .guest-shell input[type="checkbox"]:disabled {
  outline: 2px solid #6b7280;
  outline-offset: 2px;
}

.guest-page .guest-shell button:disabled:not(.quantity-control) {
  opacity: 1;
  color: #4b5563;
  border-color: #9ca3af;
  background: #d1d5db;
  box-shadow: inset 0 0 0 2px #9ca3af;
  cursor: not-allowed;
}

/* Guest feedback is durable beside its form; this one live region announces
   in flow so it cannot cover the evidence at phone width. */
.guest-page #guest-status.status {
  position: static;
  right: auto;
  bottom: auto;
  max-width: none;
  min-height: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
  color: var(--surface);
  border: 0;
  background: transparent;
  box-shadow: none;
  transform: none;
  visibility: hidden;
  transition: none;
}

.guest-page #guest-status.status.visible {
  min-height: var(--v2-target);
  padding: 12px 14px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--v2-accent);
  background: var(--v2-panel);
  visibility: visible;
}

.guest-page #guest-status.status.error {
  color: var(--v2-danger-text);
  border-color: var(--v2-danger-text);
  background: #fff7ed;
}

/* ==== V2 route section: /desk ==== */

.desk-page header {
  flex-wrap: wrap;
}

.desk-page .role-nav {
  min-width: 0;
  justify-content: flex-end;
}

.desk-page .role-nav .role {
  overflow-wrap: anywhere;
}

/* ==== V2 route section: /staff ==== */

/*
 * My Stall's V2 presentation is deliberately route-scoped. The role shell,
 * Action Feedback implementation and fulfilment behaviour stay shared; these
 * rules only arrange the one-stall readiness, capacity, menu and stock duty.
 */
.my-stall-page {
  background:
    linear-gradient(155deg, rgb(255 255 255 / 0.96) 0 46%, transparent 72%),
    radial-gradient(circle at 92% 8%, #fed7aa 0 5%, transparent 28%), #fffaf5;
}

.my-stall-page header,
.my-stall-page main {
  width: min(100% - (2 * var(--v2-gutter)), 760px);
}

.my-stall-page main,
.all-stalls-page main {
  container-type: inline-size;
}

.my-stall-page header {
  align-items: flex-start;
  gap: 16px;
  padding-block: 18px;
  border-bottom: 1px solid var(--v2-panel-border);
}

.my-stall-page .role-nav {
  justify-content: flex-end;
  gap: 4px 14px;
}

.my-stall-page .role-nav .role {
  flex-basis: 100%;
  text-align: right;
}

.my-stall-page main {
  padding-block: 26px 80px;
}

.my-stall-page .intro {
  max-width: 620px;
}

.my-stall-page .intro h1 {
  margin: 8px 0 12px;
  font-size: clamp(42px, 11vw, 68px);
}

.my-stall-page[data-stall-selected] .intro {
  display: none;
}

.my-stall-page .my-stall-workspace {
  gap: 18px;
  margin-top: 18px;
}

.my-stall-page .my-stall-route-state,
.my-stall-page .active-stall-picker,
.my-stall-page .session-ended-notice,
.my-stall-page .event-lock {
  padding: 20px;
  border: 1px solid var(--v2-panel-border);
  border-left: 5px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
  box-shadow: 0 12px 30px rgb(120 53 15 / 0.08);
}

.my-stall-page .my-stall-route-state h2,
.my-stall-page .my-stall-route-state p,
.my-stall-page .session-ended-notice,
.my-stall-page .event-lock h2,
.my-stall-page .event-lock p {
  margin-block: 0 8px;
}

.my-stall-page .my-stall-route-state[data-route-state="offline"],
.my-stall-page .my-stall-route-state[data-route-state="session-expired"] {
  border-left-color: var(--v2-danger-text);
}

.my-stall-page .role-sign-in {
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
}

.my-stall-page .active-stall-picker h2 {
  font-size: clamp(24px, 7vw, 34px);
  line-height: 1.08;
}

.my-stall-page .active-stall-picker .stall-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 10px;
}

.my-stall-page .active-stall-picker .stall-form label {
  grid-column: 1 / -1;
}

.my-stall-page .empty-state {
  margin: 14px 0 0;
  padding: 14px;
  border: 1px dashed var(--muted);
  border-radius: var(--v2-radius);
}

.my-stall-page .stall-panel {
  gap: 18px;
}

.my-stall-page .active-stall {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(112px, 100%), 1fr));
  align-items: center;
  gap: 10px 16px;
  padding: 18px;
  overflow: hidden;
  color: white;
  border-radius: var(--v2-radius);
  background: var(--surface);
  box-shadow: 0 18px 38px rgb(17 24 39 / 0.16);
}

.my-stall-page .active-stall .eyebrow {
  margin: 0 0 4px;
  color: #fdba74;
}

.my-stall-page #active-stall-heading {
  margin: 0;
  color: white;
  font-size: clamp(28px, 8vw, 42px);
  line-height: 1;
  overflow-wrap: anywhere;
}

.my-stall-page #change-stall {
  min-width: var(--v2-target);
  min-height: var(--v2-target);
  padding: 8px 11px;
  color: white;
  border-color: rgb(255 255 255 / 0.55);
  background: transparent;
}

.my-stall-page #capacity-state {
  justify-self: start;
  min-height: 30px;
  padding: 6px 11px;
  color: var(--surface);
  border: 0;
  border-radius: 999px;
  background: #fed7aa;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
}

.my-stall-page #capacity-state::before {
  content: "● ";
}

.my-stall-page .active-stall .queue-counts {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin: 0;
  color: #e5e7eb;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
}

/*
 * Fulfillment is the task Stall Staff came here to do. Keep its two live
 * queues immediately below the immutable stall identity; readiness, Capacity
 * State, menu, and Ingredient Stock remain available below as setup context.
 * Toast's oldest-left rail becomes oldest-top on the phone rather than a
 * horizontal overflow trap.
 */
.my-stall-page .stall-queues {
  gap: 12px;
}

.my-stall-page .queue-heading-row,
.my-stall-page .queue-panel-heading {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 10px;
}

.my-stall-page .queue-heading-row .eyebrow,
.my-stall-page .queue-heading-row h3,
.my-stall-page .queue-panel-heading h4 {
  margin: 0;
}

.my-stall-page .queue-heading-row h3 {
  font-size: clamp(24px, 7vw, 32px);
  line-height: 1;
}

.my-stall-page .queue-order-note,
.my-stall-page .queue-priority {
  margin: 0;
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 10px;
  font-weight: 800;
  line-height: 1.25;
  text-align: right;
  text-transform: uppercase;
}

.my-stall-page .queue-panel {
  padding: 14px;
  border-radius: var(--v2-radius);
  background: rgb(255 255 255 / 0.9);
  box-shadow: 0 8px 22px rgb(120 53 15 / 0.05);
}

.my-stall-page .queue-panel-heading {
  align-items: center;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--v2-panel-border);
}

.my-stall-page .queue-panel-heading h4 {
  font-size: 18px;
}

.my-stall-page .queue-panel:has(#ready-orders) .queue-priority {
  color: var(--orange-text);
}

.my-stall-page .queue-list {
  display: grid;
  gap: 8px;
}

.my-stall-page .queue-row {
  display: grid;
  gap: 5px;
  padding: 11px 12px 12px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--surface);
  border-radius: 6px;
  background: white;
}

.my-stall-page #ready-orders .queue-row {
  border-left-color: var(--orange-text);
  background: #fffaf5;
}

.my-stall-page .queue-number,
.my-stall-page .queue-lines,
.my-stall-page .queue-age {
  margin: 0;
}

.my-stall-page .queue-number {
  color: var(--surface);
  font-size: 15px;
  font-weight: 850;
  line-height: 1.25;
}

.my-stall-page .queue-lines {
  color: var(--surface);
  font-size: 13px;
  line-height: 1.35;
}

.my-stall-page .queue-age {
  font-size: 10px;
  line-height: 1.35;
}

.my-stall-page .queue-empty,
.my-stall-page .handed-off-empty {
  min-height: 44px;
  margin: 0;
  padding: 12px;
  border: 1px dashed var(--v2-panel-border);
  border-radius: 6px;
}

.my-stall-page .fulfilment-actions {
  gap: 6px;
  margin-top: 6px;
}

.my-stall-page .fulfilment-actions:has(.mark-ready):has(.cancel-line) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.my-stall-page
  .fulfilment-actions:has(.mark-ready):has(.cancel-line)
  .mark-ready {
  grid-column: 1 / -1;
  color: white;
  border-color: var(--surface);
  background: var(--surface);
}

.my-stall-page .fulfilment-control,
.my-stall-page .fulfilment-confirm,
.my-stall-page .fulfilment-abandon,
.my-stall-page .exceptional-disclose {
  padding: 8px 10px;
  font-size: 12px;
  line-height: 1.25;
}

.my-stall-page .queue-row .handoff {
  margin-top: 5px;
}

.my-stall-page .handoff-form {
  grid-template-columns: 8ch minmax(0, 1fr);
  gap: 6px 8px;
}

.my-stall-page .handoff-label,
.my-stall-page .handoff-hint,
.my-stall-page .handoff-error {
  grid-column: 1 / -1;
}

.my-stall-page .handoff-form input.stated-pickup-code {
  width: 100%;
  max-width: none;
}

.my-stall-page .handoff-form button.confirm-handoff {
  width: 100%;
  justify-self: stretch;
  padding: 8px 10px;
  font-size: 12px;
}

.my-stall-page .handoff-exceptional {
  margin-top: 6px;
  padding-top: 6px;
}

.my-stall-page .handed-off-row {
  padding: 10px 12px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid #15803d;
  border-radius: 6px;
}

.my-stall-page .readiness,
.my-stall-page .capacity-panel,
.my-stall-page .stall-setup-review {
  min-width: 0;
  padding: 18px;
  border: 1px solid var(--v2-panel-border);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
  box-shadow: 0 10px 26px rgb(120 53 15 / 0.06);
}

.my-stall-page .readiness h3,
.my-stall-page .capacity-panel h3,
.my-stall-page .stall-setup-review h3 {
  margin: 0 0 12px;
  font-size: clamp(22px, 6vw, 30px);
}

.my-stall-page .blocker-list {
  display: grid;
  gap: 8px;
  margin-bottom: 16px;
}

.my-stall-page .blocker {
  margin: 0;
  padding: 12px 14px;
  border: 1px solid #fed7aa;
  border-left: 5px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: #fff7ed;
}

.my-stall-page .blocker::before {
  content: "Needs attention · ";
  font-weight: 800;
}

.my-stall-page .enable-orders-panel {
  margin-top: 16px;
  padding: 16px;
  border-width: 2px;
  border-radius: var(--v2-radius);
}

.my-stall-page .capacity-controls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(76px, 100%), 1fr));
  gap: 6px;
  padding: 5px;
  border: 1px solid var(--v2-panel-border);
  border-radius: calc(var(--v2-radius) + 2px);
  background: #f3f4f6;
}

.my-stall-page .capacity-choice {
  width: 100%;
  min-width: 0;
  min-height: var(--v2-target);
  color: var(--surface);
  border: 2px solid transparent;
  border-radius: var(--v2-radius);
  background: transparent;
  box-shadow: none;
  clip-path: none;
}

.my-stall-page .capacity-choice[aria-pressed="true"] {
  color: var(--surface);
  border-color: var(--surface);
  background: white;
  box-shadow: 0 2px 7px rgb(17 24 39 / 0.15);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.my-stall-page .menu-item-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 5px 14px;
  padding: 14px 0;
}

.my-stall-page .menu-item-name {
  min-width: 0;
  font-size: 17px;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.my-stall-page .menu-item-price {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.my-stall-page .menu-item-availability {
  grid-column: 1 / -1;
  justify-self: start;
  padding: 4px 8px;
  color: var(--orange-text);
  border: 1px solid currentColor;
  border-radius: 999px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
}

.my-stall-page #add-menu-item-effect {
  margin: 12px 0 8px;
  padding-left: 12px;
  border-left: 3px solid var(--orange-text);
}

.my-stall-page .menu-setup details {
  margin-top: 8px;
}

.my-stall-page .menu-setup summary {
  display: flex;
  width: 100%;
  min-height: var(--v2-target);
  padding: 10px 12px;
  border: 1px solid var(--surface);
  border-radius: var(--v2-radius);
  background: white;
}

.my-stall-page .menu-setup form {
  max-width: none;
  border-radius: var(--v2-radius);
}

.my-stall-page .ingredient-stock-card {
  border-radius: var(--v2-radius);
  box-shadow: 0 8px 20px rgb(17 24 39 / 0.06);
}

.my-stall-page .ingredient-stock-card[data-ingredient-status="Out of Stock"] {
  border-left-color: var(--rose);
}

.my-stall-page
  .ingredient-stock-card[data-ingredient-status="Out of Stock"]
  .ingredient-stock-status {
  color: var(--v2-danger-text);
}

.my-stall-page #status.status {
  position: static;
  max-width: none;
  min-height: 0;
  margin: 12px 0 0;
  padding: 0;
  overflow: hidden;
  color: var(--surface);
  border: 0;
  background: transparent;
  box-shadow: none;
  transform: none;
  visibility: hidden;
  transition: none;
}

.my-stall-page #status.status.visible {
  min-height: var(--v2-target);
  padding: 12px 14px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
  visibility: visible;
}

.my-stall-page #status.status.error {
  color: var(--v2-danger-text);
  border-left-color: var(--v2-danger-text);
}

.my-stall-page .action-feedback {
  padding: 14px;
  border-radius: var(--v2-radius);
}

.my-stall-page[data-mutation-state="pending"] .my-stall-workspace::before {
  content: "Saving this My Stall change… all actions are paused.";
  display: block;
  padding: 12px 14px;
  color: var(--surface);
  border: 2px dashed var(--muted);
  border-radius: var(--v2-radius);
  background: #f3f4f6;
  font-weight: 800;
}

.my-stall-page
  :is(
    a[href],
    button,
    input,
    select,
    textarea,
    summary,
    [tabindex]
  ):focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

.my-stall-page :is(input, select, textarea):disabled {
  opacity: 1;
  color: #374151;
  border-color: #6b7280;
  border-style: dashed;
  background: #e5e7eb;
  cursor: not-allowed;
}

.my-stall-page button:disabled {
  opacity: 1;
  color: #4b5563;
  border: 2px dashed #6b7280;
  background: #d1d5db;
  box-shadow: inset 0 0 0 1px #9ca3af;
  cursor: not-allowed;
}

.my-stall-page .role-nav-link[aria-disabled="true"] {
  color: #4b5563;
  border-bottom-style: dashed;
  cursor: not-allowed;
}

@media (max-width: 560px) {
  .my-stall-page header {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
  }

  .my-stall-page .brand {
    align-self: start;
  }

  .my-stall-page .role-nav {
    gap: 2px 12px;
  }

  .my-stall-page .active-stall-picker .stall-form {
    grid-template-columns: minmax(0, 1fr);
  }

  .my-stall-page .active-stall-picker .stall-form label,
  .my-stall-page .active-stall-picker .stall-form button {
    grid-column: 1;
    width: 100%;
  }

  .my-stall-page .active-stall {
    padding: 16px;
  }

  .my-stall-page #change-stall {
    max-width: 96px;
  }

  .my-stall-page .readiness,
  .my-stall-page .capacity-panel,
  .my-stall-page .stall-setup-review {
    padding: 16px;
  }
}

/* ==== V2 route section: /staff/all-stalls ==== */

.all-stalls-page {
  background:
    linear-gradient(160deg, rgb(255 255 255 / 0.96) 0 48%, transparent 74%),
    radial-gradient(circle at 92% 8%, #fed7aa 0 5%, transparent 28%), #fffaf5;
}

.all-stalls-page header,
.all-stalls-page main {
  width: min(100% - (2 * var(--v2-gutter)), 820px);
}

.all-stalls-page header {
  align-items: flex-start;
  gap: 16px;
  padding-block: 18px;
  border-bottom: 1px solid var(--v2-panel-border);
}

.all-stalls-page .role-nav {
  justify-content: flex-end;
  gap: 4px 14px;
}

.all-stalls-page .role-nav .role {
  flex-basis: 100%;
  text-align: right;
}

.all-stalls-page main {
  padding-block: 24px 72px;
}

.all-stalls-page .compact-intro {
  max-width: 650px;
  margin-bottom: 16px;
}

.all-stalls-page .compact-intro h1 {
  margin: 8px 0 10px;
  font-size: clamp(40px, 11vw, 64px);
  line-height: 0.96;
}

.all-stalls-page .compact-intro p:last-child {
  max-width: 55ch;
  margin: 0;
  color: var(--muted);
}

.all-stalls-page[data-stalls-selected] .compact-intro {
  display: none;
}

.all-stalls-page .all-stalls-route-state,
.all-stalls-page .role-sign-in,
.all-stalls-page .session-ended-notice,
.all-stalls-page .event-lock {
  padding: 20px;
  border: 1px solid var(--v2-panel-border);
  border-left: 5px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
  box-shadow: 0 12px 30px rgb(120 53 15 / 0.08);
}

.all-stalls-page .all-stalls-route-state h2,
.all-stalls-page .all-stalls-route-state p,
.all-stalls-page .event-lock h2,
.all-stalls-page .event-lock p {
  margin-block: 0 8px;
}

.all-stalls-page
  .all-stalls-route-state:is(
    [data-route-state="offline"],
    [data-route-state="session-expired"],
    [data-route-state="failure"]
  ) {
  border-left-color: var(--v2-danger-text);
}

.all-stalls-page .all-stalls-workspace {
  gap: 14px;
  margin-top: 14px;
}

.all-stalls-page .monitoring {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr));
  gap: 10px 14px;
  padding: 14px 16px;
  color: white;
  border: 0;
  border-radius: var(--v2-radius);
  background: var(--surface);
  box-shadow: 0 14px 32px rgb(17 24 39 / 0.14);
}

.all-stalls-page .monitoring .eyebrow {
  margin: 0 0 3px;
  color: #fdba74;
}

.all-stalls-page .monitoring-summary {
  color: white;
  font-size: 15px;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.all-stalls-page .monitoring button {
  align-self: center;
  justify-self: end;
  max-width: 100%;
  min-width: var(--v2-target);
  min-height: var(--v2-target);
  padding: 8px 12px;
  color: white;
  border-color: rgb(255 255 255 / 0.55);
  border-radius: var(--v2-radius);
  background: transparent;
}

.all-stalls-page .coverage-overview {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.all-stalls-page .coverage-overview-item {
  margin: 0;
  padding: 8px 10px;
  color: var(--surface);
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--orange-text);
  border-radius: 6px;
  background: var(--v2-panel);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 10px;
  font-weight: 800;
  line-height: 1.35;
}

.all-stalls-page .setup-empty {
  padding: 18px;
  border: 1px dashed var(--muted);
  border-left: 5px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
}

.all-stalls-page .swimlanes {
  gap: 12px;
}

.all-stalls-page .stall-lane {
  display: grid;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--v2-panel-border);
  border-left: 5px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: rgb(255 255 255 / 0.92);
  box-shadow: 0 10px 26px rgb(120 53 15 / 0.07);
}

.all-stalls-page .stall-lane-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 3px 12px;
}

.all-stalls-page .stall-lane-name {
  font-size: clamp(23px, 7vw, 32px);
  line-height: 1;
}

.all-stalls-page .stall-lane-counts {
  margin: 0;
  padding: 5px 8px;
  color: var(--surface);
  border: 1px solid var(--v2-panel-border);
  border-radius: 999px;
  background: #fff7ed;
  font-size: 9px;
  font-weight: 800;
  line-height: 1.2;
  text-align: right;
  text-transform: uppercase;
}

.all-stalls-page .restock-awareness-list {
  grid-column: 1 / -1;
  display: grid;
  gap: 5px;
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}

.all-stalls-page .restock-awareness {
  margin: 0;
  padding: 8px 10px;
  color: #7c2d12;
  border: 1px solid #fdba74;
  border-left: 4px solid var(--orange-text);
  border-radius: 6px;
  background: #fff7ed;
  font-size: 11px;
  font-weight: 800;
  line-height: 1.3;
}

.all-stalls-page .restock-awareness[data-acknowledged="true"] {
  color: var(--muted);
  border-style: dashed;
  border-left-style: solid;
  background: #f9fafb;
}

.all-stalls-page .lane-queue {
  min-width: 0;
  padding: 11px;
  border: 1px solid var(--v2-panel-border);
  border-radius: var(--v2-radius);
  background: rgb(255 255 255 / 0.86);
}

.all-stalls-page .lane-queue + .lane-queue {
  margin-top: 0;
}

.all-stalls-page .lane-queue h3 {
  margin-bottom: 8px;
  font-size: 11px;
}

.all-stalls-page .lane-ready {
  border-left: 3px solid var(--orange-text);
}

.all-stalls-page .lane-list {
  gap: 7px;
}

.all-stalls-page .stall-order-card {
  display: grid;
  gap: 3px;
  padding: 10px 11px 11px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--surface);
  border-radius: 6px;
  background: white;
}

.my-stall-page [data-arrived],
.all-stalls-page [data-arrived] {
  border-left: 3px solid #ea580c;
  background: linear-gradient(90deg, #fff7ed, transparent 60%);
}

.all-stalls-page .lane-ready .stall-order-card {
  border-left-color: var(--orange-text);
  background: #fffaf5;
}

.all-stalls-page .new-order-cue {
  justify-self: start;
  margin: 0 0 2px;
  padding: 3px 7px;
  color: white;
  border-radius: 999px;
  background: var(--surface);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 9px;
  font-weight: 850;
  letter-spacing: 0.06em;
  line-height: 1.35;
  text-transform: uppercase;
}

.all-stalls-page .stall-order-title,
.all-stalls-page .stall-order-lines,
.all-stalls-page .stall-order-age {
  margin: 0;
}

.all-stalls-page .stall-order-title {
  font-size: 15px;
  line-height: 1.25;
}

.all-stalls-page .stall-order-lines {
  color: var(--surface);
  font-size: 13px;
  line-height: 1.3;
}

.all-stalls-page .stall-order-age {
  font-size: 10px;
  line-height: 1.3;
}

.all-stalls-page .lane-empty,
.all-stalls-page .handed-off-empty {
  min-height: var(--v2-target);
  padding: 12px;
  border: 1px dashed var(--v2-panel-border);
  border-radius: 6px;
}

.all-stalls-page .stall-order-actions,
.all-stalls-page .fulfilment-actions {
  gap: 6px;
  margin-top: 5px;
}

.all-stalls-page .fulfilment-actions:has(.mark-ready):has(.cancel-line) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.all-stalls-page
  .fulfilment-actions:has(.mark-ready):has(.cancel-line)
  .mark-ready {
  grid-column: 1 / -1;
  color: white;
  border-color: var(--surface);
  background: var(--surface);
}

.all-stalls-page .fulfilment-control,
.all-stalls-page .fulfilment-confirm,
.all-stalls-page .fulfilment-abandon,
.all-stalls-page .exceptional-disclose,
.all-stalls-page .handoff-form button.confirm-handoff {
  padding: 8px 10px;
  font-size: 12px;
  line-height: 1.25;
}

.all-stalls-page .handoff-form {
  grid-template-columns: 8ch minmax(0, 1fr);
  gap: 6px 8px;
}

.all-stalls-page .handoff-label,
.all-stalls-page .handoff-hint,
.all-stalls-page .handoff-error {
  grid-column: 1 / -1;
}

.all-stalls-page .handoff-form input.stated-pickup-code {
  width: 100%;
  max-width: none;
}

.all-stalls-page .handoff-form button.confirm-handoff {
  width: 100%;
  justify-self: stretch;
}

.all-stalls-page .handoff-exceptional {
  margin-top: 6px;
  padding-top: 6px;
}

.all-stalls-page .duty-note {
  padding: 12px 14px;
  border-left: 3px solid var(--orange-text);
  background: #fff7ed;
}

.all-stalls-page #status.status {
  position: static;
  max-width: none;
  min-height: 0;
  margin: 10px 0 0;
  padding: 0;
  overflow: hidden;
  color: var(--surface);
  border: 0;
  background: transparent;
  box-shadow: none;
  transform: none;
  visibility: hidden;
  transition: none;
}

.all-stalls-page #status.status.visible,
.all-stalls-page #status.status:not(:empty) {
  min-height: var(--v2-target);
  padding: 12px 14px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
  visibility: visible;
}

.all-stalls-page #status.status.error {
  color: var(--v2-danger-text);
  border-left-color: var(--v2-danger-text);
}

.all-stalls-page .action-feedback {
  padding: 12px;
  border-radius: var(--v2-radius);
}

.all-stalls-page .action-feedback-heading,
.all-stalls-page .action-feedback-status {
  margin-block: 0 6px;
}

.all-stalls-page .action-feedback-detail {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: 3px 8px;
  margin: 8px 0;
  font-size: 11px;
  line-height: 1.3;
}

.all-stalls-page .action-feedback-detail dt,
.all-stalls-page .action-feedback-detail dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.all-stalls-page[data-mutation-state="pending"] .all-stalls-workspace::before {
  content: "Checking this All Stalls change… selection, navigation, and queues are paused in this tab.";
  display: block;
  padding: 12px 14px;
  color: var(--surface);
  border: 2px dashed var(--muted);
  border-radius: var(--v2-radius);
  background: #f3f4f6;
  font-weight: 800;
}

.all-stalls-page
  :is(
    a[href],
    button,
    input,
    select,
    textarea,
    summary,
    [tabindex]
  ):focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

.all-stalls-page :is(input, select, textarea):disabled {
  opacity: 1;
  color: #374151;
  border-color: #6b7280;
  border-style: dashed;
  background: #e5e7eb;
  cursor: not-allowed;
}

.all-stalls-page button:disabled {
  opacity: 1;
  color: #4b5563;
  border: 2px dashed #6b7280;
  background: #d1d5db;
  box-shadow: inset 0 0 0 1px #9ca3af;
  cursor: not-allowed;
}

.all-stalls-page .role-nav-link[aria-disabled="true"] {
  color: #4b5563;
  border-bottom-style: dashed;
  cursor: not-allowed;
}

.all-stalls-page .stall-dialog {
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  border-radius: var(--v2-radius);
}

@media (max-width: 560px) {
  .all-stalls-page header {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 10px;
    padding-block: 12px;
  }

  .all-stalls-page .brand {
    align-self: start;
  }

  .all-stalls-page .role-nav {
    gap: 2px 12px;
  }

  .all-stalls-page main {
    padding-block: 14px 52px;
  }

  .all-stalls-page .all-stalls-workspace {
    gap: 8px;
    margin-top: 8px;
  }

  .all-stalls-page .monitoring {
    grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr));
    gap: 8px 10px;
    padding: 10px 12px;
  }

  .all-stalls-page .monitoring .eyebrow {
    display: none;
  }

  .all-stalls-page .monitoring-summary {
    font-size: 13px;
  }

  .all-stalls-page .coverage-overview {
    grid-template-columns: minmax(0, 1fr);
  }

  .all-stalls-page .stall-lane {
    gap: 9px;
    padding: 11px;
  }

  .all-stalls-page .stall-lane-header {
    grid-template-columns: minmax(0, 1fr);
  }

  .all-stalls-page .stall-lane-counts {
    justify-self: start;
    text-align: left;
  }

  .all-stalls-page .fulfilment-actions:has(.mark-ready):has(.cancel-line),
  .all-stalls-page .handoff-form {
    grid-template-columns: minmax(0, 1fr);
  }

  .all-stalls-page
    .fulfilment-actions:has(.mark-ready):has(.cancel-line)
    .mark-ready {
    grid-column: auto;
  }

  .all-stalls-page .fulfilment-control,
  .all-stalls-page .fulfilment-confirm,
  .all-stalls-page .fulfilment-abandon,
  .all-stalls-page .exceptional-disclose,
  .all-stalls-page .handoff-form button.confirm-handoff {
    width: 100%;
  }

  .all-stalls-page .handoff-form input.stated-pickup-code {
    width: 100%;
    max-width: none;
  }

  .all-stalls-page[data-mutation-state="pending"]
    .all-stalls-workspace::before {
    content: "Checking result… this tab's selection, navigation, and queues are paused.";
    padding: 9px 11px;
    font-size: 12px;
  }
}

@container (max-width: 220px) {
  .my-stall-page #status:has(~ #my-stall-workspace),
  .all-stalls-page #status:has(~ #all-stalls-workspace) {
    position: static;
  }
}

/* ==== V2 route section: /overseer ==== */

/*
 * Operations is a glanceable phone lane: exceptions first, two dominant live
 * counts, then the complete Capacity State denominator and compact stall rows.
 * Every selector is route-scoped so Settings keeps its administrative rhythm.
 */
.operations-page header,
.operations-page main {
  width: min(calc(100% - 32px), 720px);
  max-width: 720px;
}

.operations-page header {
  gap: 16px;
  padding-block: 14px;
  border-bottom: 1px solid var(--v2-panel-border);
}

.operations-page .brand {
  flex: 0 0 auto;
  font-size: 15px;
}

.operations-page .role-nav {
  justify-content: flex-end;
  gap: 4px 12px;
}

.operations-page .role-nav-link,
.operations-page .role-nav .text-button {
  min-height: var(--v2-target);
  font-size: 13px;
}

.operations-page
  :is(input, select, textarea, button, a[href], summary):focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

.operations-page .clipped:focus-visible {
  box-shadow: inset 0 0 0 3px var(--orange-text);
}

.operations-page main {
  padding-block: 18px 64px;
}

.operations-page .intro {
  max-width: 590px;
}

.operations-page .intro h1 {
  margin: 8px 0;
  font-size: clamp(2.25rem, 11vw, 4rem);
  line-height: 0.94;
}

.operations-page .intro > p:last-child {
  margin: 0;
  font-size: 14px;
  line-height: 1.45;
}

.operations-route-state {
  margin-top: 16px;
  padding: 16px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
}

.operations-route-state h2,
.operations-route-state p {
  margin: 0;
}

.operations-route-state h2 {
  margin-top: 4px;
  font-size: 1.1rem;
}

.operations-route-state p:last-child {
  margin-top: 5px;
  color: var(--muted);
  font-size: 13px;
}

.operations-route-state[data-route-state="offline"],
.operations-route-state[data-route-state="session-expired"] {
  border-left-color: var(--v2-danger-text);
}

.operations-page .connectivity-status {
  margin-top: 12px;
}

.operations-page .role-sign-in :disabled {
  cursor: not-allowed;
  opacity: 0.48;
}

.operations-page #status.status {
  position: static;
  max-width: none;
  min-height: 0;
  margin: 12px 0 0;
  padding: 0;
  overflow: hidden;
  color: var(--surface);
  border: 0;
  background: transparent;
  box-shadow: none;
  transform: none;
  visibility: hidden;
  transition: none;
}

.operations-page #status.status.visible,
.operations-page #status.status:not(:empty) {
  min-height: var(--v2-target);
  padding: 11px 13px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
  visibility: visible;
}

.operations-page #status.status.error {
  color: var(--v2-danger-text);
  border-left-color: var(--v2-danger-text);
}

/* Routine announcements remain available to assistive technology without
 * displacing live metrics. Action Feedback is the durable visible record. */
.operations-page #status.status.visible:not(.error),
.operations-page:has(
    #operations-route-state[data-route-state="no-open-event"]:not([hidden])
  )
  #status.status,
.operations-page:has(#operations-session-ended:not([hidden])) #status.status,
.operations-page:has(.operations-offline) .connectivity-status {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.operations-page .overseer-workspace {
  gap: 28px;
  margin-top: 18px;
}

.operations-page .operations-offline > * {
  display: none;
}

.operations-page .operations-section-heading .eyebrow,
.operations-page .operations-section-heading h2 {
  margin: 0;
}

.operations-page .operations-section-heading h2 {
  margin-top: 3px;
  font-size: 1.35rem;
  letter-spacing: -0.025em;
}

.operations-page .exception-list,
.operations-page .stall-health-list {
  margin-top: 10px;
}

.operations-page .exception {
  margin-bottom: 8px;
  padding: 12px 14px;
  border: 1px solid var(--v2-panel-border);
  border-left: 4px solid var(--orange-text);
  border-radius: var(--v2-radius);
  background: var(--v2-panel);
}

.operations-page .exception.empty {
  border-left-color: #15803d;
  color: var(--surface);
}

.operations-page .exception-summary {
  margin-bottom: 2px;
  font-size: 14px;
}

.operations-page .exception .hint {
  margin: 0;
  font-size: 12px;
  line-height: 1.4;
}

.operations-page .health-totals {
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1px;
  margin-top: 10px;
  border-radius: var(--v2-radius);
  overflow: hidden;
}

.operations-page .health-totals > div {
  grid-column: span 2;
  padding: 11px 10px;
}

.operations-page .health-totals > .primary-total {
  grid-column: span 3;
  padding: 15px 14px;
}

.operations-page .health-totals dt {
  font-size: 0.61rem;
}

.operations-page .health-totals dd {
  margin-top: 3px;
  font-size: 1.25rem;
  font-weight: 650;
}

.operations-page .health-totals .primary-total dd:not(.total-share) {
  font-size: 2.8rem;
  font-weight: 320;
  line-height: 1;
}

.operations-page .health-totals .total-share {
  font-size: 0.62rem;
  line-height: 1.3;
}

.operations-page .health-basis,
.operations-page .stall-health > .hint {
  margin: 8px 0 0;
  font-size: 12px;
  line-height: 1.45;
}

.operations-page .stall-health-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 5px 12px;
  padding: 13px 0;
}

.operations-page .stall-health-row h3,
.operations-page .stall-health-row .queue-counts,
.operations-page .stall-health-row .stall-comparison {
  margin: 0;
}

.operations-page .stall-health-row .event-state {
  align-self: start;
  min-height: 30px;
  padding: 6px 10px;
  font-size: 11px;
}

.operations-page .stall-health-row .queue-counts,
.operations-page .stall-health-row .stall-comparison,
.operations-page .pause-exception,
.operations-page .paused-note {
  grid-column: 1 / -1;
}

.operations-page .stall-health-row .queue-counts {
  font-size: 13px;
}

.operations-page .stall-health-row .stall-comparison {
  padding-left: 8px;
  font-size: 11px;
  line-height: 1.4;
}

.operations-page .pause-exception {
  gap: 7px;
  margin-top: 6px;
}

.operations-page .pause-label {
  font-size: 13px;
}

.operations-page .pause-exception input {
  min-height: var(--v2-target);
  margin-top: 5px;
}

.operations-page .pause-requirement {
  font-size: 11px;
  line-height: 1.4;
}

.operations-page .pause-stall {
  min-height: var(--v2-target);
  padding-inline: 16px;
  font-size: 13px;
}

.operations-page .paused-note {
  margin: 0;
  font-size: 12px;
}

.operations-page .settings-outbound {
  margin: 0;
  padding-top: 16px;
  border-top: 1px solid var(--v2-panel-border);
  color: var(--muted);
  font-size: 13px;
}

.operations-page .settings-outbound a {
  display: inline-flex;
  align-items: center;
  min-height: var(--v2-target);
}

@media (max-width: 560px) {
  .operations-page header {
    align-items: start;
  }

  .operations-page .role-nav .role {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }

  .operations-page .role-nav {
    gap: 3px 10px;
  }

  .operations-page .role-nav-link,
  .operations-page .role-nav .text-button {
    font-size: 12px;
  }
}

/* ==== V2 route section: /overseer/settings ==== */

/*
 * Settings is the quiet administrative counterpart to Operations: the same
 * warm paper and clipped geometry, with denser evidence modules and no live
 * health dashboard treatment.
 */
.settings-page header,
.settings-page main {
  width: min(calc(100% - 32px), 720px);
  max-width: 720px;
}

.settings-page header {
  flex-wrap: wrap;
  padding-block: 20px;
}

.settings-page main {
  container-type: inline-size;
  padding-bottom: 72px;
}

.settings-page .intro {
  padding-block: 42px 20px;
}

.settings-page .intro h1 {
  max-width: none;
  margin-bottom: 12px;
  font-size: clamp(2.7rem, 13vw, 4.8rem);
  line-height: 0.92;
}

.settings-page .intro > p:last-child {
  max-width: 58ch;
  margin-bottom: 0;
}

.settings-page .settings-route-state {
  margin-top: 20px;
  padding: 24px;
  border: 1px solid var(--border);
  border-inline-start: 4px solid var(--orange);
  background: rgb(255 253 251 / 0.9);
  clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 0 100%);
}

.settings-page .settings-route-state h2,
.settings-page .settings-route-state p {
  margin-bottom: 8px;
}

.settings-page .settings-route-state p:last-child {
  margin-bottom: 0;
  color: var(--muted);
}

.settings-page .session-ended-notice {
  margin: 0 0 16px;
  padding: 12px 14px;
  border-inline-start: 3px solid var(--rose);
  background: #fff5f7;
}

.settings-page .overseer-settings {
  gap: 14px;
  margin-top: 28px;
}

.settings-page .settings-module {
  position: relative;
  min-width: 0;
  padding: clamp(20px, 5vw, 30px);
  border-color: #ded7ce;
  background: rgb(255 253 251 / 0.94);
  clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 0 100%);
}

.settings-page .settings-module::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--orange);
}

.settings-page .settings-module h2,
.settings-page .settings-module h3,
.settings-page .settings-module p {
  overflow-wrap: anywhere;
}

.settings-page .settings-module > h2,
.settings-page .module-heading h2 {
  margin: 0;
  font-size: clamp(1.65rem, 7vw, 2.2rem);
}

.settings-page .settings-module > .hint,
.settings-page .module-heading + .hint {
  margin: 10px 0 0;
  max-width: 60ch;
  font-size: 0.86rem;
  line-height: 1.55;
}

.settings-page .module-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.settings-page .module-heading .eyebrow {
  margin-bottom: 5px;
}

.settings-page .settings-state {
  display: inline-flex;
  align-items: center;
  min-height: 30px;
  padding: 5px 10px;
  border: 1px solid var(--border);
  background: #f7f2eb;
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.settings-page .credential-list,
.settings-page .report-list,
.settings-page .correction-list,
.settings-page .dispute-list {
  margin-top: 16px;
}

.settings-page .credential-row {
  padding: 0;
  border-top: 0;
}

.settings-page .credential-details {
  border-top: 1px solid var(--border);
}

.settings-page .credential-details > summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
  padding: 10px 0;
  cursor: pointer;
  list-style: none;
}

.settings-page .credential-role,
.settings-page .credential-details .credential-rotated {
  min-width: 0;
  overflow-wrap: anywhere;
}

.settings-page .credential-details > summary::-webkit-details-marker {
  display: none;
}

.settings-page .credential-details > summary::after {
  content: "+";
  flex: 0 0 auto;
  color: var(--orange-text);
  font-size: 1.25rem;
}

.settings-page .credential-details[open] > summary::after {
  content: "−";
}

.settings-page .credential-details .credential-rotated {
  margin: 0 0 0 auto;
  font-size: 0.72rem;
  text-align: right;
}

.settings-page .credential-details .credential-form {
  padding: 4px 0 16px;
}

.settings-page .credential-form {
  display: grid;
  gap: 10px;
}

.settings-page .credential-form .hint,
.settings-page .credential-radius {
  margin: 0;
}

.settings-page .credential-form button,
.settings-page .boards-module button,
.settings-page .dispute-form button {
  width: 100%;
  min-height: 44px;
}

.settings-page .board-list {
  display: grid;
  gap: 12px;
  margin-top: 16px;
}

.settings-page .board-row {
  min-width: 0;
  margin: 0;
  padding: 16px;
  border: 1px solid var(--border);
  background: #fffdfb;
}

.settings-page .board-row legend {
  padding-inline: 6px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.settings-page .board-row .stall-choices {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 4px 10px;
  margin-top: 10px;
}

.settings-page .board-link {
  margin-top: 8px;
  color: var(--orange-text);
}

.settings-page .form-actions {
  margin-top: 14px;
}

.settings-page .report-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.settings-page .report-list li {
  min-width: 0;
  padding: 0;
}

.settings-page .report-link {
  width: 100%;
  min-height: 48px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  background: #fffdfb;
  font-size: 0.78rem;
  line-height: 1.3;
  text-decoration: none;
}

.settings-page .report-link::after {
  content: "↓";
  margin-left: auto;
  padding-left: 8px;
  font-size: 1rem;
}

.settings-page .correction-list,
.settings-page .dispute-list {
  max-height: 390px;
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

.settings-page .correction-row {
  margin: 0;
  padding: 13px 14px;
  border-block-start: 1px solid var(--border);
  border-inline-start: 3px solid var(--orange);
  background: #fffdfb;
}

.settings-page .correction-summary,
.settings-page .correction-row .hint {
  margin: 0;
}

.settings-page .correction-summary {
  font-size: 0.87rem;
  font-weight: 650;
}

.settings-page .correction-row .hint {
  margin-top: 4px;
  font-size: 0.76rem;
}

.settings-page .reconciliation-grid {
  display: grid;
  gap: 22px;
  margin-top: 20px;
}

.settings-page .reconciliation-grid > .reconciliation-details {
  padding: 16px;
  border: 1px solid var(--border);
  background: #fffdfb;
}

.settings-page .reconciliation-details > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px;
  cursor: pointer;
  list-style: none;
}

.settings-page .reconciliation-details > summary::-webkit-details-marker {
  display: none;
}

.settings-page .reconciliation-details > summary span {
  color: var(--orange-text);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.settings-page .reconciliation-grid h3 {
  margin: 0;
  font-size: 1.08rem;
}

.settings-page .reconciliation-grid .hint {
  margin: 8px 0 14px;
  font-size: 0.76rem;
}

.settings-page .settings-reconciliation {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 6px 14px;
  margin: 0;
  font-size: 0.82rem;
}

.settings-page .settings-reconciliation dt {
  color: var(--muted);
}

.settings-page .settings-reconciliation dd {
  margin: 0;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.76rem;
  text-align: right;
}

.settings-page .tender-review-fields {
  display: grid;
  gap: 10px;
  margin: 14px 0;
}

.settings-page .tender-review-fields label {
  margin: 0;
}

.settings-page .reconciliation-reviewed {
  min-height: 44px;
  margin-top: 14px;
  padding: 10px 12px;
  border-inline-start: 3px solid var(--orange);
  background: #fffaf5;
  font-size: 0.8rem;
  line-height: 1.4;
}

.settings-page .event-close-flow > summary[aria-disabled="true"] {
  cursor: not-allowed;
  background: rgb(255 255 255 / 0.5);
}

.settings-page #event-close-review-state {
  color: #9f1239;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.settings-page
  .event-close-flow
  > summary[aria-disabled="false"]
  #event-close-review-state {
  color: var(--orange-text);
}

.settings-page .dispute-row {
  padding: 16px;
  border-block-start: 1px solid var(--border);
  background: #fffdfb;
}

.settings-page .dispute-row:focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: -3px;
}

.settings-page
  :is(input, select, textarea, button, a[href], summary):focus-visible {
  outline: var(--v2-focus-ring);
  outline-offset: var(--v2-focus-offset);
}

.settings-page .dispute-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.settings-page .dispute-heading h3,
.settings-page .dispute-claim,
.settings-page .dispute-guest,
.settings-page .dispute-resolution-reason {
  margin: 0;
}

.settings-page .dispute-heading h3 {
  flex: 1;
  min-width: 0;
}

.settings-page .dispute-status {
  flex: 0 1 62%;
  max-width: 62%;
  padding: 4px 8px;
  border: 1px solid var(--border);
  background: #f7f2eb;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.66rem;
  line-height: 1.35;
  text-align: right;
}

.settings-page .dispute-claim {
  margin-top: 8px;
  font-weight: 600;
}

.settings-page .dispute-guest {
  margin-top: 4px;
  font-size: 0.74rem;
}

.settings-page .dispute-links {
  margin: 10px 0 0;
  padding-left: 18px;
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.7rem;
}

.settings-page .dispute-form {
  display: grid;
  gap: 10px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.settings-page .dispute-form textarea {
  min-height: 78px;
  resize: vertical;
}

.settings-page .dispute-resolution-reason {
  margin-top: 12px;
  padding: 10px 12px;
  border-inline-start: 3px solid var(--orange);
  background: #f7f2eb;
}

.settings-page .event-close-flow {
  overflow: hidden;
  border: 1px solid var(--rose);
  background: #fff5f7;
  clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 0 100%);
}

.settings-page .event-close-flow > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  min-height: 76px;
  padding: 18px 20px;
  cursor: pointer;
  list-style: none;
}

.settings-page .event-close-flow > summary::-webkit-details-marker {
  display: none;
}

.settings-page .event-close-flow > summary > span:first-child {
  display: grid;
  gap: 4px;
}

.settings-page .event-close-flow summary small {
  color: #9f1239;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 0.65rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.settings-page .event-close-flow summary strong {
  font-size: 1.15rem;
}

.settings-page .event-close-flow summary span span {
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.4;
}

.settings-page .event-close-flow[open] > summary > span:last-child {
  transform: rotate(90deg);
}

.settings-page .event-close-flow .panel.guarded {
  border: 0;
  border-top: 1px solid var(--rose);
  border-inline-start: 4px solid var(--rose);
}

.settings-page .settings-offline .credential-list,
.settings-page .settings-offline .board-list,
.settings-page .settings-offline .report-list,
.settings-page .settings-offline .correction-list,
.settings-page .settings-offline .reconciliation-grid,
.settings-page .settings-offline .dispute-list,
.settings-page .settings-offline .event-close-flow {
  visibility: hidden;
}

@media (min-width: 620px) {
  .settings-page .credential-form {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
  }

  .settings-page .credential-form > :not(label):not(button) {
    grid-column: 1 / -1;
  }

  .settings-page .credential-form button {
    width: auto;
  }

  .settings-page .reconciliation-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 430px) {
  .settings-page header,
  .settings-page main {
    width: min(calc(100% - 24px), 720px);
  }

  .settings-page header {
    align-items: flex-start;
    gap: 10px;
  }

  .settings-page .role-nav {
    min-width: 0;
    justify-content: flex-end;
    gap: 8px;
  }

  .settings-page .role-nav .role {
    flex-basis: 100%;
    text-align: right;
  }

  .settings-page .panel.guarded {
    padding: 20px 16px;
  }
}

@container (max-width: 220px) {
  .settings-page #status.status {
    position: static;
    right: auto;
    bottom: auto;
    max-width: 100%;
    margin: 0 0 16px;
    transform: none;
  }

  .settings-page #status.status:not(.visible) {
    margin: 0;
    padding: 0;
  }
}

/* ==== V2 route section: /board ==== */
