:root {
  /* Operator till chrome — dark/high-contrast by design, not a brand
     surface. --accent is the one thing branding.js retunes per tenant —
     as of 2026-09-27 it's driven by color_accent_dark_ground (falling
     back to color_secondary), not color_secondary directly, since a
     light-ground CTA colour doesn't always pass contrast on this dark
     chrome. This static value is just the pre-JS-paint fallback and
     matches Branding::PLATFORM_DEFAULT's color_accent_dark_ground
     (Epos One mint), same as the --pos-* tokens below match its other
     fields. */
  --bg: #101216;
  --panel: #1b1e25;
  --panel-raised: #22262f;
  --accent: #63C79B;
  --text: #f2f2f2;
  --muted: #8a8f98;
  --good: #3ecf72;
  --bad: #ff5c5c;
  --line: #2a2e37;

  /* Brand tokens — defaults are the Epos One platform palette (see
     Branding::PLATFORM_DEFAULT), overridden per-reseller at runtime by
     src/branding.js. These are only the pre-JS-paint fallback; Aster
     IT's own palette now lives entirely in its reseller_branding row. */
  --pos-color-primary: #13201B;
  --pos-color-secondary: #0B6B4F;
  --pos-color-tertiary: #63C79B;
  --pos-color-quaternary: #C9A15B;
  --pos-bg-page: #EFEBE2;
  --pos-bg-surface: #FFFFFF;
  --pos-bg-surface-alt: #FDFCF9;
  --pos-bg-hover: #E7F1EC;
  --pos-border-color: #E2DED2;
  --pos-font-color-primary: #13201B;
  --pos-font-color-secondary: #4A5A52;
  --pos-font-color-link: #0B6B4F;
  --pos-font-color-headings: #13201B;
  --pos-selection-color: #0B6B4F;
  --pos-button-radius: 5px;
  --pos-font-family: 'Poppins', sans-serif;
  --pos-font-size: 18px;
  --pos-header-bg: #EFEBE2;
  --pos-color-success: #147A52;
  /* Text on primary CTA buttons (e.g. the accent-coloured Pay button) —
     white by default because pine (#0B6B4F) is dark enough that white
     passes WCAG AA here (~6.5:1), unlike Aster IT's mid-tone orange
     which needed near-black instead. Never hardcode white/
     --pos-bg-surface as CTA text colour; use this token so a reseller
     with a different (lighter or darker) accent still gets correct
     contrast by overriding just this one field. */
  --pos-cta-text-color: #FFFFFF;

  font-size: 18px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  height: 100vh;
  overflow: hidden;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.screen { height: 100vh; display: flex; flex-direction: column; }
.hidden { display: none !important; }

.btn {
  border: none;
  border-radius: 10px;
  padding: 0.9rem 1.4rem;
  font-size: 1rem;
  background: var(--panel-raised);
  color: var(--text);
  cursor: pointer;
  transition: transform 0.08s ease, filter 0.15s ease, opacity 0.15s ease;
}
.btn:active { transform: scale(0.97); filter: brightness(0.92); }
.btn-primary { background: var(--accent); color: #1c1200; font-weight: 700; box-shadow: 0 4px 14px rgba(255, 122, 48, 0.35); }
.btn-ghost { background: transparent; border: 1px solid #3a3f4a; box-shadow: none; }
.btn-large { font-size: 1.25rem; padding: 1.1rem; }
/* Customer/setup-facing screens carry the resolved brand look; the
   operator till (below) deliberately stays on the dark chrome instead.
   #screen-idle is the one exception — the self-checkout attract screen is
   deliberately dark (see its own rules further down), matching the
   design handoff's idle/attract screen rather than the light SCO look. */
#screen-pairing, #screen-self-shop, #screen-self-done, #screen-phone-claim,
#screen-self-customer, #screen-self-giftcard, #screen-self-loyalty {
  background: var(--pos-bg-page);
  color: var(--pos-font-color-primary);
  font-family: var(--pos-font-family);
  font-size: var(--pos-font-size);
}
#screen-pairing h1, #screen-self-shop h1, #screen-self-done h1, #screen-phone-claim h1,
#screen-self-customer h1, #screen-self-giftcard h1, #screen-self-loyalty h1 {
  color: var(--pos-font-color-headings);
  font-weight: 600;
}

.brand-logo {
  max-width: 220px;
  max-height: 80px;
  margin: 0 auto 1.5rem;
  display: block;
}

.pairing-box, .idle-box {
  margin: auto;
  text-align: center;
  max-width: 420px;
  padding: 2rem;
}
.pairing-box input {
  width: 100%;
  font-size: 1.5rem;
  text-align: center;
  padding: 0.8rem;
  border-radius: 10px;
  border: 1px solid #3a3f4a;
  background: var(--panel);
  color: var(--text);
  margin: 1rem 0;
}
.error { color: var(--bad); min-height: 1.2rem; font-size: 0.95rem; }

/* Hardware peripheral marketplace (2026-10-06, roadmap V3) — the
   till-side pairing panel (ui/peripherals-panel.js), opened from
   screen-till's/screen-kitchen-display's own "Peripherals" header
   button. One row per configured peripheral, each with its own live
   paired/not-paired status for THIS browser (see printer.js's own
   header comment on why that status can only ever be read here, not
   stored server-side). */
.peripherals-list { text-align: left; margin: 1rem 0; }
.peripheral-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid #3a3f4a;
}
.peripheral-row:last-child { border-bottom: none; }
.peripheral-row-label { font-weight: 600; }
.peripheral-row-kind { font-size: 0.85rem; color: #9a9a9a; }
.peripheral-status { font-size: 0.85rem; padding: 0.2rem 0.6rem; border-radius: 999px; }
.peripheral-status-paired { background: rgba(76, 175, 80, 0.2); color: #4caf50; }
.peripheral-status-unpaired { background: rgba(255, 138, 101, 0.2); color: #ff8a65; }
.peripheral-status-unsupported { background: rgba(154, 154, 154, 0.2); color: #9a9a9a; }

/* --- Self-checkout idle/attract screen: dark "attract mode" per the
   design handoff — stacked lockup, tagline, a bold "Touch to start"
   invite with a gentle pulse, language chips, and a footer bar. Fixed
   dark palette rather than the reseller's light bg_page/bg_surface
   tokens (same convention as the operator till's chrome staying dark
   regardless of brand) — only the accent colour ties into branding. */
#screen-idle {
  cursor: pointer;
  background: #0B0B0C;
  color: #F2F2F2;
  font-family: var(--pos-font-family);
  font-size: var(--pos-font-size);
  display: flex;
  flex-direction: column;
}
#screen-idle .sco-idle-content {
  flex: 1;
  margin: auto;
  text-align: center;
  max-width: 640px;
  padding: 2rem;
  animation: idle-pulse 2.4s ease-in-out infinite;
}
#screen-idle .sco-idle-logo { max-width: 220px; max-height: 220px; margin-bottom: 1.5rem; }
#screen-idle .sco-idle-tagline {
  margin: 0 0 1.4rem;
  text-transform: uppercase;
  letter-spacing: 0.3rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: #9a9a9a;
}
#screen-idle .sco-idle-rule {
  width: 160px;
  border: none;
  border-top: 1px solid #3a3a3a;
  margin: 0 auto 2rem;
}
#screen-idle h1 {
  font-size: 3rem;
  font-weight: 700;
  margin: 0 0 0.5rem;
  color: #FFFFFF;
}
#screen-idle .sco-idle-subtext {
  margin: 0 0 2rem;
  font-size: 1.15rem;
  color: #b7b7b7;
}
#screen-idle .sco-idle-languages {
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  flex-wrap: wrap;
}
#screen-idle .sco-lang-chip {
  padding: 0.7rem 1.4rem;
  border-radius: var(--pos-button-radius);
  border: 1px solid #4a4a4a;
  background: transparent;
  color: #F2F2F2;
  font-weight: 600;
  font-family: inherit;
  font-size: 0.95rem;
  cursor: pointer;
}
#screen-idle .sco-lang-chip.active { border-color: #F2F2F2; }
#screen-idle .sco-idle-phone-link {
  display: block;
  margin: 1.8rem auto 0;
  background: transparent;
  border: none;
  color: #b7b7b7;
  font-family: inherit;
  font-size: 0.95rem;
  text-decoration: underline;
  cursor: pointer;
  animation: none; /* sits below the pulsing content, shouldn't pulse with it */
}
#screen-idle .sco-idle-footer {
  display: flex;
  justify-content: space-between;
  padding: 1.2rem 2rem;
  border-top: 1px solid #232323;
  color: #9a9a9a;
  font-size: 0.95rem;
  font-weight: 600;
}
@keyframes idle-pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.015); opacity: 0.92; }
}
.pin-display {
  font-size: 2.2rem;
  letter-spacing: 0.7rem;
  min-height: 2.6rem;
  margin: 1rem 0;
  font-weight: 600;
}
.pin-pad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.7rem;
}
.pin-key {
  font-size: 1.5rem;
  aspect-ratio: 1;
  border-radius: 999px;
  border: none;
  background: var(--panel-raised);
  color: var(--text);
  transition: transform 0.08s ease, background 0.15s ease;
}
.pin-key:active { transform: scale(0.93); background: var(--accent); color: #1c1200; }

.discount-key {
  font-size: 1.4rem;
  font-weight: 600;
  aspect-ratio: 1;
  border-radius: 14px;
  border: none;
  background: var(--panel-raised);
  color: var(--text);
  transition: transform 0.08s ease, background 0.15s ease;
}
.discount-key:active { transform: scale(0.93); background: var(--accent); color: #1c1200; }
.discount-type-toggle {
  display: flex;
  gap: 0.6rem;
  justify-content: center;
  margin-bottom: 0.4rem;
}

.till-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 1.2rem;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 2px 8px rgba(0,0,0,0.2);
  z-index: 1;
}
.till-site-label { font-weight: 700; letter-spacing: 0.01em; }
.staff-label { color: var(--muted); }
.sync-status { color: var(--good); margin-left: auto; font-size: 0.8em; }
.sync-status.offline { color: var(--bad); }
.till-header .btn { position: relative; }
.sco-header-logo { max-width: 160px; max-height: 44px; }
.staff-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 600;
}
.staff-pill-avatar {
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 50%;
  background: var(--accent);
  color: #1c1200;
  font-size: 0.75rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.badge {
  position: absolute;
  top: -6px; right: -6px;
  background: var(--accent);
  color: #1c1200;
  font-size: 0.7rem;
  font-weight: 700;
  border-radius: 999px;
  min-width: 1.2rem;
  height: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 0.3rem;
  box-shadow: 0 0 0 2px var(--panel);
}

.till-main { flex: 1; display: flex; overflow: hidden; }
.catalog-pane { flex: 3; display: flex; flex-direction: column; overflow: hidden; position: relative; }
.cart-pane { flex: 2; background: var(--panel); display: flex; flex-direction: column; border-left: 1px solid var(--line); }

.category-tabs { display: flex; gap: 0.5rem; padding: 0.9rem 0.9rem 0.6rem; overflow-x: auto; }
.category-tabs button {
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  border: 1px solid #3a3f4a;
  background: transparent;
  color: var(--text);
  white-space: nowrap;
  font-size: 0.92rem;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.category-tabs button.active { background: var(--accent); color: #1c1200; border-color: var(--accent); font-weight: 600; }

.product-grid {
  flex: 1;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.9rem;
  padding: 0.4rem 0.9rem 0.9rem;
  align-content: start;
}
.product-tile {
  background: var(--panel-raised);
  border-radius: 14px;
  padding: 0.7rem 0.8rem 0.9rem;
  text-align: left;
  border: 1px solid var(--line);
  color: var(--text);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
  transition: transform 0.08s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.product-tile:active { transform: scale(0.97); }
.product-tile .name { font-weight: 600; display: block; margin: 0.15rem 0 0.25rem; line-height: 1.25; }
.product-tile .price { color: var(--muted); font-variant-numeric: tabular-nums; }
.product-tile.out-of-stock { opacity: 0.4; }
.product-tile.low-stock { border-color: #d97706; box-shadow: 0 0 0 1px rgba(217,119,6,0.3); }
.product-tile .stock-flag { display: block; font-size: 0.7rem; color: #d97706; margin-top: 0.3rem; font-weight: 600; }
.product-tile .options-flag {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--pos-color-secondary, var(--accent));
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 0.05rem 0.5rem;
  margin-top: 0.3rem;
}
/* Age-restricted tile badge (2026-09-27) — same shape as .options-flag,
   own colour so it reads as a warning rather than "this item has
   choices" at a glance. See ui/age-verification.js. */
.product-tile .age-flag {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 600;
  color: #d97706;
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 0.05rem 0.5rem;
  margin-top: 0.3rem;
  margin-left: 0.3rem;
}

.tile-media {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: 9px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.15rem;
  background: var(--panel);
}
.tile-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.tile-placeholder { color: #fff; font-size: 1.6rem; font-weight: 700; }

.cart-items { flex: 1; overflow-y: auto; padding: 0.4rem 0.9rem; }
.cart-line {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--line);
  transition: opacity 0.15s ease;
}
.cart-line:active { opacity: 0.6; }

/* Course/seat tag chips (2026-10-05, roadmap §7c) — table-service only,
   see renderCart()'s buildTagChip() calls. flex-basis: 100% drops this
   onto its own line below the item/price row rather than squeezing in
   beside them. */
.cart-line-tags { flex-basis: 100%; display: flex; gap: 0.4rem; margin-top: 0.3rem; }
.cart-line-tag-chip {
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  border: 1px solid var(--pos-border-color, var(--line));
  background: transparent;
  color: var(--pos-color-secondary, #94a3b8);
  font-size: 0.72rem;
  font-weight: 600;
  cursor: pointer;
}
.cart-line-tag-chip.tagged { background: rgba(60,140,255,0.15); color: #3c8cff; border-color: transparent; }

/* Course firing rail (2026-10-05, roadmap §7c) — see renderCourseRail()
   in operator.js. Sits above #cart-items; .fired swaps to a muted
   "already sent" look rather than the brand accent, so an unfired
   course (needing action) still reads as the more prominent one. */
.course-rail {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--line);
  margin-bottom: 0.4rem;
}
.course-chip {
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  border: none;
  background: var(--accent);
  color: #1c1200;
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
}
.course-chip.fired { background: var(--pos-bg-surface-alt, #2a2a2a); color: var(--pos-font-color-secondary, #94a3b8); font-weight: 600; }
.course-chip:disabled { opacity: 0.6; cursor: default; }

/* Split bill screen (2026-10-05, roadmap §7c) — by seat/by item; see
   wireSplitBillScreen() in operator.js. */
.split-bill-main { padding: 1rem 1.5rem; max-width: 640px; margin: 0 auto; width: 100%; }
.split-bill-mode-toggle { display: flex; gap: 0.6rem; margin-bottom: 1rem; }
.split-bill-mode-toggle .btn.active { background: var(--accent); color: #1c1200; }
.split-bill-list { display: flex; flex-direction: column; gap: 0.5rem; }
.split-bill-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--pos-border-color, var(--line));
  border-radius: 10px;
  cursor: pointer;
  font-weight: 600;
}
.split-bill-row.selected { border-color: var(--accent); background: rgba(255, 122, 48, 0.1); }
.split-bill-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 1.5rem;
  border-top: 1px solid var(--line);
  gap: 1rem;
}
.cart-line .qty {
  color: var(--pos-color-secondary, var(--accent));
  margin-right: 0.5rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Member pricing / BOGOF line indicators (2026-09-24, roadmap Phase 8) —
   the struck-through catalog price next to the reduced one a line will
   actually charge, and a small badge (a free-unit count, or "Member")
   showing why. Kept subtle — this is a normal, expected state at a
   loyalty-enabled till, not a warning. */
.cart-line-was {
  text-decoration: line-through;
  color: var(--pos-color-secondary, #94a3b8);
  margin-right: 0.35rem;
  font-weight: 400;
}
.cart-line-badge {
  display: inline-block;
  margin-left: 0.5rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  background: rgba(60,140,255,0.15);
  color: #3c8cff;
  font-size: 0.7rem;
  font-weight: 700;
  vertical-align: middle;
}

.cart-discount-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.5rem 0.9rem;
  background: rgba(255,122,48,0.1);
  border-top: 1px dashed var(--accent);
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 600;
}

/* Attached customer strip (2026-09-23, roadmap Phase 7) — same shape as
   the discount row just above, distinct blue tint so the two are never
   confused at a glance (a discount reduces the bill, a customer doesn't). */
.cart-customer-row {
  background: rgba(60,140,255,0.12);
  border-top: 1px dashed #3c8cff;
  color: #3c8cff;
}

/* Loyalty tender step (2026-09-23, roadmap Phase 7) */
#tender-loyalty-points { margin-bottom: 0.6rem; }
#tender-loyalty-value { margin: 0 0 0.8rem; }
#tender-loyalty-customer-info { margin-top: 0; }

.cart-totals { padding: 0.9rem; border-top: 1px solid var(--line); }
.cart-totals div { display: flex; justify-content: space-between; padding: 0.25rem 0; font-variant-numeric: tabular-nums; }
.cart-totals .total { font-size: 1.5rem; font-weight: 700; padding-top: 0.5rem; margin-top: 0.2rem; border-top: 1px solid var(--line); }

.cart-actions { display: flex; gap: 0.6rem; padding: 0 0.9rem 0.7rem; }
.cart-actions:last-of-type { padding-bottom: 0.9rem; }
.cart-actions .btn-large { flex: 1; }
.cart-actions .btn { flex: 1; }
.btn-small { flex: none; padding: 0.35rem 0.7rem; font-size: 0.85rem; }

/* Collapsible cart bottom sheet (2026-09-26) — see index.html's own
   comment on #cart-detail-sheet for why this exists. At every width
   above the 700px breakpoint below, this is a no-op: .cart-detail-sheet
   just needs to behave exactly like .cart-pane's direct children used to
   (a flex column filling the remaining height, so #cart-items{flex:1}
   still scrolls correctly), and .cart-summary-toggle stays hidden. */
.cart-detail-sheet { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.cart-summary-toggle {
  display: none;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  background: var(--panel-raised);
  border: none;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 0.7rem 0.9rem;
  color: inherit;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.discount-type-toggle { display: flex; gap: 0.5rem; justify-content: center; margin-bottom: 0.5rem; }
.discount-type-toggle .btn.active { background: var(--accent); color: #1c1200; }

/* Discount presets (2026-09-19) — tenant-defined named shortcuts shown
   above the custom keypad, so a cashier can one-tap "Staff 10%" instead
   of typing 1-0-Apply. Hidden entirely (both this and the label below)
   when a tenant has no presets, so the screen looks exactly as it did
   before for anyone who hasn't set any up. */
.discount-presets { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; margin-bottom: 0.8rem; }
.discount-preset-btn { padding: 0.55rem 1rem; }
.discount-presets-label { color: var(--muted); font-size: 0.85rem; margin: 0 0 0.6rem; }

.recall-list { max-height: 50vh; overflow-y: auto; text-align: left; margin: 1rem 0; }
.recall-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.9rem;
  background: var(--panel-raised);
  border-radius: 12px;
  margin-bottom: 0.6rem;
  border: 1px solid var(--line);
}
.recall-item button { margin-left: 0.5rem; }
.recall-empty { color: var(--muted); text-align: center; padding: 1rem 0; }

.till-complete-tick {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--pos-color-success, #0E8A5F);
  color: #fff;
  font-size: 1.8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 1rem;
}
.receipt-content {
  font-family: 'Courier New', monospace;
  text-align: left;
  background: #fff;
  color: #111;
  padding: 1.2rem;
  border-radius: 6px;
  max-height: 50vh;
  overflow-y: auto;
  white-space: pre-wrap;
  box-shadow: 0 2px 10px rgba(0,0,0,0.3);
  font-size: 0.95rem;
  line-height: 1.5;
}

.cashup-summary { text-align: left; margin: 1rem 0; }
.cashup-summary div { display: flex; justify-content: space-between; padding: 0.3rem 0; font-variant-numeric: tabular-nums; }
.cashup-summary .total { font-weight: 700; font-size: 1.15rem; border-top: 1px solid var(--line); padding-top: 0.5rem; margin-top: 0.2rem; }
#cashup-counted {
  width: 100%; font-size: 1.5rem; text-align: center; padding: 0.8rem;
  border-radius: 10px; border: 1px solid #3a3f4a; background: var(--panel);
  color: var(--text); margin: 0.5rem 0 1rem;
}

/* Table-service floor view (2026-10-04, roadmap §7c) — reuses
   .till-header/.staff-pill etc from the operator till above; only the
   content area below the header is new. Tiles use a dedicated
   --table-* status palette rather than overloading --good/--bad,
   since "order_in" and "bill_requested" aren't success/error states —
   see TableServiceController::list()'s 4-state status derivation
   (operator.js's renderFloor() is the only thing that reads these
   classes). */
.floor-main { flex: 1; overflow-y: auto; padding: 1.2rem; }
.floor-area { margin-bottom: 1.6rem; }
.floor-area-name { font-weight: 700; letter-spacing: 0.01em; margin-bottom: 0.7rem; color: var(--muted); text-transform: uppercase; font-size: 0.85rem; }
.floor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.9rem;
}
.floor-tile {
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--panel-raised);
  padding: 1rem 0.9rem;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-height: 90px;
  transition: transform 0.1s ease;
}
.floor-tile:active { transform: scale(0.96); }
.floor-tile-name { font-weight: 700; font-size: 1.05rem; }
.floor-tile-meta { color: var(--muted); font-size: 0.82rem; }
.floor-tile-status { font-size: 0.78rem; font-weight: 600; margin-top: auto; }
/* empty — quiet, matches the resting tile chrome above */
.floor-tile.status-empty .floor-tile-status { color: var(--muted); }
/* seated — table's open but no items rung in yet */
.floor-tile.status-seated { border-color: var(--accent); }
.floor-tile.status-seated .floor-tile-status { color: var(--accent); }
/* order_in — actively being served */
.floor-tile.status-order_in { background: rgba(99,199,155,0.16); border-color: var(--accent); }
.floor-tile.status-order_in .floor-tile-status { color: var(--accent); }
/* bill_requested — wants staff attention; a distinct amber rather than
   --bad, since this isn't an error */
.floor-tile.status-bill_requested { background: rgba(232,163,61,0.18); border-color: #e8a33d; }
.floor-tile.status-bill_requested .floor-tile-status { color: #e8a33d; }

/* Covers stepper (screen-table-open) */
.stepper { display: flex; align-items: center; justify-content: center; gap: 0.8rem; margin: 0.8rem 0 1.2rem; }
.stepper input {
  width: 4.5rem; text-align: center; font-size: 1.8rem; font-weight: 700;
  padding: 0.5rem; border-radius: 10px; border: 1px solid #3a3f4a;
  background: var(--panel); color: var(--text);
}
.stepper .btn { width: 3rem; height: 3rem; font-size: 1.4rem; padding: 0; }

/* Till-side refunds (2026-09-19) — screen-refund-search reuses the
   Held-orders .recall-list look for its results; screen-refund-detail
   is deliberately wider than the other .pairing-box-style screens
   (.refund-box) since it needs to show a line-item table, so it gets
   its own .refund-detail-box instead. .field-hint didn't exist on this
   side of the app before (admin.css only) — added here rather than
   duplicated, since these screens need the same "quiet helper text"
   treatment order_refund_form.php already uses. */
.field-hint { color: var(--muted); font-size: 0.85rem; margin: 0.4rem 0; }

.refund-box, .refund-detail-box {
  margin: auto;
  text-align: left;
  padding: 2rem;
  max-height: 92vh;
  overflow-y: auto;
}
.refund-box { max-width: 520px; width: 100%; }
.refund-detail-box { max-width: 720px; width: 100%; }
.refund-box h1, .refund-detail-box h1 { text-align: center; }
.refund-box input, .refund-detail-box input[type="text"] {
  width: 100%;
  font-size: 1.1rem;
  padding: 0.8rem;
  border-radius: 10px;
  border: 1px solid #3a3f4a;
  background: var(--panel);
  color: var(--text);
  margin: 0.5rem 0;
}
.refund-search-result { cursor: pointer; }
.refund-search-result:active { filter: brightness(1.15); }

.refund-table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
.refund-table th, .refund-table td { text-align: left; padding: 0.5rem 0.4rem; border-bottom: 1px solid var(--line); font-size: 0.95rem; }
.refund-table th { color: var(--muted); font-weight: 600; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.03rem; }
.refund-qty-input {
  width: 4.2rem; font-size: 1rem; padding: 0.4rem; border-radius: 8px;
  border: 1px solid #3a3f4a; background: var(--panel); color: var(--text); text-align: center;
}

.refund-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1rem 0; }
.refund-payment-row { margin: 1rem 0; }
.refund-fields label, .refund-payment-row label { display: block; color: var(--muted); font-size: 0.8rem; margin-bottom: 0.3rem; }
.refund-fields select, .refund-payment-row select {
  width: 100%; font-size: 1rem; padding: 0.7rem; border-radius: 10px;
  border: 1px solid #3a3f4a; background: var(--panel); color: var(--text);
}

.refund-alert { color: var(--bad); background: rgba(255,92,92,0.12); border: 1px solid var(--bad); border-radius: 8px; padding: 0.6rem 0.8rem; margin-bottom: 0.6rem; font-size: 0.9rem; }
.refund-success { color: var(--good); background: rgba(62,207,114,0.12); border: 1px solid var(--good); border-radius: 8px; padding: 0.6rem 0.8rem; margin-bottom: 0.6rem; font-size: 0.9rem; }
.refund-history { margin-top: 1.2rem; border-top: 1px solid var(--line); padding-top: 0.8rem; }
.refund-history-item { padding: 0.5rem 0; border-bottom: 1px solid var(--line); font-size: 0.85rem; color: var(--muted); }

@media print {
  body * { visibility: hidden; }
  #receipt-content, #receipt-content *, #reading-content, #reading-content * { visibility: visible; }
  #receipt-content, #reading-content { position: absolute; top: 0; left: 0; width: 100%; box-shadow: none; }
}

.payment-status { min-height: 2rem; }

/* --- Operator till: payment & tender screen --- */
#screen-payment { flex-direction: row; }
.tender-summary-rail {
  flex: 0 0 320px;
  background: var(--panel);
  color: var(--text);
  display: flex;
  flex-direction: column;
  padding: 2rem 1.6rem;
  border-right: 1px solid var(--line);
}
.tender-item-count { color: var(--muted); margin-bottom: 1.2rem; }
.tender-summary-totals { margin: auto 0; }
.tender-summary-totals > div { display: flex; justify-content: space-between; padding: 0.5rem 0; color: var(--muted); }
.tender-summary-totals > div.total { color: var(--text); font-size: 1.4rem; font-weight: 700; border-top: 1px solid var(--line); margin-top: 0.5rem; padding-top: 1rem; }
.tender-panel {
  flex: 1;
  background: var(--pos-bg-page);
  color: var(--pos-font-color-primary);
  font-family: var(--pos-font-family);
  font-size: var(--pos-font-size);
  padding: 1.8rem 2.2rem;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  max-width: 560px;
}
.tender-due-box {
  background: var(--pos-bg-surface-alt);
  border-radius: 12px;
  padding: 1.3rem 1.5rem;
}
.tender-due-label { display: block; text-transform: uppercase; letter-spacing: 0.08rem; font-size: 0.78rem; font-weight: 700; color: var(--pos-font-color-secondary); }
.tender-due-amount { display: block; font-size: 2.4rem; font-weight: 700; color: var(--pos-font-color-headings); }
.tender-change-line { display: block; color: var(--pos-color-success); font-weight: 700; margin-top: 0.3rem; }
.tender-quickcash {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.6rem;
}
/* 2026-09-19, Pete: proper phone/calculator-style keypad rather than a
   4-wide grid the 12 keys just happened to flow into — 1-9 in a 3x3
   block, then 00/0/back along the bottom (see renderKeypadInto's key
   order in operator.js, which already emits keys in exactly this
   row-by-row order; only the column count needed to change here). Same
   3-across shape the till's other keypads already use (see .pin-key and
   .discount-key below) — this was the one keypad in the app that didn't
   match it. */
.tender-keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.6rem;
}
.tender-preset, .tender-key {
  padding: 0.9rem 0.5rem;
  border-radius: var(--pos-button-radius);
  border: 1px solid var(--pos-border-color);
  background: var(--pos-bg-surface);
  color: var(--pos-font-color-primary);
  font-weight: 600;
  font-size: 1.05rem;
  font-family: inherit;
  cursor: pointer;
}
.tender-preset:active, .tender-key:active { background: var(--pos-bg-hover); }

/* Step 1: payment-type picker */
.tender-step-heading { margin: 0 0 0.4rem; font-size: 1.3rem; color: var(--pos-font-color-headings); }
.tender-method-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.9rem; }

/* Evenly N ways (2026-10-05, roadmap §7c) — see renderEvenSplitOptions
   in operator.js. .tender-preset.active reuses the existing preset
   button look, just picking out whichever N is currently selected. */
.tender-even-split {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.4rem;
}
.tender-even-split-label { font-weight: 600; color: var(--pos-font-color-secondary); font-size: 0.9rem; }
.tender-even-split-options { display: flex; gap: 0.4rem; }
.tender-even-split-options .tender-preset { padding: 0.5rem 0.8rem; font-size: 0.95rem; }
.tender-preset.active { background: var(--accent); color: #1c1200; border-color: var(--accent); font-weight: 700; }
.tender-even-split-active {
  font-size: 0.85rem;
  color: var(--pos-font-color-secondary);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.tender-even-split-cancel {
  background: none;
  border: none;
  color: var(--pos-font-color-secondary);
  text-decoration: underline;
  cursor: pointer;
  font-size: 0.85rem;
  padding: 0;
}

/* Split tender (2026-09-25) — the "paid so far" list shown on the method
   picker once at least one partial payment has been taken (see
   renderPickerStep in operator.js). */
.tender-paid-summary {
  background: var(--pos-bg-surface-alt);
  border-radius: 12px;
  padding: 1rem 1.2rem;
  margin-bottom: 0.2rem;
}
.tender-paid-heading { text-transform: uppercase; letter-spacing: 0.08rem; font-size: 0.78rem; font-weight: 700; color: var(--pos-font-color-secondary); margin-bottom: 0.5rem; }
.tender-paid-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.35rem 0;
  font-weight: 600;
  color: var(--pos-font-color-primary);
}
.tender-paid-remove {
  background: none;
  border: none;
  color: var(--pos-font-color-secondary);
  font-family: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0.15rem 0.4rem;
  white-space: nowrap;
}
.tender-paid-remove:hover { color: var(--pos-font-color-primary); }
.tender-method-tile {
  padding: 1.6rem 1rem;
  border-radius: var(--pos-button-radius);
  border: 1px solid var(--pos-border-color);
  background: var(--pos-bg-surface);
  color: var(--pos-font-color-primary);
  font-weight: 700;
  font-size: 1.1rem;
  font-family: inherit;
  cursor: pointer;
  text-align: center;
}
.tender-method-tile:active { background: var(--pos-bg-hover); }
.tender-method-tile:disabled { opacity: 0.4; cursor: not-allowed; }

/* Step 2: whichever method was chosen */
.tender-sub-step { display: flex; flex-direction: column; gap: 1.1rem; }
.tender-back-link {
  align-self: flex-start;
  background: none;
  border: none;
  color: var(--pos-font-color-secondary);
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  padding: 0.2rem 0;
}
.tender-back-link:hover { color: var(--pos-font-color-primary); }
.tender-field-label { display: block; font-size: 0.85rem; font-weight: 600; color: var(--pos-font-color-secondary); margin-bottom: -0.5rem; }
.tender-text-input {
  width: 100%;
  font-size: 1.2rem;
  padding: 0.8rem 0.9rem;
  border-radius: var(--pos-button-radius);
  border: 1px solid var(--pos-border-color);
  background: var(--pos-bg-surface);
  color: var(--pos-font-color-primary);
  font-family: inherit;
}
#btn-payment-complete {
  background: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
}
#btn-payment-complete:disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; }
/* Split tender (2026-09-25) — these four now toggle `disabled` too (card/
   gift card/other gained the same partial-amount gating cash already
   had; "Back to sale" locks once a gift card/loyalty redemption can't be
   cleanly undone — see renderPickerStep in operator.js). */
#btn-tender-card-charge:disabled,
#btn-tender-voucher-complete:disabled,
#btn-tender-other-complete:disabled,
#btn-tender-loyalty-complete:disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; }
#btn-payment-cancel:disabled { opacity: 0.35; cursor: not-allowed; }

/* Operator till: product grid re-skinned to the light brand look per the
   design handoff (the running-sale rail on the other side stays on the
   dark operator chrome — that's the one column design's own "Payment &
   tender" screen also keeps dark). Header/cart-pane deliberately keep
   the dark defaults above. */
#screen-till .catalog-pane { background: var(--pos-bg-page); }
#screen-till .category-tabs button {
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-primary);
  background: var(--pos-bg-surface);
}
#screen-till .category-tabs button.active {
  background: var(--pos-color-secondary);
  border-color: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
}
#screen-till .product-tile {
  background: var(--pos-bg-surface);
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-primary);
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
#screen-till .tile-media { background: var(--pos-bg-surface-alt); }
#screen-till .product-tile .price { color: var(--pos-color-secondary); font-weight: 600; }

/* Self-checkout re-skins the shared till-header/product-grid/cart-pane
   components with brand tokens instead of the operator's dark chrome.
   Per the design handoff, the header bar itself stays dark (matching the
   idle/attract screen) while the basket and item panels below it carry
   the light brand look — same markup and JS, different surfaces. */
#screen-self-shop .till-header {
  background: #0B0B0C;
  border-bottom: 1px solid #232323;
  color: #FFFFFF;
  box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
#screen-self-shop .sco-header-lane { margin-left: auto; font-weight: 600; color: #e6e6e6; }
#screen-self-shop .basket-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 1.1rem 0.9rem 0.4rem;
}
#screen-self-shop .basket-heading h2 { margin: 0; font-size: 1.4rem; color: var(--pos-font-color-headings); }
#screen-self-shop .basket-count { color: var(--pos-font-color-secondary); font-size: 0.9rem; }
#screen-self-shop .cart-line { cursor: default; flex-direction: column; align-items: stretch; gap: 0.3rem; }
#screen-self-shop .cart-line-info { display: flex; justify-content: space-between; }
#screen-self-shop .cart-line-right { display: flex; align-items: center; justify-content: space-between; }
#screen-self-shop .cart-line-price { font-weight: 700; }
#screen-self-shop .cart-line-remove {
  padding: 0.35rem 0.8rem;
  font-size: 0.85rem;
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-secondary);
}
#screen-self-shop .category-tabs button {
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-primary);
}
#screen-self-shop .category-tabs button.active {
  background: var(--pos-color-secondary);
  border-color: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
}
#screen-self-shop .product-tile {
  background: var(--pos-bg-surface);
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-primary);
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
#screen-self-shop .tile-media { background: var(--pos-bg-surface-alt); }
#screen-self-shop .product-tile .price { color: var(--pos-color-secondary); font-weight: 600; }
#screen-self-shop .cart-pane {
  background: var(--pos-bg-surface-alt);
  border-left: 1px solid var(--pos-border-color);
  color: var(--pos-font-color-primary);
}
#screen-self-shop .cart-line { border-bottom: 1px solid var(--pos-border-color); }
#screen-self-shop .cart-line .qty { color: var(--pos-color-secondary); }
#screen-self-shop .cart-totals { border-top-color: var(--pos-border-color); }
#screen-self-shop .cart-totals .total { border-top-color: var(--pos-border-color); }
#screen-self-shop #btn-self-checkout {
  background: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
  box-shadow: 0 4px 14px rgba(0,0,0,0.12);
}

