/* ============================================================================
   Phase 26 — Field Operations PWA (Port 8003) — consumer-grade mobile design.
   Phase 30 — Plum + Lavender + Off-White colour system (replaces #511877 maroon).

   Standalone stylesheet: the field vertical mounts its OWN /static (= static/field),
   so the admin chrome is intentionally never loaded here. Visual language translated
   1:1 from the design reference (EventCortex PWA.dc.html): Plus Jakarta Sans, the
   Plum (#6D28D9) gradient identity, soft white cards, and the sheet/toast/scan
   keyframes. Class names that JS or HTMX hook into are PRESERVED verbatim
   (fld-scan-result*, fld-flash, fld-scan-headline/msg, fld-queue-count, fld-sync-now,
   result-<rowId>, fld-ticket*, fld-sent*, fld-error).

   Design system doc: Code/FIELD_DESIGN.md (AR-48 — consult before any 8003 UI change).
   ========================================================================== */

/* Self-hosted webfonts (no CDN). The field PWA's CSP is default-src 'self' and the
   app must run fully offline at the gate — so fonts are vendored alongside htmx/alpine,
   not pulled from fonts.googleapis.com (which the CSP blocks and which fails offline).
   Plus Jakarta Sans ships as a single variable woff2 (400–800 axis); JetBrains Mono is
   the latin 400 cut used only by .fld-input--mono. Latin subset only. */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/static/fonts/plus-jakarta-sans-latin-var.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/jetbrains-mono-latin-400.woff2') format('woff2');
}

:root {
  /* ── Plum + Lavender + Off-White identity (Phase 30) ────────────────────── */
  --fld-brand:  #6D28D9;  /* Plum — primary CTA, active tab, brand icon */
  --fld-brand2: #8B5CF6;  /* Violet — gradient partner, avatar gradient end */
  --fld-accent: #7C3AED;  /* Violet-600 — mid accent, icons, links */
  --fld-ink:    #1E1040;  /* Near-black with plum cast — body text */
  --fld-muted:  #7D6E9F;  /* Muted violet — secondary labels, kickers */
  --fld-muted2: #9181B3;  /* Lighter muted — timestamps, tertiary labels */
  --fld-faint:  #C4B5FD;  /* Lavender — disabled states, scanner corners */
  --fld-line:   #EDE9FE;  /* Violet-100 — hairline borders, dividers */
  --fld-line2:  #E5DFFE;  /* Slightly denser — card + chip borders */
  --fld-bg:     #FAF7FF;  /* Off-White — page background */
  --fld-tint:   #F5F3FF;  /* Violet-50 — hover/selected bg, ghost btn bg */
  --fld-card:   #ffffff;  /* Card surface — pure white */

  /* ── Semantic (unchanged — never migrate these) ──────────────────────────── */
  --fld-ok:     #15875a;
  --fld-bad:    #c0392b;
  --fld-warn:   #b87514;
  --fld-okbg:   #eafaf2;
  --fld-badbg:  #fbecea;

  /* ── Elevation ───────────────────────────────────────────────────────────── */
  --fld-shadow: 0 2px 10px -6px rgba(109,40,217,.10);
  --fld-shadow-lg: 0 24px 50px -18px rgba(109,40,217,.35);
}

* { box-sizing: border-box; }
[x-cloak] { display: none !important; }

/* ── Cross-document view transitions (Phase 32) ───────────────────────────────
   Each tab is a full server-rendered page (no SPA router), so without this every
   bottom-nav tap hard-cuts to a blank flash-of-white before the next page paints
   — the single biggest remaining "this is a website" tell. `navigation: auto`
   opts every field-app page into the browser's native cross-document transition
   (Chrome 126+, Safari 18.2+ iOS/macOS; Firefox ignores it — plain navigation,
   no regression). Zero JS, no library, CSP/AR-48-safe. `.fld-top` and
   `.fld-bottomnav` get a shared view-transition-name so the chrome stays put and
   only the page content cross-fades — exactly how a native app's persistent
   chrome behaves under a screen transition, instead of the whole page (including
   the tab bar) flashing. Each name may appear at most once per page — verified
   true here (top bar / bottom nav are each singular, conditionally rendered). */
@view-transition { navigation: auto; }
.fld-top { view-transition-name: fld-topbar; }
.fld-bottomnav { view-transition-name: fld-bottomnav; }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) {
    animation: none !important;
  }
}

/* ── Native-app feel (Phase 32 — §9 FIELD_DESIGN.md) ──────────────────────────
   overscroll-behavior stops the iOS/Android rubber-band bounce + Chrome's
   pull-to-refresh from firing when a scroll view hits its top/bottom edge —
   without this, an accidental swipe reloads the whole app mid-shift, which
   reads as "a website", not "an app". Applied at the document root AND on
   every internal scroll container (sheets/menus) so scroll never chains out
   to the browser. */
html, body { height: 100%; overscroll-behavior-y: none; }
.fld-body {
  margin: 0;
  font-family: 'Plus Jakarta Sans', -apple-system, system-ui, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  color: var(--fld-ink);
  background: var(--fld-bg);
  overscroll-behavior-y: none;
}
::-webkit-scrollbar { width: 0; height: 0; }

/* touch-action: manipulation removes the ~300ms tap delay and disables
   double-tap-to-zoom on controls (that gesture is for content, not buttons).
   -webkit-touch-callout: none suppresses iOS's long-press callout menu
   ("Copy" / "Look Up") on rapid repeated taps against nav/buttons. Neither
   rule touches user-select, so ticket numbers/attendee names stay copyable —
   only interactive chrome opts out of the browser's text-selection gesture. */