/* --- Self-checkout: payment method screen. Dark rail (amount due, item
   count, back out) + light 2x2 grid of payment tiles, per the design
   handoff's split-panel payment screen. --- */
#screen-self-payment {
  flex-direction: row;
  font-family: var(--pos-font-family);
  font-size: var(--pos-font-size);
}
.sco-payment-rail {
  flex: 0 0 38%;
  background: #0B0B0C;
  color: #FFFFFF;
  display: flex;
  flex-direction: column;
  padding: 2rem;
}
.sco-payment-rail .sco-header-logo { margin-bottom: 2rem; }
.sco-payment-summary { margin: auto 0; }
.sco-payment-count { display: block; color: #b7b7b7; font-size: 1.05rem; margin-bottom: 1.4rem; }
.sco-payment-due-label { display: block; color: #b7b7b7; font-size: 1.05rem; margin-bottom: 0.3rem; }
.sco-payment-amount { display: block; font-size: 3rem; font-weight: 700; }
.sco-payment-rail .btn-ghost { align-self: flex-start; }
.sco-payment-methods {
  flex: 1;
  background: var(--pos-bg-page);
  color: var(--pos-font-color-primary);
  padding: 2.2rem;
  overflow-y: auto;
}
.sco-payment-methods h1 { margin: 0 0 1.4rem; font-size: 1.9rem; color: var(--pos-font-color-headings); }
.sco-payment-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
.sco-payment-tile {
  text-align: left;
  background: var(--pos-bg-surface);
  border: 1px solid var(--pos-border-color);
  border-radius: 14px;
  padding: 1.4rem;
  min-height: 130px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  cursor: pointer;
  font-family: inherit;
  color: var(--pos-font-color-primary);
}
.sco-payment-tile-label { font-size: 1.3rem; font-weight: 700; }
.sco-payment-tile-hint { color: var(--pos-font-color-secondary); font-size: 0.9rem; }
.sco-payment-tile.primary {
  background: var(--pos-color-secondary);
  border-color: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
}
.sco-payment-tile.primary .sco-payment-tile-hint { color: var(--pos-cta-text-color); opacity: 0.75; }
.sco-payment-tile:disabled { opacity: 0.45; cursor: not-allowed; }
.sco-payment-tile:not(:disabled):active { transform: scale(0.98); }
#self-payment-status { margin-top: 1rem; min-height: 1.2rem; color: var(--pos-font-color-secondary); }

/* --- Self-checkout: payment complete screen. --- */
#screen-self-done {
  background: var(--pos-bg-page);
  color: var(--pos-font-color-primary);
  font-family: var(--pos-font-family);
  font-size: var(--pos-font-size);
}
.sco-complete-box { margin: auto; text-align: center; max-width: 620px; padding: 2rem; }
.sco-complete-tick {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  background: var(--pos-color-success);
  color: #FFFFFF;
  font-size: 2.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 1.6rem;
}
.sco-complete-box h1 { font-size: 2.4rem; margin: 0 0 0.6rem; color: var(--pos-font-color-headings); }
.sco-complete-summary { color: var(--pos-font-color-secondary); font-size: 1.2rem; margin: 0 0 1.8rem; }
.sco-complete-actions { display: flex; gap: 1rem; justify-content: center; }
#btn-self-done-print { background: var(--pos-color-secondary); color: var(--pos-cta-text-color); }
#btn-self-done-email {
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-secondary);
}
#btn-self-done-email:disabled { opacity: 0.45; cursor: not-allowed; }

/* The idle screen's dark "continue from phone" link (styled above, with
   the rest of #screen-idle) leads here — the code-entry screen itself
   stays on the brand-light look, like #screen-self-shop above, since it
   shares its pin-pad markup with the staff PIN login. */
#screen-phone-claim .pin-display { color: var(--pos-font-color-headings); }
#screen-phone-claim .pin-key {
  background: var(--pos-bg-surface-alt);
  border: 1px solid var(--pos-border-color);
  color: var(--pos-font-color-primary);
}
#screen-phone-claim .pin-key:active {
  background: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
}
#screen-phone-claim .btn-ghost {
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-secondary);
}

/* QR handoff camera preview (2026-09-19) — only ever shown once a
   stream actually starts (see startQrScanner() in selfcheckout.js), so
   there's no "camera not found" dead box to style for; this is just the
   happy-path look. */
.phone-claim-camera-wrap { margin: 0 0 1rem; }
.phone-claim-video {
  display: block;
  width: 100%;
  max-width: 260px;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  margin: 0 auto 0.5rem;
  border-radius: 14px;
  border: 2px solid var(--pos-border-color);
  background: #000;
}

.btn { border-radius: var(--pos-button-radius); }

/* --- Scan & Shop (shop.html): a customer's own phone, so this is a
   normal scrolling mobile page, not a fixed single-viewport till screen —
   overrides the till-wide `body { height:100vh; overflow:hidden }` above. --- */