button, a, .fld-tab, .fld-btn, .fld-evchip__btn, .fld-evchip__option,
.fld-acct__av, .fld-acct__action, .fld-seg__btn, .fld-install__cta, .fld-install__close {
  touch-action: manipulation;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

/* ── Keyframes (lifted from the design reference) ─────────────────────────── */
/* Travel distance tuned to the .fld-vf__box size (230px, minus its 16px laser inset
   on each side = ~198px) — keep this in sync if the viewfinder box size changes. */
@keyframes fld-scan  { 0%{transform:translateY(0);opacity:0} 12%{opacity:1} 88%{opacity:1} 100%{transform:translateY(198px);opacity:0} }
@keyframes fld-flash { 0%{opacity:.55;transform:scale(.96)} 100%{opacity:1;transform:scale(1)} }
@keyframes fld-sheet { 0%{transform:translateY(102%)} 100%{transform:translateY(0)} }
@keyframes fld-toast { 0%{opacity:0;transform:translateY(10px)} 100%{opacity:1;transform:translateY(0)} }
@keyframes fld-pop   { 0%{opacity:0;transform:translateY(6px) scale(.98)} 100%{opacity:1;transform:translateY(0) scale(1)} }
@keyframes fld-popc  { 0%{opacity:0;transform:translate(-50%,-50%) scale(.96)} 100%{opacity:1;transform:translate(-50%,-50%) scale(1)} }
@keyframes fld-pulse { 0%,100%{opacity:.5} 50%{opacity:1} }
@keyframes fld-spin  { to{transform:rotate(360deg)} }

/* ── Top app bar (white, sticky) ──────────────────────────────────────────── */
.fld-top {
  display: flex; align-items: center; gap: 9px;
  background: #fff; border-bottom: 1px solid var(--fld-line);
  padding: calc(14px + env(safe-area-inset-top)) 16px 12px;
  position: sticky; top: 0; z-index: 30;
}
.fld-top__logo {
  width: 36px; height: 36px; border-radius: 10px; flex: none;
  background: var(--fld-brand); display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 16px -6px rgba(109,40,217,.55);
}
.fld-top__logo::after { content: ""; width: 10px; height: 10px; border: 2px solid #fff; border-radius: 3px; }
img.fld-top__logo { background: none; box-shadow: none; object-fit: contain; padding: 0; }
.fld-top__brand { font-size: 15px; font-weight: 800; letter-spacing: -.01em; color: var(--fld-ink); }
.fld-top__brand .np { color: var(--fld-accent); }
.fld-top__tenant {
  margin-left: auto; font-size: 11.5px; font-weight: 700; color: var(--fld-accent);
  background: #EDE9FE; border: 1px solid #E5DFFE; padding: 5px 11px; border-radius: 999px;
}

/* Event selector (legacy header dropdown — kept for reference; now replaced by fld-evchip) */
.fld-evsel { position: relative; min-width: 0; }
.fld-evsel__btn { font-family: inherit; cursor: pointer; background: none; border: none; padding: 0;
  text-align: right; max-width: 60vw; }
.fld-evsel__kicker { display: block; font-size: 10px; font-weight: 700; color: var(--fld-muted2); letter-spacing: .04em; }
.fld-evsel__name { display: flex; align-items: center; justify-content: flex-end; gap: 5px;
  font-size: 14px; font-weight: 800; color: var(--fld-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fld-evsel__caret { color: var(--fld-faint); font-size: 11px; }
.fld-evsel__menu { position: absolute; top: calc(100% + 9px); right: 0; z-index: 50;
  width: max(220px, 60vw); max-height: 60vh; overflow-y: auto;
  background: #fff; border: 1px solid var(--fld-line2); border-radius: 16px;
  box-shadow: var(--fld-shadow-lg); padding: 6px; animation: fld-pop .16s ease; }
.fld-evsel__item { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  text-decoration: none; color: var(--fld-ink); font-size: 14px; font-weight: 600;
  border-radius: 11px; padding: 11px 12px; }
.fld-evsel__item:active { background: var(--fld-tint); }
.fld-evsel__item--active { background: var(--fld-tint); color: var(--fld-brand); font-weight: 800; }
.fld-evsel__tick { color: var(--fld-brand); font-weight: 800; }

/* ── Page header (title + subtitle row) ──────────────────────────────────── */
.fld-page-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
/* Variant with an inline action button (e.g. allocations "+ New") — the title
   block sits in its own wrapper div, so its .fld-h1/.fld-sub need tighter,
   button-row-appropriate spacing than the plain title+subtitle page head. */
.fld-page-head--tight { margin-bottom: 0; }
.fld-page-head--tight .fld-h1  { margin: 0; }
.fld-page-head--tight .fld-sub { margin: 2px 0 0; }

/* ── Event context chip (per-tab page-level event switcher) ──────────────── */
.fld-evchip { margin-bottom: 16px; position: relative; }
.fld-evchip__btn {
  width: 100%; background: var(--fld-card); border: 1px solid var(--fld-line2);
  border-radius: 14px; padding: 9px 12px; display: flex; align-items: center;
  justify-content: space-between; gap: 8px; cursor: pointer; font-family: inherit;
  min-height: 48px;
  box-shadow: 0 1px 4px -2px rgba(109,40,217,.08);
  transition: border-color .15s, background .12s;
  -webkit-tap-highlight-color: transparent;
}
.fld-evchip__btn:active { border-color: var(--fld-brand2); background: var(--fld-tint); }
/* flex: 1 so left side absorbs all available space before the caret */
.fld-evchip__left { display: flex; align-items: center; gap: 9px; min-width: 0; flex: 1; }
.fld-evchip__icon { flex: none; color: var(--fld-accent); }
.fld-evchip__text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.fld-evchip__kicker { font-size: 9.5px; font-weight: 700; color: var(--fld-muted); letter-spacing: .06em; }
/* No max-width — let flex parent constrain; ellipsis fires only when truly needed */
.fld-evchip__name { font-size: 13.5px; font-weight: 800; color: var(--fld-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fld-evchip__caret { flex: none; color: var(--fld-muted); transition: transform .2s ease; }

.fld-evchip__panel {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  background: var(--fld-card);
  border: 1.5px solid var(--fld-line2); border-radius: 16px;
  overflow: hidden; box-shadow: 0 8px 24px -8px rgba(109,40,217,.12);
}
.fld-evchip__panel--enter { transition: opacity .18s ease, transform .18s ease; }
.fld-evchip__panel--enter-start { opacity: 0; transform: translateY(-6px); }
.fld-evchip__panel--enter-end   { opacity: 1; transform: translateY(0); }

.fld-evchip__option {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 14px; min-height: 52px;
  text-decoration: none; color: var(--fld-ink);
  font-size: 14px; font-weight: 600;
  border-bottom: 1px solid var(--fld-line);
  -webkit-tap-highlight-color: transparent;
  transition: background .1s;
}
.fld-evchip__option:last-child { border-bottom: none; }
.fld-evchip__option:active { background: var(--fld-tint); }
.fld-evchip__option--active { color: var(--fld-brand); font-weight: 800; background: var(--fld-tint); }
.fld-evchip__opt-check { width: 20px; flex: none; display: flex; align-items: center; justify-content: center; color: var(--fld-brand); }
.fld-evchip__opt-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .fld-evchip__panel--enter { transition: none; }
  .fld-evchip__caret { transition: none; }
  .fld-evchip__btn { transition: none; }
}

/* ── Account avatar + dropdown ────────────────────────────────────────────── */
.fld-acct { position: relative; flex: none; margin-left: auto; }
.fld-acct__av {
  width: 34px; height: 34px; border-radius: 50%;
  background: linear-gradient(135deg, var(--fld-brand) 0%, var(--fld-brand2) 100%);
  color: #fff; font-family: inherit; font-size: 12px; font-weight: 800;
  letter-spacing: .02em; border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 12px -4px rgba(109,40,217,.50);
  /* Tap target: 44×44 via touch-action-safe padding without breaking the circle */
  padding: 0; min-width: 44px; min-height: 44px;
  border-radius: 50%; margin: -5px 0;  /* visual 34px, tap 44px */
}
.fld-acct__av:active { opacity: .85; }
.fld-acct__menu {
  position: absolute; top: calc(100% + 12px); right: 0; z-index: 60;
  width: 220px; background: #fff; border: 1px solid var(--fld-line2);
  border-radius: 18px; box-shadow: 0 20px 50px -12px rgba(0,0,0,.22), 0 4px 16px -6px rgba(109,40,217,.10);
  padding: 6px; overflow: hidden;
}
.fld-acct__menu--in { animation: fld-pop .15s ease; }
.fld-acct__identity { padding: 10px 12px 8px; }
.fld-acct__name { font-size: 13.5px; font-weight: 800; color: var(--fld-ink); margin-bottom: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fld-acct__email { font-size: 11.5px; color: var(--fld-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fld-acct__sep { margin: 0 8px 4px; border: 0; border-top: 1px solid var(--fld-line); }
.fld-acct__action {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 12px; border-radius: 12px;
  font-family: inherit; font-size: 13.5px; font-weight: 700; color: var(--fld-ink);
  text-decoration: none; cursor: pointer; background: none; border: none;
  width: 100%; text-align: left; transition: background .12s;
}
.fld-acct__action:active { background: var(--fld-tint); }
.fld-acct__action--danger { color: var(--fld-bad); }
.fld-acct__action--danger:active { background: #fff5f5; }
.fld-acct__logout-form { margin: 0; }

/* ── Main scroll area ─────────────────────────────────────────────────────── */
.fld-main { max-width: 640px; margin: 0 auto; padding: 16px 14px 24px; }
.fld-main--hasnav { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
/* Full-bleed screens (login, change-password) supply their own edge-to-edge
   background + safe-area padding via .fld-login — the default .fld-main
   padding/max-width was leaving a ring of the wrong (--fld-bg off-white)
   background visible around all four sides of the "full-bleed" gradient
   card, the exact "bg color is not fully used" symptom. This modifier zeroes
   .fld-main out completely so .fld-login owns 100% of the viewport itself. */
.fld-main--bleed { padding: 0; max-width: none; margin: 0; }
.fld-h1  { font-size: 20px; font-weight: 800; margin: 4px 0 3px; letter-spacing: -.01em; }
.fld-sub { color: var(--fld-muted2); font-size: 12.5px; line-height: 1.5; margin: 0 0 14px; }
.fld-section-label { font-size: 11px; font-weight: 700; color: #9181B3; letter-spacing: .04em; margin: 4px 2px 8px;
  display: flex; align-items: center; gap: 6px; }
.fld-section-label svg { flex: none; }

.fld-empty {
  text-align: center; padding: 46px 20px; color: var(--fld-faint);
  border: 1px dashed var(--fld-line2); border-radius: 16px; background: #fff;
}
.fld-empty b { display: block; color: var(--fld-muted); font-weight: 700; font-size: 14px; }
.fld-empty span { font-size: 12.5px; }
.fld-empty--compact { padding: 30px 20px; }

/* A block-width submit button directly under a single sheet input. */
.fld-input + .fld-btn--block { margin-top: 12px; }

/* Empty-state / no-access icon chip — Violet-100 fill + Violet-150 border
   (FIELD_DESIGN §3). Geometry (size/radius/margin) stays inline per template;
   colour lives here so templates carry no hex in style="" (AR-14). */
.fld-eico { background: var(--fld-line); border: 1px solid var(--fld-line2); }
/* Small "all caught up" variant (allocations empty state) — 48px, green-themed,
   text glyph instead of an SVG. Geometry stays inline per the .fld-eico
   convention above only where it's genuinely per-instance; this size/colour
   pairing repeats nowhere else so it gets its own modifiers instead. */
.fld-eico--sm { width: 48px; height: 48px; border-radius: 14px; margin: 0 auto 14px;
  display: flex; align-items: center; justify-content: center; }
.fld-eico--ok { background: var(--fld-okbg); border-color: transparent; color: var(--fld-ok); font-size: 20px; }

/* ── Buttons ──────────────────────────────────────────────────────────────── */
.fld-btn {
  font-family: inherit; cursor: pointer; appearance: none;
  border: 1px solid var(--fld-line2); background: #fff; color: var(--fld-ink);
  padding: 12px 15px; border-radius: 12px; font-weight: 700; font-size: 13.5px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: transform .06s ease, filter .15s ease;
}
.fld-btn:active { transform: translateY(1px) scale(.995); }
.fld-btn--primary {
  background: var(--fld-brand); color: #fff; border-color: var(--fld-brand);
  box-shadow: 0 10px 22px -12px rgba(109,40,217,.65);
}
.fld-btn--ghost  { background: var(--fld-tint); color: var(--fld-brand); border-color: #E5DFFE; }
.fld-btn--danger { background: #fff; color: var(--fld-bad); border-color: #f0d8d4; }
.fld-btn--block  { width: 100%; }

/* ── Cards ────────────────────────────────────────────────────────────────── */
.fld-card {
  background: var(--fld-card); border: 1px solid var(--fld-line); border-radius: 18px;
  padding: 15px 16px; margin-bottom: 12px; box-shadow: var(--fld-shadow);
}
.fld-card--link { display: block; text-decoration: none; color: inherit; }
.fld-card--link:active { background: #fafafa; }
.fld-card__head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.fld-card__title { font-size: 14.5px; font-weight: 800; color: var(--fld-ink); }
.fld-card__tier  { color: var(--fld-muted); font-size: 12.5px; margin-top: 2px; }

.fld-counts { display: flex; align-items: baseline; gap: 6px; margin: 10px 0 2px; }
.fld-counts .big { font-size: 22px; font-weight: 800; color: var(--fld-brand); }
.fld-counts .of  { font-size: 12px; font-weight: 700; color: #9181B3; }
.fld-count { font-size: 13px; }
.fld-count b { font-size: 18px; }
.fld-count--muted { color: var(--fld-muted); }

.fld-progress { margin-top: 9px; height: 6px; background: var(--fld-line); border-radius: 99px; overflow: hidden; }
.fld-progress__bar { height: 100%; background: linear-gradient(90deg,#6D28D9,#8B5CF6); border-radius: 99px; transition: width .3s ease; }

/* Wallet (distributor hand-out list) */
.fld-wallet__title { font-size: 14.5px; font-weight: 800; color: var(--fld-ink); }
.fld-wallet__sub { font-size: 11.5px; color: var(--fld-muted2); margin-top: 2px; }
.fld-wallet__line { border-top: 1px solid var(--fld-line); padding-top: 11px; margin-top: 11px; }
.fld-wallet__line:first-of-type { border-top: none; padding-top: 12px; }
.fld-wallet__name { font-size: 14.5px; font-weight: 800; color: var(--fld-ink); }
.fld-wallet__rem { font-size: 20px; font-weight: 800; color: var(--fld-brand); }
.fld-wallet__of { font-size: 12px; color: #9181B3; font-weight: 700; }
.fld-wallet__noperm { margin-top: 11px; text-align: center; font-size: 12px; font-weight: 700;
  color: var(--fld-muted); background: var(--fld-tint); border-radius: 12px; padding: 11px; }
.fld-wallet__done { margin-top: 11px; text-align: center; }
/* "Pool remaining" caption — same weight as .fld-wallet__name, smaller + muted */
.fld-wallet__caption { font-size: 13px; font-weight: 800; color: var(--fld-muted); }
/* Contextual spacing overrides scoped to the wallet card, matching the existing
   .fld-tiercard .fld-progress / .fld-scan-hero .fld-progress precedent instead
   of ad-hoc inline style="margin-top:…". */
.fld-wallet__line .fld-card__head { margin-top: 8px; }
.fld-wallet__line .fld-card__tier { margin-top: 5px; }
.fld-wallet__line .fld-progress { margin-top: 7px; }
.fld-wallet__line .fld-btn--block { margin-top: 11px; }

/* Distribute-method accordion (email / manual hand-over) inside the wallet
   sheet — was fully inline `style=""` at every call site; now a real component. */
.fld-acc__head {
  font-family: inherit; cursor: pointer; width: 100%; background: none; border: none;
  padding: 8px 0; display: flex; align-items: center; justify-content: space-between;
}
.fld-acc__head-left { display: flex; align-items: center; gap: 9px; }
.fld-acc__caret { color: var(--fld-muted); font-size: 13px; transition: transform .18s; }
.fld-acc__caret--open { transform: rotate(180deg); }
.fld-acc__body { margin-top: 10px; }
.fld-acc__divider { border-top: 1px solid var(--fld-line); margin-top: 6px; padding-top: 6px; }
.fld-acc__submit { margin-top: 8px; }
/* Compact icon variant for the accordion header (base .fld-method__icon is 42px,
   used elsewhere at full card size — this context needs the smaller 32px cut). */
.fld-method__icon--sm { width: 32px; height: 32px; font-size: 16px; border-radius: 10px; flex: none; }
/* Reserves layout space for the validation hint before any text appears, so the
   field below doesn't jump when it does. */
.fld-req__hint--reserve { min-height: 15px; }
/* Repeated 12px top-gap between stacked form fields inside the accordion body. */
.fld-label--gap { margin-top: 12px; }
/* Native :disabled already reflects Alpine's :disabled="!canSend" binding — no
   need for a duplicate :style="!x && 'opacity:...'" expression per button. */
.fld-btn:disabled { opacity: .5; cursor: not-allowed; }

/* ── Badges ───────────────────────────────────────────────────────────────── */
.fld-badge { font-size: 10.5px; font-weight: 700; padding: 4px 9px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; }
.fld-badge--requested { background: #ede9fe; color: #6d28d9; }
.fld-badge--pending   { background: #fbf4e7; color: #b87514; }
.fld-badge--approved  { background: #dcfce7; color: #15803d; }
.fld-badge--distributed { background: #ede9fe; color: #6d28d9; }
.fld-badge--exhausted { background: #f1f5f9; color: #475569; }
.fld-badge--rejected, .fld-badge--cancelled { background: #fee2e2; color: #b91c1c; }

/* ── Segmented control (pill toggle) ──────────────────────────────────────── */
.fld-seg { display: flex; background: var(--fld-tint); border-radius: 13px; padding: 3px; margin-bottom: 14px; }
.fld-seg__btn {
  font-family: inherit; cursor: pointer; flex: 1; border: none; background: none;
  border-radius: 10px; padding: 10px; font-weight: 700; font-size: 13px; color: var(--fld-muted);
  transition: background .18s ease, color .18s ease, box-shadow .18s ease;
}
.fld-seg__btn--active { background: #fff; color: var(--fld-brand); box-shadow: 0 2px 8px -4px rgba(109,40,217,.20); }
.fld-seg__count { font-size: 11px; font-weight: 800; margin-left: 5px; color: var(--fld-warn);
  background: #fbf4e7; padding: 1px 7px; border-radius: 99px; }

/* ── Approval card extras ─────────────────────────────────────────────────── */
.fld-req__head { display: flex; align-items: center; justify-content: space-between; }
.fld-avatar { width: 30px; height: 30px; border-radius: 50%; background: #EDE9FE; color: var(--fld-accent);
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 11px; flex: none; }
.fld-req__who { display: flex; align-items: center; gap: 9px; }
.fld-req__name { font-size: 13.5px; font-weight: 800; }
.fld-req__when { font-size: 11px; color: var(--fld-muted2); }
.fld-req__lines { background: var(--fld-bg); border: 1px solid var(--fld-line); border-radius: 12px;
  padding: 10px 12px; margin-top: 11px; display: flex; flex-direction: column; gap: 7px; }
.fld-req__line { display: flex; align-items: center; justify-content: space-between; font-size: 13px;
  font-weight: 700; color: #3D2B6E; }
.fld-req__reason-label { font-size: 10.5px; font-weight: 800; color: #9181B3; letter-spacing: .03em;
  display: block; margin-top: 11px; }
.fld-req__reason-label + .fld-input,
.fld-req__reason-label + .fld-req__reason { margin-top: 5px; }
/* Quoted-reason callout (Phase 32 redesign) — used both for a maker's own
   reason ("My requests") and the requester's reason on the approval card.
   Previously a bare line of grey text with no container, so a terse answer
   like "ok" read as a stray fragment with no context. Now a tinted card with
   a quote-accent left border, always paired with a .fld-req__reason-label
   ("REASON" / "REQUESTER'S REASON") immediately above it. */
.fld-req__reason {
  font-size: 12.5px; color: var(--fld-ink); line-height: 1.45;
  background: var(--fld-tint); border-left: 2.5px solid var(--fld-line2);
  border-radius: 0 10px 10px 0; padding: 8px 10px 8px 12px;
}
.fld-field-row { display: flex; gap: 8px; margin-top: 12px; }
.fld-field-row .fld-btn { flex: 1; }
.fld-field-row .fld-btn--primary { flex: 2; }

/* Request-card bullets + meta (maker's "My requests" list) */
.fld-req__bullets { display: flex; flex-direction: column; gap: 4px; margin-top: 9px; }
.fld-req__bullet { display: flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; color: #3D2B6E; }
.fld-dot { width: 5px; height: 5px; border-radius: 50%; background: #C4B5FD; flex: none; }
/* Footer metadata row — pushed further from the reason card above (7→11px) and
   given an icon so it reads as a distinct "submission facts" footer rather than
   a continuation of the reason text above it. */
.fld-card__meta { font-size: 11.5px; color: var(--fld-faint); margin-top: 11px;
  display: flex; align-items: center; gap: 5px; }
.fld-card__meta svg { flex: none; opacity: .8; }

/* Approval-card right-hand ticket count + per-line availability */
.fld-req__total { font-size: 18px; font-weight: 800; color: var(--fld-ink); line-height: 1; }
.fld-req__total-label { font-size: 10.5px; color: var(--fld-muted2); font-weight: 600; }
.fld-req__total-wrap { text-align: right; }
/* Cancel button on a pending "My requests" card. */
.fld-req__cancel-btn { margin-top: 12px; }
.fld-avail { font-size: 11.5px; font-weight: 700; display: inline-flex; align-items: center; gap: 5px; }
.fld-avail--ok    { color: var(--fld-ok); }
.fld-avail--short { color: var(--fld-bad); }

/* Mandatory-reason validation hint (request + approval) */
.fld-req__hint { font-size: 11.5px; font-weight: 600; color: var(--fld-bad); margin-top: 6px; }

/* Inputs (shared) */
.fld-input {
  font-family: inherit; width: 100%; border: 1.5px solid #E5DFFE; border-radius: 12px;
  padding: 12px 13px; font-size: 15px; color: var(--fld-ink); outline: none; background: #fff;
}
.fld-input:focus { border-color: var(--fld-brand2); }
.fld-input--mono { font-family: 'JetBrains Mono', monospace; letter-spacing: 2px; text-transform: uppercase; }
.fld-label { font-size: 12px; font-weight: 700; color: #6B5E8A; margin: 6px 0; display: block; }
.fld-label .req { color: var(--fld-bad); }

/* ── Bottom sheet + modal (Alpine-driven) ─────────────────────────────────── */
.fld-backdrop { position: fixed; inset: 0; z-index: 80; background: rgba(30,16,64,.45); }
.fld-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 86;
  background: #fff; border-radius: 26px 26px 0 0; max-height: 92%; overflow-y: auto;
  padding: 16px 18px calc(30px + env(safe-area-inset-bottom));
  animation: fld-sheet .28s cubic-bezier(.2,.8,.2,1);
  /* Prevents an over-scroll at the top/bottom of the sheet's own content from
     chaining into the page behind it (rubber-band / pull-to-refresh). */
  overscroll-behavior: contain;
}
.fld-sheet__grab { width: 38px; height: 4px; background: #EDE9FE; border-radius: 99px; margin: 0 auto 14px; }
.fld-sheet__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 3px; }
.fld-sheet__title { font-size: 18px; font-weight: 800; color: var(--fld-ink); }
/* 44×44 minimum touch target (Apple HIG / WCAG 2.5.5). Visual circle stays 32px;
   negative margin offsets the extra hit-area so layout spacing is unchanged. */
.fld-sheet__close { font-family: inherit; cursor: pointer; background: var(--fld-tint); border: none;
  width: 44px; height: 44px; border-radius: 50%; color: #6B5E8A; font-size: 15px;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0; margin: -7px -7px -7px 0; }
.fld-sheet__sub { font-size: 13px; color: var(--fld-muted); margin-bottom: 14px; }
/* Live running-total recap ("3 tickets across 2 tiers") above the submit button
   in the new-request sheet — centred, with its own top/bottom rhythm. */
.fld-sheet__sub--summary { text-align: center; margin: 12px 0 10px; }

/* Centered modal card (confirm / error popup) */
.fld-modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%,-50%); z-index: 97;
  width: min(320px, 86vw); background: #fff; border-radius: 20px; padding: 22px;
  box-shadow: 0 30px 70px -20px rgba(30,16,64,.60); animation: fld-popc .18s ease; }

/* Confirmation dialog (replaces the native confirm() for every hx-confirm; design
   lifted from the reference's confirmation-dialog component). */
.fld-confirm { position: fixed; inset: 0; z-index: 96; }
.fld-confirm[hidden] { display: none; }
.fld-confirm__backdrop { position: fixed; inset: 0; background: rgba(30,16,64,.50); animation: fld-flash .16s ease; }
.fld-modal__title { font-size: 17px; font-weight: 800; color: var(--fld-ink); }
.fld-modal__body  { font-size: 13.5px; color: #6B5E8A; line-height: 1.5; margin-top: 8px; }
.fld-modal__actions { display: flex; gap: 9px; margin-top: 20px; }
.fld-modal__actions .fld-btn { flex: 1; }
.fld-btn--soft { background: var(--fld-tint); color: #6B5E8A; border-color: transparent; }
.fld-btn--danger-solid { background: var(--fld-bad); color: #fff; border-color: var(--fld-bad); }

/* Method chooser tiles (distribute) */
.fld-method { font-family: inherit; cursor: pointer; text-align: left; width: 100%;
  background: var(--fld-bg); border: 1px solid var(--fld-line2); border-radius: 15px;
  padding: 14px 15px; display: flex; align-items: center; gap: 13px; margin-bottom: 9px; }
.fld-method__icon { width: 42px; height: 42px; border-radius: 12px; display: flex; align-items: center;
  justify-content: center; font-size: 19px; flex: none; }
.fld-method__icon--mail { background: var(--fld-okbg); }
.fld-method__icon--qr   { background: #EDE9FE; }
.fld-method__t { font-size: 14.5px; font-weight: 800; color: var(--fld-ink); }
.fld-method__d { font-size: 12px; color: var(--fld-muted); }

/* Qty stepper (request form) */
.fld-stepper { display: flex; align-items: center; gap: 11px; padding: 11px 0; border-bottom: 1px solid var(--fld-line); }
.fld-stepper__main { flex: 1; }
.fld-stepper__btn { font-family: inherit; cursor: pointer; width: 36px; height: 36px; border-radius: 10px;
  border: 1.5px solid #E5DFFE; background: var(--fld-bg); color: var(--fld-brand); font-size: 18px; font-weight: 700; }
.fld-stepper__qty { font-family: inherit; font-size: 16px; font-weight: 800; color: var(--fld-ink);
  width: 54px; text-align: center; border: 1.5px solid #E5DFFE; border-radius: 10px; background: #fff; padding: 8px 2px; outline: none; }

/* ── Distribution result fragment (HTMX target) ───────────────────────────── */
.fld-result { margin-top: 14px; }
.fld-ticket { text-align: center; padding: 16px; border: 1px solid var(--fld-line2); border-radius: 16px; background: var(--fld-bg); }
.fld-ticket--repeat { border-color: #f59e0b; }
.fld-ticket__note { color: #b45309; font-size: 12px; margin-bottom: 8px; }
.fld-ticket__qr { width: 200px; max-width: 70%; margin: 0 auto; }
.fld-ticket__qr svg { width: 100%; height: auto; }
.fld-ticket__hint { color: var(--fld-muted); font-size: 12px; margin-top: 10px; }
.fld-ticket__remain { font-weight: 800; margin-top: 6px; color: var(--fld-brand); }
.fld-sent { background: var(--fld-okbg); border: 1px solid #a7f3d0; border-radius: 14px; padding: 13px; font-size: 13.5px; }
.fld-sent__remain { display: block; color: var(--fld-muted); font-size: 12px; margin-top: 4px; }
.fld-error { background: var(--fld-badbg); border: 1px solid #f3d3ce; color: #9a2d20;
  border-radius: 12px; padding: 12px; font-size: 13px; font-weight: 600; }

/* ── Scanner ──────────────────────────────────────────────────────────────── */
.fld-offline-banner { background: var(--fld-badbg); border: 1px solid #f3d3ce; border-radius: 14px;
  padding: 11px 13px; margin-bottom: 12px; display: flex; align-items: center; gap: 11px; }
.fld-offline-banner::before { content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: var(--fld-bad); animation: fld-pulse 1.4s infinite; flex: none; }
.fld-offline-banner b { display: block; font-size: 13px; color: #9a2d20; }
.fld-offline-banner span { font-size: 11.5px; color: #bb5e52; }

/* .fld-scan-device fuses the camera (.fld-cam) and the result banner
   (#fld-scan-result) into ONE continuous instrument: one outer radius, one
   card shadow, no visible seam — instead of two independently-styled stacked
   cards. The two children keep their own backgrounds/state colours; only the
   shared outer corners + elevation move up to this wrapper. See
   FIELD_DESIGN.md §7 "Scan device". */
.fld-scan-device { border-radius: 22px; overflow: hidden; box-shadow: var(--fld-shadow); margin: 8px 0 14px; }

/* Camera stack: #fld-scan-reader holds the qr-scanner <video> on the bottom layer,
   the pulsing viewfinder floats on top (pointer-events:none so the camera-
   permission button underneath stays tappable). Radius/margin live on the
   .fld-scan-device wrapper now — .fld-cam is a flush top segment of it.
   .fld-cam and the <video> are both a FIXED height (340px, Phase 32 — was 260px;
   raised so the camera reads as a substantial full-bleed native viewfinder
   instead of a thin strip) — height:auto (intrinsic camera aspect ratio)
   previously made the video a different size than its container on any stream
   that wasn't exactly the fixed height at 100% width, showing as a gap (video
   shorter) or a silent crop (video taller). Fixed height + object-fit:cover
   makes the two boxes identical always, cropping the stream instead of
   letterboxing it — standard for camera viewfinders. */
.fld-cam { position: relative; height: 340px;
  background: radial-gradient(120% 90% at 50% 30%, #2D1060 0%, #0F0820 100%); }
.fld-reader, #fld-scan-reader { position: relative; z-index: 1; width: 100%; height: 100%; }
#fld-scan-reader video { width: 100% !important; height: 100% !important; object-fit: cover; display: block; }
#fld-scan-reader { color: #C4B5FD; }                    /* permission prompt text on dark bg */

.fld-vf { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
/* Phase 32: the faint tech-grid overlay was removed — no mainstream native QR
   scanner (Apple/Google/WeChat/Pay apps) draws a grid across the live camera;
   it read as an AR/wireframe effect rather than a clean camera view and was
   flagged as a "doesn't feel native" contributor. The corner-bracket frame
   alone is the correct amount of camera chrome. */
/* Frame enlarged 200→230px and corners lengthened/thickened (Phase 32) so it
   reads as a confident, obvious scan target — matching how native scanners
   size their viewfinder relative to the camera view, rather than a small
   frame floating in a lot of empty background. */
.fld-vf__box { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  width: 230px; height: 230px; }
.fld-vf__c { position: absolute; width: 42px; height: 42px; }
.fld-vf__c--tl { top: 0; left: 0; border-top: 3.5px solid #C4B5FD; border-left: 3.5px solid #C4B5FD; border-radius: 10px 0 0 0; }
.fld-vf__c--tr { top: 0; right: 0; border-top: 3.5px solid #C4B5FD; border-right: 3.5px solid #C4B5FD; border-radius: 0 10px 0 0; }
.fld-vf__c--bl { bottom: 0; left: 0; border-bottom: 3.5px solid #C4B5FD; border-left: 3.5px solid #C4B5FD; border-radius: 0 0 0 10px; }
.fld-vf__c--br { bottom: 0; right: 0; border-bottom: 3.5px solid #C4B5FD; border-right: 3.5px solid #C4B5FD; border-radius: 0 0 10px 0; }
.fld-vf__laser { position: absolute; top: 16px; left: 16px; right: 16px; height: 2px;
  background: linear-gradient(90deg,transparent,#A78BFA,transparent); box-shadow: 0 0 12px #A78BFA;
  animation: fld-scan 2.4s ease-in-out infinite; }

/* Scan result banner — scanner.js swaps the --ok/--dup/--invalid/--idle modifier and
   re-adds .fld-flash on every scan. Colours = the design's green-admit / red-reject.
   Radius lives on the .fld-scan-device wrapper — this is the flush bottom segment. */
.fld-scan-result { padding: 15px 16px; text-align: center; color: #fff; }
.fld-scan-result__head { display: flex; align-items: center; justify-content: center; gap: 7px; }
.fld-scan-result__headline { font-size: 20px; font-weight: 800; }
.fld-scan-result__msg { font-size: 13.5px; margin-top: 4px; opacity: .95; }
.fld-scan-result--idle { background: radial-gradient(120% 90% at 50% 30%, #3D2B6E 0%, #1E1040 100%); }
.fld-scan-result--ok   { background: linear-gradient(90deg,#15875a,#1aa06c); }   /* GREEN — admitted */
.fld-scan-result--dup,
.fld-scan-result--invalid { background: linear-gradient(90deg,#c0392b,#d8503f); } /* RED — dup / off-manifest */
.fld-flash { animation: fld-flash .25s ease; }

/* Phase 32: the resting "Ready to scan" state is a passive hint, not feedback
   about something that happened — it should read as a quiet caption under the
   viewfinder, not a shouted headline+paragraph competing with the camera for
   attention (the exact contributor to the "too bulky" complaint). The mandated
   copy strings (FIELD_DESIGN.md §14.4) are unchanged — only their weight here.
   Every OTHER state (pending/ok/dup/invalid) is real-time feedback the operator
   must act on or notice immediately and KEEPS the full bold treatment above. */
.fld-scan-result--idle { padding: 9px 16px; }
.fld-scan-result--idle .fld-scan-result__headline { font-size: 12.5px; font-weight: 700; }
.fld-scan-result--idle .fld-scan-result__msg { font-size: 11px; opacity: .6; margin-top: 1px; }
.fld-scan-result--idle .fld-scan-result__icon,
.fld-scan-result--idle .fld-scan-result__icon svg { width: 14px; height: 14px; }

/* State icon — WCAG 1.4.1 (don't convey state by colour alone) + faster at-a-glance
   read in bright outdoor gate conditions. Sits INLINE beside the headline (not
   stacked above it) so it stays a compact one-line row instead of adding a whole
   icon-badge row of height to the banner. Pure CSS: all four SVGs are always in the
   DOM: scanner.js only ever toggles the parent's --idle/--pending/--ok/--dup/--invalid
   class (unchanged); this block keys icon visibility off that same class so scanner.js
   never gains an innerHTML/DOM write. Dup + invalid share one icon (both rejections,
   already share one red background above) per §14's "don't split dup into gate/server
   visual variants" rule — extended here to icon choice for the same reason. */
.fld-scan-result__icon { display: flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: none; }
.fld-scan-result__icon svg { display: none; width: 18px; height: 18px; }
.fld-scan-result--idle .i-idle,
.fld-scan-result--pending .i-pending,
.fld-scan-result--ok .i-ok,
.fld-scan-result--dup .i-bad,
.fld-scan-result--invalid .i-bad { display: block; }

.fld-scan-meta { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 14px; font-size: 13px; color: var(--fld-muted); }
.fld-scan-meta b { color: var(--fld-ink); }

/* Scanner dashboard (pre-scan by-tier check-in view) */
.fld-backlink { font-family: inherit; cursor: pointer; background: none; border: none; padding: 0;
  color: var(--fld-brand); font-weight: 700; font-size: 13.5px; margin-bottom: 11px; }
.fld-overall { background: #fff; border: 1px solid var(--fld-line); border-radius: 18px;
  padding: 14px 16px; margin-bottom: 13px; box-shadow: var(--fld-shadow); }
.fld-overall__head { display: flex; align-items: baseline; justify-content: space-between; }
.fld-overall__n { font-size: 26px; font-weight: 800; color: var(--fld-ink); }
.fld-overall__of { font-size: 14px; color: #9181B3; font-weight: 700; }
.fld-overall__pct { font-size: 12px; font-weight: 700; color: var(--fld-ok); }
.fld-tiercard { background: #fff; border: 1px solid var(--fld-line); border-radius: 15px;
  padding: 13px 14px; margin-bottom: 9px; }
.fld-tiercard__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.fld-tiercard__name { font-size: 14.5px; font-weight: 800; color: var(--fld-ink); }
.fld-tiercard__pill { font-size: 11.5px; font-weight: 700; color: var(--fld-brand);
  background: var(--fld-tint); padding: 3px 9px; border-radius: 99px; white-space: nowrap; }
.fld-tiercard__sub { font-size: 12px; color: var(--fld-muted); margin-top: 5px; }
.fld-tiercard .fld-progress { margin-top: 7px; height: 5px; }
.fld-scanbig { width: 100%; margin-top: 6px; padding: 15px; font-size: 15px; }
.fld-syncrow { display: flex; gap: 8px; margin-top: 11px; }
.fld-syncrow .fld-btn { flex: 1; }
.fld-syncrow__note { text-align: center; font-size: 11px; color: var(--fld-faint); margin-top: 9px; }
.fld-torch { font-family: inherit; cursor: pointer; position: absolute; top: 12px; right: 12px; z-index: 3;
  width: 38px; height: 38px; border-radius: 12px; border: 1px solid rgba(255,255,255,.16);
  background: rgba(255,255,255,.12); color: #fff; font-size: 16px; }
.fld-torch--on { background: #A78BFA; }

/* ── Phase 31 Scanner UX redesign ─────────────────────────────────────────── */

/* Pending scan — Plum gradient while the confirm sheet is open.
   Signals "brand interaction moment — the operator must decide now."
   NOT amber (that's for low-stock warnings; it must never appear here). */
.fld-scan-result--pending { background: linear-gradient(135deg, var(--fld-brand) 0%, var(--fld-brand2) 100%); }

/* Admit button — the ONE legitimate exception where --fld-ok green overrides
   --fld-brand Plum. Used ONLY on the "Admit ✓" gate action inside .fld-sheet.
   The green matches the --ok scan-result colour so the action and outcome agree. */
.fld-btn--admit {
  background: var(--fld-ok);
  color: #fff;
  border-color: var(--fld-ok);
  box-shadow: 0 8px 20px -10px rgba(21,135,90,.55);
}
.fld-btn--admit:active { background: #0f6847; }

/* Camera permission overlay — position: absolute inside .fld-cam (which is
   position: relative), so it fills the camera area before access is granted.
   .fld-perm--denied = red treatment for OS-blocked camera. */
.fld-perm {
  position: absolute; inset: 0; z-index: 10; border-radius: 22px;
  background: var(--fld-tint);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 28px 20px; gap: 14px; text-align: center;
}
.fld-perm--denied { background: var(--fld-badbg); }
.fld-perm__icon {
  width: 64px; height: 64px; border-radius: 20px;
  background: var(--fld-brand);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 24px -8px rgba(109,40,217,.45);
  color: #fff; flex-shrink: 0;
}
.fld-perm--denied .fld-perm__icon { background: var(--fld-bad); box-shadow: 0 10px 24px -8px rgba(192,57,43,.40); }
.fld-perm__title { font-size: 16px; font-weight: 800; color: var(--fld-ink); }
.fld-perm--denied .fld-perm__title { color: #9a2d20; }
.fld-perm__body { font-size: 13px; color: var(--fld-muted); line-height: 1.5; max-width: 240px; }
.fld-perm--denied .fld-perm__body { color: #bb5e52; }
.fld-perm__btn { margin-top: 4px; }

/* Dashboard hero card — replaces the bare .fld-overall div.
   White card (NOT Plum gradient — that's the command dashboard only). */
.fld-scan-hero {
  background: var(--fld-card); border: 1px solid var(--fld-line);
  border-radius: 20px; padding: 20px 18px; margin-bottom: 14px;
  box-shadow: var(--fld-shadow);
}
.fld-scan-hero__top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.fld-scan-hero__n  { font-size: 40px; font-weight: 800; color: var(--fld-ink); letter-spacing: -.02em; line-height: 1; }
.fld-scan-hero__of { font-size: 15px; font-weight: 700; color: var(--fld-muted2); }
.fld-scan-hero__pct {
  font-size: 11.5px; font-weight: 800; color: var(--fld-ok);
  background: var(--fld-okbg); border-radius: 99px; padding: 3px 10px; flex-shrink: 0; align-self: center;
}
.fld-scan-hero__evt {
  font-size: 12px; font-weight: 600; color: var(--fld-muted); margin-top: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fld-scan-hero .fld-progress { margin-top: 14px; height: 8px; }

/* Scan-stat bar — compact header for the active-scan view.
   Replaces .fld-backlink + .fld-h1 + .fld-sub in the old layout. */
.fld-scan-bar { display: flex; align-items: center; gap: 8px; padding-bottom: 12px; }
.fld-scan-bar__back {
  font-family: inherit; cursor: pointer; background: none; border: none;
  padding: 4px 8px 4px 0; font-size: 22px; font-weight: 800; color: var(--fld-brand);
  line-height: 1; min-height: 44px; display: flex; align-items: center;
}
.fld-scan-bar__evt {
  font-size: 13px; font-weight: 700; color: var(--fld-ink);
  flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fld-scan-bar__chip {
  font-size: 11px; font-weight: 800; color: var(--fld-ok);
  background: var(--fld-okbg); border-radius: 99px; padding: 3px 10px; flex-shrink: 0;
}

/* Action strip below the result banner — torch + enter-code + sync.
   Replaces the old .fld-scan-meta row. */
.fld-scan-actions {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 10px; padding: 0 2px; font-size: 12px; color: var(--fld-muted);
}
.fld-scan-actions__right { display: flex; gap: 8px; align-items: center; }
.fld-scan-actions .fld-btn { padding: 9px 12px; font-size: 12.5px; }

/* Ticket info card inside the scan confirm sheet.
   Plum left-border gives a "ticket stub" cue without full skeuomorphism. */
.fld-ticket-info {
  background: var(--fld-tint); border: 1px solid var(--fld-line2);
  border-left: 4px solid var(--fld-brand);
  border-radius: 16px; padding: 16px 16px 16px 14px; margin-bottom: 6px;
}
.fld-ticket-info__name {
  font-size: 18px; font-weight: 800; color: var(--fld-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fld-ticket-info__tier {
  font-size: 11px; font-weight: 700; color: var(--fld-brand);
  text-transform: uppercase; letter-spacing: .07em; margin-top: 5px;
}
.fld-ticket-info__num {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12.5px; color: var(--fld-muted2); letter-spacing: 1.5px; margin-top: 8px;
  display: block;
}

/* Error sheet title modifiers — invalid (red) vs dup/already (amber) */
.fld-sheet__title--invalid { color: var(--fld-bad); }
.fld-sheet__title--dup     { color: #b87514; }

/* Dup ticket info card — amber left-border instead of Plum to signal "already used" */
.fld-ticket-info--dup {
  background: #fffbeb; border-left-color: #f59e0b;
}
.fld-ticket-info--dup .fld-ticket-info__tier { color: #b87514; }

/* Confirm sheet action row — 48 px tap-height (Apple HIG / Android material touch spec). */
.fld-scan-confirm__acts { display: flex; gap: 10px; margin-top: 20px; }
.fld-scan-confirm__acts .fld-btn { min-height: 48px; }
.fld-scan-confirm__acts .fld-btn:first-child { flex: 1; }
.fld-scan-confirm__acts .fld-btn--admit { flex: 1.6; min-width: 0; font-size: 15px; }

/* ── Bottom navigation (RBAC-gated tabs) ──────────────────────────────────── */
.fld-bottomnav { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; background: #fff; border-top: 1px solid var(--fld-line);
  padding: 9px 6px calc(22px + env(safe-area-inset-bottom)); }
.fld-tab { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 4px 0; text-decoration: none; color: var(--fld-muted2); font-size: 10px; font-weight: 700;
  position: relative; }
.fld-tab svg { display: block; }
.fld-tab--active { color: var(--fld-brand); }
.fld-tab__badge { position: absolute; top: -3px; left: 50%; margin-left: 5px; min-width: 15px; height: 15px;
  background: var(--fld-bad); color: #fff; border-radius: 99px; font-size: 9.5px; font-weight: 800;
  display: flex; align-items: center; justify-content: center; padding: 0 3px; }

/* ── Toasts (driven by the `toast` HX-Trigger event) ──────────────────────── */
.fld-toasts { position: fixed; left: 16px; right: 16px; bottom: calc(96px + env(safe-area-inset-bottom));
  z-index: 101; display: flex; flex-direction: column; gap: 8px; pointer-events: none; }
.fld-toast { background: var(--fld-ink); color: #fff; border-radius: 14px; padding: 13px 16px;
  font-size: 13.5px; font-weight: 600; box-shadow: 0 16px 36px -12px rgba(0,0,0,.5);
  animation: fld-toast .22s ease; display: flex; align-items: center; gap: 10px; }
.fld-toast__icon { font-weight: 800; }
.fld-toast--good  .fld-toast__icon { color: #5ee3a4; }
.fld-toast--error .fld-toast__icon { color: #ff8d7a; }

/* ── Loader overlay ───────────────────────────────────────────────────────── */
.fld-loader { position: fixed; inset: 0; z-index: 100; background: rgba(250,247,255,.82);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px;
  backdrop-filter: blur(2px); }
.fld-loader[hidden] { display: none; }   /* author rule beats the UA [hidden] default */
.fld-loader__spin { width: 42px; height: 42px; border-radius: 50%; border: 3.5px solid #EDE9FE;
  border-top-color: var(--fld-brand); animation: fld-spin .7s linear infinite; }
.fld-loader__t { font-size: 13.5px; font-weight: 700; color: #6B5E8A; }

/* ── Install banner (Phase 32 — §9.1 FIELD_DESIGN.md) ─────────────────────────
   Snackbar-style "Add to Home Screen" prompt. Android gets a real "Install"
   button wired to the captured beforeinstallprompt event; iOS Safari (no such
   event exists there) gets manual Share-sheet instructions instead. Hidden
   entirely once running standalone — see the script in base_field.html. */
.fld-install {
  position: fixed; left: 12px; right: 12px; z-index: 90;
  bottom: calc(12px + env(safe-area-inset-bottom));
  background: var(--fld-card); border: 1px solid var(--fld-line2);
  border-radius: 18px; box-shadow: var(--fld-shadow-lg);
  padding: 14px 34px 14px 14px; display: flex; align-items: flex-start; gap: 10px;
  animation: fld-toast .22s ease;
}
.fld-install[hidden] { display: none; }
/* Sits above the bottom nav on authenticated pages so it never overlaps the tabs. */
.fld-install--hasnav { bottom: calc(78px + env(safe-area-inset-bottom)); }
.fld-install__icon {
  flex: none; width: 38px; height: 38px; border-radius: 11px;
  background: var(--fld-brand); display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 16px -6px rgba(109,40,217,.55);
}
.fld-install__text { flex: 1; min-width: 0; }
.fld-install__title { font-size: 13.5px; font-weight: 800; color: var(--fld-ink); }
.fld-install__body { font-size: 12px; color: var(--fld-muted); margin-top: 2px; line-height: 1.45; }
.fld-install__cta {
  margin-top: 9px; padding: 8px 16px; min-height: 36px; font-size: 12.5px;
}
.fld-install__close {
  position: absolute; top: 8px; right: 8px; width: 28px; height: 28px;
  border-radius: 50%; border: none; background: var(--fld-tint); color: var(--fld-muted);
  font-size: 13px; line-height: 1; cursor: pointer;
}

/* ── Login (full-screen Plum gradient) ────────────────────────────────────── */
.fld-login { min-height: 100vh; min-height: 100dvh;
  background: radial-gradient(130% 80% at 50% 0%, #7C3AED 0%, #5B21B6 48%, #3B0764 100%);
  display: flex; flex-direction: column;
  /* Top inset was a flat 78px with no env(safe-area-inset-top) — inconsistent
     with .fld-top's calc(14px + env(safe-area-inset-top)) pattern, and the one
     remaining place on this screen a large Dynamic-Island-class inset could
     crowd the brand mark under the notch. Bottom already did this correctly. */
  padding: calc(78px + env(safe-area-inset-top)) 26px calc(30px + env(safe-area-inset-bottom));
  overflow-y: auto;
  /* This div (not <body>) is the actual scroll container on short viewports
     (e.g. the 3-field change-password form) — needs its own overscroll-behavior
     so a bounce at its top/bottom doesn't chain into the page (Phase 32 §9). */
  overscroll-behavior: contain; }
.fld-login__brandwrap { display: flex; flex-direction: column; align-items: center; text-align: center; margin-bottom: 30px; }
.fld-login__mark { width: 88px; height: 88px; border-radius: 24px; background: rgba(255,255,255,.12);
  border: 1px solid rgba(255,255,255,.25); display: flex; align-items: center; justify-content: center; margin-bottom: 16px; }
.fld-login__mark::after { content: ""; width: 24px; height: 24px; border: 3px solid #fff; border-radius: 7px; }
img.fld-login__mark { background: none; border: none; box-shadow: none; object-fit: contain; }
.fld-login__brand { font-size: 26px; font-weight: 800; color: #fff; letter-spacing: -.02em; }
.fld-login__brand .np { color: #DDD6FE; }
.fld-login__kicker { font-size: 13px; font-weight: 600; color: rgba(255,255,255,.62); margin-top: 5px; letter-spacing: .02em; }
.fld-login__card { background: #fff; border-radius: 22px; padding: 22px 20px; box-shadow: 0 30px 60px -24px rgba(0,0,0,.5); }
.fld-login__title { font-size: 18px; font-weight: 800; color: var(--fld-ink); margin-bottom: 2px; }
.fld-login__sub { font-size: 12.5px; color: var(--fld-muted); margin-bottom: 16px; }
.fld-login__form { display: flex; flex-direction: column; }
.fld-login__form .fld-input { margin-bottom: 13px; }
.fld-login__pwd { position: relative; }
.fld-login__pwd .fld-input { padding-right: 58px; }
/* min-height:44px meets the Apple HIG / WCAG 2.5.5 tap-target rule (§9, HARD) —
   was 6px padding (~24px tall). translateY(-50%) keeps it vertically centred on
   the input regardless of its own box height, so this doesn't shift the visible
   "Show"/"Hide" text position. */
.fld-login__eye { font-family: inherit; cursor: pointer; position: absolute; right: 4px; top: 21px;
  transform: translateY(-50%); background: none; border: none; color: var(--fld-accent); font-size: 12px; font-weight: 700;
  padding: 6px 10px; min-height: 44px; min-width: 44px; display: flex; align-items: center; justify-content: center; }
.fld-login__submit { margin-top: 5px; width: 100%; padding: 15px; font-size: 15px; }
.fld-powered {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  margin-top: auto; padding-top: 24px;
}
.fld-powered__row {
  display: flex; align-items: center; justify-content: center; gap: 9px;
}
.fld-powered__label {
  font-size: 11px; font-weight: 700; color: rgba(255,255,255,.7); letter-spacing: .08em; text-transform: uppercase;
}
.fld-powered__logo { height: 26px; width: auto; display: block; }
.fld-login__foot { text-align: center; font-size: 10px; color: rgba(255,255,255,.38); margin-top: 4px; padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
.fld-login .fld-error { margin-bottom: 14px; }
.fld-input--err { border-color: var(--fld-bad) !important; }
.fld-field-err { font-size: 11.5px; color: var(--fld-bad); font-weight: 600; margin: 3px 0 6px; }
.fld-chpw-banner { background: #fef3c7; border: 1px solid #fcd34d; color: #92400e; border-radius: 10px;
  font-size: 12.5px; font-weight: 600; padding: 10px 13px; margin-bottom: 14px; line-height: 1.4; }
/* padding (not just margin) gives this a real ≥44px tap height — was bare text
   with only its own line-height (~18px) clickable, failing the §9 tap-target
   rule. margin-top trimmed 16→3px so the padding addition keeps the same
   ~16px visual gap from the button above. */
.fld-chpw-back { display: block; text-align: center; margin-top: 3px; padding: 13px 0; font-size: 13px; font-weight: 600;
  color: var(--fld-accent); text-decoration: none; }
.fld-chpw-back:hover { text-decoration: underline; }
.fld-login__form .fld-label { margin-top: 0; }
.fld-login__form--busy { opacity: .7; pointer-events: none; }
.fld-label--tight { margin-top: 4px; }
.fld-login__submit--gap { margin-top: 18px; }

/* ── Command dashboard (first tab — live ticketing operations overview) ───────
   Mobile-first single column within .fld-main (640px cap). Palette + type sizes
   follow the design reference, mapped onto the field tokens. */
.fld-cmd-hero {
  background: linear-gradient(135deg, #6D28D9 0%, #8B5CF6 100%);
  border-radius: 18px; padding: 16px 16px 14px; color: #fff;
  margin: 2px 0 16px; box-shadow: var(--fld-shadow);
}
.fld-cmd-hero__row { display: flex; align-items: flex-start; }
.fld-cmd-hero__stat { flex: 1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.fld-cmd-hero__stat--c { align-items: center; text-align: center; }
.fld-cmd-hero__stat--r { align-items: flex-end; text-align: right; }
.fld-cmd-hero__lbl { font-size: 10px; font-weight: 700; letter-spacing: .04em; opacity: .65; }
.fld-cmd-hero__n   { font-size: 26px; font-weight: 800; line-height: 1.05; letter-spacing: -.02em; }
.fld-cmd-hero__bar { height: 5px; border-radius: 99px; background: rgba(255,255,255,.25); margin: 14px 0 5px; overflow: hidden; }
.fld-cmd-hero__fill { height: 100%; border-radius: 99px; background: #fff; }
.fld-cmd-hero__cap { font-size: 10.5px; font-weight: 400; opacity: .65; }

/* Stat cards (Pending / Customer channel / Gate) */
.fld-cmd-card {
  background: var(--fld-card); border: 1px solid var(--fld-line);
  border-radius: 14px; padding: 12px 13px; margin-bottom: 12px;
  display: flex; flex-direction: column; gap: 3px; box-shadow: var(--fld-shadow);
}
.fld-cmd-card__lbl { font-size: 10px; font-weight: 700; letter-spacing: .04em; }
.fld-cmd-card__lbl--ok   { color: var(--fld-ok); }
.fld-cmd-card__lbl--warn { color: var(--fld-warn); }
.fld-cmd-card__lbl--bad  { color: var(--fld-bad); }
.fld-cmd-card__n   { font-size: 22px; font-weight: 800; color: var(--fld-ink); line-height: 1.05; }
.fld-cmd-card__sub { font-size: 10.5px; color: var(--fld-muted2); }
.fld-cmd-card__sub--ok  { color: var(--fld-ok); }
.fld-cmd-card__sub--bad { color: var(--fld-bad); }
.fld-cmd-card--ok  { background: var(--fld-okbg); border-color: #c0e9d4; }
.fld-cmd-card--bad { background: var(--fld-badbg); border-color: #f3d3ce; }

/* 2-up pair (Gate: admitted / cancelled) */
.fld-cmd-pair { display: flex; gap: 8px; margin-bottom: 6px; }
.fld-cmd-pair .fld-cmd-card { flex: 1; margin-bottom: 0; }

/* Field ops card — 3-metric row + distribution bar + footer */
.fld-cmd-fo {
  background: var(--fld-card); border: 1px solid var(--fld-line);
  border-radius: 14px; padding: 13px 14px; margin-bottom: 12px; box-shadow: var(--fld-shadow);
}
.fld-cmd-fo__row { display: flex; }
.fld-cmd-fo__col {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  text-align: center; padding: 0 4px;
}
.fld-cmd-fo__col + .fld-cmd-fo__col { border-left: 1px solid var(--fld-line); }
.fld-cmd-fo__lbl { font-size: 10px; font-weight: 700; letter-spacing: .03em; }
.fld-cmd-fo__lbl--muted { color: var(--fld-muted2); }
.fld-cmd-fo__lbl--ok    { color: var(--fld-ok); }
.fld-cmd-fo__lbl--warn  { color: var(--fld-warn); }
.fld-cmd-fo__n   { font-size: 20px; font-weight: 800; color: var(--fld-ink); line-height: 1.05; }
.fld-cmd-fo__bar { height: 4px; border-radius: 99px; background: var(--fld-tint); margin: 12px 0 8px; overflow: hidden; }
.fld-cmd-fo__fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #6D28D9, #8B5CF6); }
.fld-cmd-fo__foot { display: flex; justify-content: space-between; align-items: center; }
.fld-cmd-fo__pct { font-size: 11px; color: var(--fld-muted2); }

.fld-cmd-foot {
  display: block; text-align: center; margin-top: 10px; padding: 4px;
  font-size: 10.5px; color: var(--fld-faint); text-decoration: none;
}
.fld-cmd-foot:active { color: var(--fld-brand); }

/* Tiers — one card, a row per tier (inventory / demand) */
.fld-cmd-tiers {
  background: var(--fld-card); border: 1px solid var(--fld-line);
  border-radius: 14px; padding: 4px 14px; margin-bottom: 12px; box-shadow: var(--fld-shadow);
}
.fld-cmd-tier { padding: 12px 0; }
.fld-cmd-tier + .fld-cmd-tier { border-top: 1px solid var(--fld-line); }
.fld-cmd-tier__top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.fld-cmd-tier__name { font-size: 14px; font-weight: 800; color: var(--fld-ink); letter-spacing: -.01em;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fld-cmd-tier__price { font-size: 12.5px; font-weight: 700; color: var(--fld-accent); flex-shrink: 0; }
.fld-cmd-tier__bar { height: 5px; border-radius: 99px; background: var(--fld-tint); overflow: hidden; margin-bottom: 7px; }
.fld-cmd-tier__fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, #6D28D9, #8B5CF6); }
.fld-cmd-tier__fill.is-low  { background: var(--fld-warn); }
.fld-cmd-tier__fill.is-full { background: var(--fld-bad); }
.fld-cmd-tier__meta { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.fld-cmd-tier__sold  { font-size: 11.5px; color: var(--fld-muted2); }
.fld-cmd-tier__avail { font-size: 11.5px; font-weight: 700; color: var(--fld-ok); flex-shrink: 0; }
.fld-cmd-tier__tag {
  font-size: 10.5px; font-weight: 800; letter-spacing: .02em; flex-shrink: 0;
  padding: 2px 9px; border-radius: 99px; background: var(--fld-tint); color: var(--fld-accent);
}
.fld-cmd-tier__tag--warn { background: #fdf2e3; color: var(--fld-warn); }
.fld-cmd-tier__tag--bad  { background: var(--fld-badbg); color: var(--fld-bad); }

/* ── Offline fallback page (offline.html) ── */
.off-wrap {
  min-height: 100dvh; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 20px;
  padding: 32px 24px calc(32px + env(safe-area-inset-bottom));
  background: var(--fld-bg); text-align: center;
}
.off-mark {
  width: 72px; height: 72px; border-radius: 20px; background: var(--fld-brand);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.off-mark svg { color: #fff; }
.off-h { font-size: 20px; font-weight: 800; color: var(--fld-ink); letter-spacing: -.01em; margin: 0; }
.off-sub {
  font-size: 14px; font-weight: 600; color: var(--fld-muted);
  margin: 0; max-width: 280px; line-height: 1.5;
}
.off-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--fld-tint); border: 1.5px solid var(--fld-line2);
  border-radius: 100px; padding: 6px 14px;
  font-size: 12px; font-weight: 700; color: var(--fld-muted2);
  letter-spacing: .04em; text-transform: uppercase;
}
.off-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--fld-faint); animation: fld-pulse 1.4s ease-in-out infinite;
}
.off-retry { margin-top: 8px; }