body.shop-body {
  height: auto;
  min-height: 100vh;
  overflow-y: auto;
  user-select: auto;
  -webkit-tap-highlight-color: revert;
}
.shop-screen {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--pos-bg-page);
  color: var(--pos-font-color-primary);
  font-family: var(--pos-font-family);
  font-size: var(--pos-font-size);
}
.shop-screen.hidden { display: none !important; }
.shop-screen h1 { color: var(--pos-font-color-headings); font-weight: 600; }
.shop-screen .btn-ghost { border-color: var(--pos-border-color); color: var(--pos-font-color-secondary); }
#shop-error .idle-box, #shop-loading .idle-box { margin: auto; text-align: center; max-width: 420px; padding: 2rem; }

/* Dark header (2026-09-20, tidy-up pass to match the Claude Design
   handoff's established visual language) — same treatment
   #screen-self-shop's till-header already carries (see its own comment:
   "the header bar itself stays dark ... while the basket and item panels
   below it carry the light brand look"). shop.html is the one
   customer-facing screen that had been left on a light header from
   before that redesign pass landed — this brings it in line rather than
   inventing a third header style. Logo uses the dark-ground lockup
   (`data-brand-logo-dark` in shop.html) for the same reason
   self-checkout's header does: the light-ground lockup is invisible on
   this background. */
.shop-header {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.9rem 1rem;
  background: #0B0B0C;
  border-bottom: 1px solid #232323;
  color: #FFFFFF;
  font-weight: 700;
  box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.shop-logo { max-height: 32px; max-width: 140px; flex-shrink: 0; }
/* Truncates rather than wraps — a long store title (e.g. a reseller's
   full trading name) used to force this span onto a second line and
   crowd the Scan button off the edge of a phone-width header. */
.shop-header-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 1.05rem;
}
.shop-scan-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(255, 255, 255, 0.08);
  color: #FFFFFF;
  border-radius: 999px;
  padding: 0.5rem 0.9rem;
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease;
}
.shop-scan-btn:active { background: rgba(255, 255, 255, 0.18); }
.shop-scan-btn-icon { width: 16px; height: 16px; flex-shrink: 0; }

/* Camera barcode scan overlay (2026-09-19) — reuses .item-picker-overlay/
   -card for the modal chrome (see that block's own comment) and
   .phone-claim-video's sizing for the camera preview, so this doesn't
   invent a third set of "camera modal" styles. */
.shop-scan-card { text-align: center; }
.shop-scan-video { margin: 0 auto 0.8rem; }
.shop-scan-feedback { min-height: 1.2em; margin: 0 0 0.6rem; }
.shop-scan-feedback.barcode-feedback-error { color: var(--bad, #ff5c5c); }

.shop-product-grid {
  overflow-y: visible;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  padding-bottom: 8.5rem; /* clears the fixed cart sheet so the last row is never hidden behind it */
}
.shop-screen .product-tile {
  background: var(--pos-bg-surface);
  border-color: var(--pos-border-color);
  color: var(--pos-font-color-primary);
  box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}
.shop-screen .tile-media { background: var(--pos-bg-surface-alt); }
.shop-screen .product-tile .price { color: var(--pos-color-secondary); font-weight: 600; }
.shop-screen .category-tabs button { border-color: var(--pos-border-color); color: var(--pos-font-color-primary); }
.shop-screen .category-tabs button.active {
  background: var(--pos-color-secondary);
  border-color: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
}

.shop-cart-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  background: var(--pos-bg-surface);
  border-top: 1px solid var(--pos-border-color);
  box-shadow: 0 -4px 16px rgba(0,0,0,0.08);
  padding: 0.7rem 1rem calc(0.9rem + env(safe-area-inset-bottom));
}
.shop-cart-detail {
  max-height: 45vh;
  overflow-y: auto;
  border-bottom: 1px solid var(--pos-border-color);
  margin-bottom: 0.6rem;
}
.shop-cart-detail .cart-line { border-bottom: 1px solid var(--pos-border-color); color: var(--pos-font-color-primary); }
.shop-cart-detail .cart-line .qty { color: var(--pos-color-secondary); }
.shop-cart-summary {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background: var(--pos-bg-surface-alt);
  border: 1px solid var(--pos-border-color);
  border-radius: var(--pos-button-radius);
  padding: 0.7rem 1rem;
  margin-bottom: 0.6rem;
  color: var(--pos-font-color-primary);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
#btn-shop-pay {
  width: 100%;
  background: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
  box-shadow: 0 4px 14px rgba(0,0,0,0.12);
}
#btn-shop-pay:disabled { opacity: 0.45; box-shadow: none; }

.shop-qr-code {
  width: 190px;
  margin: 0 auto;
}
.shop-qr-code svg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  box-shadow: 0 2px 14px rgba(0,0,0,0.12);
}
.shop-transfer-code {
  font-size: 2.6rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  margin: 1.2rem 0;
  font-variant-numeric: tabular-nums;
  color: var(--pos-color-secondary);
}
.shop-code-expiry { color: var(--pos-font-color-secondary); font-size: 0.9rem; }
#shop-ready .idle-box { margin: auto; text-align: center; max-width: 440px; padding: 2rem; }
#shop-ready #btn-shop-start-over { margin-top: 1.2rem; }

/* Variant + modifier picker overlay (2026-09-18) — one shared instance for
   both operator and self-checkout (see src/ui/item-picker.js). Styled with
   the light --pos-* brand tokens rather than the operator's dark chrome,
   since it's opened directly from the product grid, which is already
   re-skinned light in both screens (see the "Operator till: product grid
   re-skinned" comment above) — the picker should look like it belongs to
   the grid it popped up from, not the dark cart rail beside it. */
.item-picker-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(10, 8, 6, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
.item-picker-card {
  background: var(--pos-bg-surface);
  color: var(--pos-font-color-primary);
  font-family: var(--pos-font-family);
  font-size: var(--pos-font-size);
  border-radius: 16px;
  padding: 1.6rem 1.7rem;
  width: 100%;
  max-width: 480px;
  max-height: 85vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0,0,0,0.35);
}
.item-picker-title { margin: 0 0 1rem; font-size: 1.4rem; color: var(--pos-font-color-headings); }
.item-picker-section { margin-bottom: 1.1rem; }
.item-picker-section h3 {
  margin: 0 0 0.5rem;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.05rem;
  color: var(--pos-font-color-secondary);
}
.item-picker-options { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.item-picker-option {
  padding: 0.6rem 1rem;
  border-radius: var(--pos-button-radius);
  border: 1px solid var(--pos-border-color);
  background: var(--pos-bg-surface);
  color: var(--pos-font-color-primary);
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
}
.item-picker-option:active { background: var(--pos-bg-hover); }
.item-picker-option.selected {
  background: var(--pos-color-secondary);
  border-color: var(--pos-color-secondary);
  color: var(--pos-cta-text-color);
}
.item-picker-actions { display: flex; gap: 0.7rem; margin-top: 1.3rem; }
.item-picker-actions .btn { flex: 1; }
#item-picker-add { background: var(--pos-color-secondary); color: var(--pos-cta-text-color); }
#item-picker-add:disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; }
#item-picker-cancel, #weigh-cancel { border-color: var(--pos-border-color); color: var(--pos-font-color-secondary); }
#weigh-add { background: var(--pos-color-secondary); color: var(--pos-cta-text-color); }
#weigh-add:disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; }

/* Barcode scanning (2026-09-18) — the input itself is never meant to be
   seen or tapped (a real keyboard/on-screen one popping up would be
   actively unhelpful); it just needs to be focusable, so this hides it
   visually without display:none, which would make it unfocusable. */
.barcode-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  border: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
}
.barcode-feedback {
  position: absolute;
  top: 3.6rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--pos-color-success);
  color: #fff;
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  font-weight: 600;
  font-size: 0.9rem;
  box-shadow: 0 4px 14px rgba(0,0,0,0.2);
  z-index: 40;
}
.barcode-feedback.barcode-feedback-error { background: var(--bad, #ff5c5c); }

/* --- Operator till: phone-width responsive layout (2026-09-20, Pete: the
   till needs to run on Sunmi V3 card terminals — 6.75" portrait, ~360-400
   CSS px effective width, no landscape rotation — and as a fallback on
   ordinary phones like a Pixel 8 Pro, ~448 CSS px). Until now .till-main
   and #screen-payment were the only two-pane layouts in the app with no
   responsive breakpoint at all (shop.html was built mobile-first from the
   start; self-checkout's single-column idle/shop screens already happened
   to fit); confirmed via screenshot testing at 390px that .catalog-pane
   (flex:3) + .cart-pane (flex:2) simply doesn't reflow, overflowing ~440px
   horizontally with the cart pane pushed off-screen entirely, and
   #screen-payment's .tender-summary-rail (a FIXED flex:0 0 320px) is
   worse — it alone is nearly the full viewport width on a phone, leaving
   almost nothing for .tender-panel.

   700px covers every phone width worth planning for (Sunmi V3's ~360-400px
   up through the Pixel 8 Pro's 448px and beyond) with headroom, while
   leaving the proven landscape/tablet layout above completely untouched —
   this file has never had a till breakpoint before, so there's no
   existing narrow-width behaviour to preserve.

   Approach is pure stacking, not a new collapse/expand interaction: both
   .catalog-pane and .cart-pane (and .tender-summary-rail/.tender-panel)
   already scroll independently within whatever height they're given
   (.product-grid, .cart-items and .tender-panel all already have their
   own overflow-y), so turning the row layout into a column one is enough
   — no JS changes needed. A collapsible cart "sheet" (shop.html's
   .shop-cart-sheet pattern) would give back more screen space to
   browsing, but needs new markup/JS to do properly; flagged here as a
   worthwhile follow-up polish pass, not done as part of this fix. */
@media (max-width: 700px) {
  /* Header: 5 action buttons (Recall/Cash up/Refund/staff pill/Sign out)
     plus the logo and site label never fit in one row at this width.
     Sunmi V3's display is unusually tall for its width (1600px physical,
     portrait-only), so wrapping onto a second row costs little — simpler
     and more robust than building a new overflow-menu component for a
     first pass. */
  .till-header {
    flex-wrap: wrap;
    padding: 0.6rem 0.8rem;
    gap: 0.5rem 0.6rem;
  }
  .till-header .btn {
    padding: 0.5rem 0.8rem;
    font-size: 0.85rem;
  }
  .sco-header-logo { max-width: 110px; max-height: 32px; }
  /* Sync dot no longer needs to shove everything else to the right once
     the row wraps — let it sit inline instead of eating the remaining
     width with margin-left:auto. */
  .till-header .sync-status { margin-left: 0; }

  /* Main till screen (2026-09-26, superseding the stacked-column split
     this same comment used to describe): the cart pane is now a true
     fixed bottom sheet instead of a permanent 45%-height column, exactly
     the follow-up flagged when the stacked layout first shipped — see
     index.html's #cart-detail-sheet comment. .catalog-pane gets the
     browsing area back nearly in full; .cart-pane floats over the
     bottom of it, collapsed down to just the toggle bar + action
     buttons until tapped open. padding-bottom on .catalog-pane reserves
     just enough room so its own last row of products is never hidden
     behind the collapsed sheet sitting on top of it — sized generously
     against the sheet's actual collapsed height (toggle bar + both
     .cart-actions rows) rather than tuned to the exact pixel, since a
     little extra scroll headroom costs nothing but an overlap would
     hide a real button. */
  .till-main { flex-direction: column; }
  .catalog-pane { flex: 1 1 auto; min-height: 0; padding-bottom: 165px; }
  .cart-pane {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 5;
    max-height: 75vh;
    border-left: none;
    border-top: 1px solid var(--line);
    box-shadow: 0 -6px 20px rgba(0,0,0,0.35);
  }
  .cart-detail-sheet {
    max-height: 40vh;
    overflow-y: auto;
  }
  .cart-detail-sheet.collapsed { display: none; }
  .cart-summary-toggle { display: flex; }

  /* Cart actions: Discount/Customer/Void/Hold as a single flex:1 row (the
     desktop/tablet layout) doesn't actually shrink to fit here — flex
     items default to min-width:auto, so four button labels' own text
     width wins over the row's available space and Hold gets pushed
     ~90px past the viewport edge (caught via each button's own
     boundingBox, not the page-level overflow check, since .till-main's
     overflow:hidden clips it silently rather than growing the page — a
     good reminder to check element boxes too, not just document
     scrollWidth). A 2x2 grid gives each button roughly double the width
     a 4-across flex row could. */
  .cart-actions:not(:last-of-type) {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem;
  }
  .cart-actions:not(:last-of-type) .btn {
    padding: 0.7rem 0.5rem;
    font-size: 0.9rem;
  }

  /* Payment & tender: the summary rail was a fixed 320px column — on a
     360-448px phone that's nearly the whole screen. Turn it into a
     compact bar above the tender panel instead of a side rail. */
  #screen-payment { flex-direction: column; overflow-y: auto; }
  .tender-summary-rail {
    flex: none;
    border-right: none;
    border-bottom: 1px solid var(--line);
    padding: 1rem 1.2rem;
  }
  .tender-item-count { margin-bottom: 0.4rem; }
  .tender-summary-totals { margin: 0; }
  .tender-panel {
    max-width: none;
    padding: 1.2rem 1rem;
  }

  /* Till-side refund screens: .refund-detail-box's 720px max-width
     already shrinks to fit via width:100%, but the two-column Reason/Note
     grid gets cramped under ~420px — stack it instead. */
  .refund-fields { grid-template-columns: 1fr; }
  .refund-table th, .refund-table td { padding: 0.4rem 0.25rem; font-size: 0.85rem; }

  /* #refund-action-row is the same .cart-actions flex-row overflow bug as
     Discount/Customer/Void/Hold above — but it actually gets caught BY
     that same .cart-actions:not(:last-of-type) grid rule above, and for
     the wrong reason: :last-of-type is scoped to sibling elements of the
     same TAG (div), not the same class, and #refund-history (a later
     <div> sibling in #screen-refund-detail) means #refund-action-row
     isn't actually the last div-type element even though it's the only
     .cart-actions in its screen. So it inherits display:grid from that
     rule, and a bare flex-direction:column here (tried first, verified
     via screenshot to have NO effect) is inert since flex-direction only
     applies to flex containers. "Refund entire order" is long enough
     that even a 2-column grid is tight, so override display explicitly
     and stack the two buttons full-width instead. */
  #refund-action-row {
    display: flex;
    flex-direction: column;
  }

  /* .item-picker-actions (Cancel / Add to order in the variant/modifier
     picker modal) is the same flex:1 pitfall — at 360px viewport width
     the two .btn-large labels are borderline (~250-270px of content
     against ~258px available), so give them the same fix pre-emptively
     rather than waiting for it to actually clip on a real device. */
  .item-picker-actions {
    flex-direction: column;
  }
}

/* Customer-facing display (2026-10-06, roadmap V2) — see
   #screen-customer-display in index.html and src/ui/customer-display.js.
   Light brand surface like shop.html/self-checkout, not the operator's
   dark chrome, since this screen only ever faces the shopper. Deliberately
   large type: this is usually mounted on a small second screen read from
   a few feet away, not touched. */
#screen-customer-display {
  background: var(--pos-bg-page);
  color: var(--pos-font-color-primary);
  font-family: var(--pos-font-family);
  align-items: center;
  justify-content: center;
  padding: 2rem;
}
.cd-state { width: 100%; max-width: 560px; text-align: center; }
#screen-customer-display h1 {
  font-size: 2.6rem;
  color: var(--pos-font-color-headings);
  margin: 0 0 0.5rem;
}
.cd-logo { max-height: 72px; margin-bottom: 1.5rem; }
.cd-cart-items {
  text-align: left;
  background: var(--pos-bg-surface);
  border: 1px solid var(--pos-border-color);
  border-radius: 10px;
  padding: 1rem 1.25rem;
  max-height: 55vh;
  overflow-y: auto;
  margin-bottom: 1rem;
}
.cd-cart-item {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  font-size: 1.2rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--pos-border-color);
}
.cd-cart-item:last-child { border-bottom: none; }
.cd-cart-item-name { flex: 1; }
.cd-totals {
  background: var(--pos-bg-surface);
  border: 1px solid var(--pos-border-color);
  border-radius: 10px;
  padding: 1rem 1.25rem;
}
.cd-totals-row {
  display: flex;
  justify-content: space-between;
  font-size: 1.2rem;
  padding: 0.3rem 0;
}
.cd-totals-row.cd-total {
  font-size: 1.8rem;
  font-weight: 700;
  border-top: 1px solid var(--pos-border-color);
  margin-top: 0.3rem;
  padding-top: 0.6rem;
}
.cd-change-due {
  font-size: 1.6rem;
  font-weight: 600;
  color: var(--pos-color-success);
}

/* Kitchen display (2026-10-06, roadmap V3) — see
   #screen-kitchen-display in index.html and src/ui/kitchen-display.js.
   Dark, high-contrast chrome rather than the light customer-facing
   surface above — this screen is read at a glance from across a pass,
   often in a steamy/bright kitchen, by staff with no hands free to
   touch it except to bump. */
#screen-kitchen-display {
  background: #1a1a1a;
  color: #f4f4f4;
  font-family: var(--pos-font-family);
  flex-direction: column;
  padding: 1.25rem 1.5rem;
}
.kd-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem;
}
.kd-header h1 { font-size: 1.6rem; margin: 0; color: #fff; }
.kd-header-logo { max-height: 40px; }
.kd-empty {
  text-align: center;
  font-size: 1.4rem;
  color: #888;
  margin-top: 3rem;
}
.kd-tickets {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1rem;
  align-content: start;
  overflow-y: auto;
  flex: 1;
}
.kt-ticket {
  background: #262626;
  border: 1px solid #3a3a3a;
  border-radius: 10px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
}
.kt-ticket-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.5rem;
}
.kt-ticket-title { font-size: 1.1rem; font-weight: 700; }
.kt-ticket-age { font-size: 0.95rem; color: #9a9a9a; }
.kt-ticket-age-late { color: #ff8a65; font-weight: 700; }
.kt-ticket-items { flex: 1; margin-bottom: 0.75rem; }
.kt-item {
  font-size: 1.05rem;
  padding: 0.3rem 0;
  border-bottom: 1px solid #333;
}
.kt-item:last-child { border-bottom: none; }
.kt-item-combo-start { border-top: 1px dashed #4a4a4a; margin-top: 0.3rem; padding-top: 0.4rem; }
.kt-item-combo { padding-left: 0.75rem; color: #d0d0d0; }
.kt-item-notes { font-size: 0.9rem; color: #ffb74d; margin-top: 0.1rem; }
.kt-bump-btn {
  background: var(--pos-color-success, #2e7d32);
  color: #fff;
  border: none;
  border-radius: 8px;
  font-size: 1.1rem;
  font-weight: 700;
  padding: 0.65rem 0;
  cursor: pointer;
}
.kt-bump-btn:active { opacity: 0.8; }
.kd-undo-bar {
  position: fixed;
  bottom: 1.25rem;
  left: 50%;
  transform: translateX(-50%);
  background: #333;
  color: #fff;
  border-radius: 8px;
  padding: 0.6rem 1rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
.kd-undo-bar button {
  background: none;
  border: none;
  color: #80cbc4;
  font-weight: 700;
  cursor: pointer;
  font-size: 1rem;
}

/* Transaction video capture (2026-10-06, roadmap V3) — the always-visible
   "this transaction is being recorded" indicator. Deliberately prominent
   and not dismissible: it is part of what makes recording lawful (people
   must be able to tell they are being recorded; the operator also needs
   physical signage). See video-capture/controller.js. */
.video-rec-indicator {
  position: fixed;
  top: 8px;
  right: 8px;
  z-index: 2000;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(20, 20, 20, 0.88);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  pointer-events: none;
}
.video-rec-indicator[hidden] { display: none; }
.video-rec-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #e53935;
  animation: video-rec-pulse 1.2s ease-in-out infinite;
}
@keyframes video-rec-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}
@media (prefers-reduced-motion: reduce) {
  .video-rec-dot { animation: none; }
}

/* Weigh screen (2026-10-07, weighed items) — reuses .item-picker-overlay/
   .item-picker-card; only the big readout, the typed field and the price
   line are new. */
.weigh-readout { font-size: 2.6rem; font-weight: 700; font-variant-numeric: tabular-nums; margin: 0.3rem 0; }
.weigh-input { width: 100%; font-size: 1.6rem; padding: 0.6rem 0.8rem; box-sizing: border-box; }
.weigh-price { font-size: 1.5rem; font-weight: 700; margin-top: 1rem; font-variant-numeric: tabular-nums; }

/* Table bookings on the till (2026-10-07) — see src/ui/bookings.js and floor.js. */
.floor-arrivals { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; padding: 0.6rem 0.8rem; border: 1px solid #3a3f4a; border-radius: 10px; }
.floor-arrivals-label { font-weight: 700; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.floor-arrival { border: 1px solid var(--accent); background: transparent; color: inherit; border-radius: 999px; padding: 0.35rem 0.8rem; font: inherit; font-size: 0.9rem; cursor: pointer; }
.floor-arrival.pending { border-style: dashed; border-color: #e8a33d; }
.floor-tile-booking { display: block; font-size: 0.74rem; margin-top: 0.15rem; opacity: 0.9; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.floor-tile-booking.next { color: var(--muted); }
.floor-tile-booking.deposit { color: var(--accent); font-weight: 600; }
.bookings-card { max-width: 760px; width: 100%; max-height: 92vh; overflow-y: auto; }
.bookings-head { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
.bk-list { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.6rem 0 1rem; }
.bk-row { border: 1px solid #3a3f4a; border-radius: 12px; padding: 0.7rem 0.8rem; }
.bk-row.status-cancelled, .bk-row.status-no_show, .bk-row.status-declined { opacity: 0.55; }
.bk-row.status-requested { border-style: dashed; border-color: #e8a33d; }
.bk-row.status-seated { border-color: var(--accent); }
.bk-main { display: flex; gap: 0.9rem; align-items: flex-start; }
.bk-time { font-weight: 700; font-size: 1.15rem; min-width: 3.2rem; }
.bk-who { flex: 1; min-width: 0; }
.bk-name { font-weight: 600; }
.bk-sub, .bk-note { font-size: 0.82rem; color: var(--muted); overflow-wrap: anywhere; }
.bk-dep { font-size: 0.82rem; color: var(--accent); font-weight: 600; }
.bk-status { font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); white-space: nowrap; }
.bk-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.6rem; }
.bk-actions .btn { flex: 0 0 auto; padding: 0.5rem 1rem; }
.bk-new .bk-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; }
.bk-new .bk-grid input, .bk-new .bk-grid select { width: 100%; padding: 0.7rem; border-radius: 8px; border: 1px solid #3a3f4a; background: transparent; color: inherit; font: inherit; }
.bk-new .bk-grid input:last-child { grid-column: 1 / -1; }
.bk-seat-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.6rem 0 1rem; }
/* The overlay card is light, so the dark-theme ghost button text is unreadable on it — same fix as #weigh-cancel above. */
.bookings-card .btn-ghost { border-color: var(--pos-border-color); color: var(--pos-font-color-secondary); }
.bookings-card .btn-primary { background: var(--pos-color-secondary); color: var(--pos-cta-text-color); }
.bookings-card .bk-new .bk-grid input, .bookings-card .bk-new .bk-grid select { border-color: var(--pos-border-color); color: var(--pos-font-color-secondary); }
.bookings-card h3 { color: var(--pos-font-color-headings); margin: 0.4rem 0; }

/* --- X / Z readings (2026-10-08) --- */
.readings-box { max-width: 460px; width: 100%; }
.readings-box .btn-large { width: 100%; margin-top: 0.8rem; }
.readings-preview { white-space: pre-wrap; background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 0.9rem 1rem; font: inherit; margin: 0 0 1rem; }
#reading-content { max-height: 60vh; overflow-y: auto; white-space: pre; font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; font-size: 0.82rem; text-align: left; overflow-x: auto; }
.readings-list { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 1rem; max-height: 55vh; overflow-y: auto; }
.readings-row { display: flex; gap: 0.8rem; justify-content: space-between; text-align: left; }
.readings-row .rr-no { font-weight: 700; min-width: 3rem; }
.readings-row .rr-when { flex: 1; color: var(--muted); }

/* Sales needing attention (2026-10-10): see src/ui/attention.js */
.attn-banner { position: fixed; left: 0; right: 0; top: 0; z-index: 900; background: var(--bad); color: #fff; border: 0; padding: 10px 16px; font: inherit; font-weight: 600; cursor: pointer; text-align: center; }
.attn-banner.hidden, .attn-overlay.hidden { display: none; }
.attn-overlay { position: fixed; inset: 0; z-index: 950; background: rgba(0,0,0,0.7); display: flex; align-items: center; justify-content: center; padding: 16px; }
.attn-card { background: var(--panel); color: var(--text); border: 1px solid var(--line); border-radius: 10px; max-width: 560px; width: 100%; max-height: 90vh; overflow: auto; padding: 20px; }
.attn-intro { color: var(--muted); }
.attn-row { border-top: 1px solid var(--line); padding: 12px 0; }
.attn-reason { color: var(--bad); margin: 4px 0 8px; }
.attn-row-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.attn-actions { margin-top: 12px; text-align: right; }

/* Receipt logo above the receipt text (2026-10-13). */
.receipt-content .receipt-logo { display: block; margin: 0 auto 0.6rem; max-width: 100%; height: auto; image-rendering: pixelated; }
/* Fit exactly the 32 columns a receipt is laid out in, so no line wraps (2026-10-13). */
#receipt-content { box-sizing: content-box; width: 32ch; max-width: calc(100vw - 4rem); max-height: 56vh; }
