:root {
  --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
  --text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
  --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --text-lg: clamp(1.125rem, 1rem + 0.75vw, 1.35rem);
  --text-xl: clamp(1.5rem, 1.2rem + 1.25vw, 2.1rem);

  --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem;
  --space-4: 1rem;    --space-5: 1.25rem; --space-6: 1.5rem;
  --space-8: 2rem;    --space-10: 2.5rem;  --space-12: 3rem;

  --color-bg: #f7f4ee;
  --color-surface: #fbf8f3;
  --color-surface-2: #f0e9de;
  --color-surface-accent: #e8ddd1;
  /* More pronounced outline for white fields/cards/buttons on the cream
     background — stronger than the old .11/.15 alphas so the outlines read
     clearly, still soft and short of a hard dark border. Bumped 2026-06-02
     (border25). */
  --color-border: rgba(40,37,29,.25);
  --color-divider: rgba(40,37,29,.08);
  --color-text: #28251d;
  --color-text-muted: #706a63;
  --color-text-faint: #a49d94;
  --color-primary: #1b5b57;
  --color-primary-hover: #144844;
  --color-success: #2f6f4f;
  --color-error: #915041;
  --color-warning: #9b6a1d;

  --shadow-sm: 0 1px 2px rgba(35,28,23,.06), 0 8px 24px rgba(35,28,23,.05);
  --shadow-md: 0 2px 6px rgba(35,28,23,.07), 0 16px 40px rgba(35,28,23,.10);

  --radius-sm: 12px; --radius-md: 18px; --radius-lg: 26px;
  --radius-xl: 32px; --radius-full: 999px;

  --font-display: 'Boska', Georgia, serif;
  --font-body: 'Satoshi', Inter, sans-serif;
  --phone-width: 420px;
}

* { box-sizing: border-box; }
html { -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; }
body {
  margin: 0;
  min-height: 100vh;
  background:
    radial-gradient(circle at top left, rgba(229,219,208,.55), transparent 32%),
    linear-gradient(180deg, #f1ece4 0%, #f8f5ef 52%, #f4efe8 100%);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.55;
}
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
.hidden { display: none !important; }

.auth-gate {
  min-height: 100vh;
  /* When the card is taller than the viewport (long scoped error + the three
     recovery buttons on a small phone), center it but let the page scroll
     instead of clipping the buttons off-screen. align-items:safe center keeps
     the top reachable; overflow-y:auto provides the scroll. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  overflow-y: auto;
  padding: var(--space-8) var(--space-4);
  /* Respect the iPhone home indicator so the last recovery button isn't tucked
     under it. */
  padding-bottom: max(var(--space-8), calc(env(safe-area-inset-bottom) + 24px));
}
/* Neutral splash shown while the saved Supabase session is being restored on
   launch — keeps the login form (and its iOS autofill prompt) from flashing
   before getSession()/refreshSession() resolve. */
.auth-loading {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--space-8) var(--space-4);
}
.auth-loading.hidden { display: none !important; }
.auth-loading-card {
  display: grid;
  justify-items: center;
  gap: 16px;
  color: var(--color-text-muted);
}
.auth-loading-spinner {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary, #1b5b57);
  animation: auth-loading-spin 0.8s linear infinite;
}
.auth-loading-text { margin: 0; font-size: 14px; }
@keyframes auth-loading-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .auth-loading-spinner { animation: none; }
}
.auth-card {
  width: min(100%, 430px);
  display: grid;
  gap: 16px;
  padding: 28px;
  border-radius: var(--radius-xl);
  background: linear-gradient(180deg, rgba(255,255,255,.82), rgba(244,238,230,.95));
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
}
.auth-logo { width: 54px; height: 54px; }
.auth-card h1 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--text-xl);
  line-height: 1.04;
  letter-spacing: -.02em;
}
.auth-card p { margin: 0; color: var(--color-text-muted); }
.auth-form { display: grid; gap: 10px; }
.auth-form label {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--color-text-muted);
}
.auth-form input {
  width: 100%;
  min-height: 48px;
  border-radius: 16px;
  border: 1px solid var(--color-border);
  background: rgba(255,255,255,.78);
  padding: 11px 13px;
}
.password-field { position: relative; display: block; }
/* Leave room so typed/masked characters never slide under the toggle. */
.password-field input { padding-right: 68px; }
.password-toggle {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  /* Sit above the input so iOS routes the tap to the button, not the field
     underneath, and make sure taps are never swallowed. */
  z-index: 2;
  pointer-events: auto;
  touch-action: manipulation;
  min-height: 36px;
  padding: 0 12px;
  border: 1px solid var(--color-border);
  border-radius: 12px;
  background: var(--color-surface-2);
  color: var(--color-text-muted);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.password-toggle:hover { color: var(--color-text); }
.password-toggle[aria-pressed="true"] {
  background: var(--color-surface);
  color: var(--color-text);
}
.password-field input[hidden] + .password-toggle { display: none; }
.auth-status {
  min-height: 20px;
  font-size: 13px;
  color: var(--color-text-muted);
}
.auth-status[data-tone="ok"] { color: var(--color-success); }
.auth-status[data-tone="error"] { color: var(--color-error); }
.auth-status[data-tone="warn"] { color: #7d5920; font-weight: 500; }
/* Retry / Sign out escape hatch shown when the post-login workspace boot
   fails or times out, so staff are never stuck on an infinite loading line. */
.auth-recovery {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}
.auth-recovery.hidden { display: none; }
.auth-recovery .action-btn,
.auth-recovery .soft-btn { flex: 1 1 40%; }
/* The clear-cache escape hatch carries long text; give it its own full-width
   row beneath Retry / Sign out so nothing truncates on a narrow phone. */
.auth-recovery #authClearCacheBtn { flex-basis: 100%; }
/* Copy-diagnostics shares the full-width row treatment so the label never
   truncates on a phone. */
.auth-recovery #authCopyDiagnosticsBtn { flex-basis: 100%; }
/* Monospace, scrollable diagnostics block. Only shown on a failed boot. */
.auth-diagnostics {
  margin: 10px 0 0;
  padding: 10px 12px;
  max-height: 180px;
  overflow: auto;
  text-align: left;
  white-space: pre-wrap;
  word-break: break-word;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
  line-height: 1.45;
  color: var(--color-text-muted);
  background: rgba(0, 0, 0, 0.04);
  border: 1px solid var(--color-border, rgba(0, 0, 0, 0.1));
  border-radius: 8px;
}
.auth-diagnostics.hidden { display: none; }
#captureStatus { margin-top: 4px; }
#captureStatus:empty { display: none; }

/* Stripe payment-link feedback. Without distinct tone colors the status text
   looked identical whether the call was pending, succeeded, or failed, so the
   button felt unresponsive. */
.stripe-status {
  min-height: 20px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
}
.stripe-status[data-tone="info"] { color: var(--color-primary); }
.stripe-status[data-tone="ok"] { color: var(--color-success); }
.stripe-status[data-tone="error"] { color: var(--color-error); }
.stripe-status[data-tone="info"]::before {
  content: "";
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-right: 6px;
  vertical-align: -1px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: stripe-spin 0.7s linear infinite;
}
@keyframes stripe-spin { to { transform: rotate(360deg); } }

.stripe-result {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-top: var(--space-2);
}
.stripe-result.hidden { display: none; }
.stripe-result-url {
  flex: 1 1 220px;
  min-width: 0;
  font-size: 12px;
  padding: 6px 8px;
  border: 1px solid var(--color-border, #ccc);
  border-radius: 6px;
  background: var(--color-surface, #fff);
  color: var(--color-text, #222);
}
.stripe-result-actions { display: flex; gap: var(--space-2); }

.shell {
  width: min(100%, 1560px);
  margin: 0 auto;
  padding: var(--space-8) var(--space-4) var(--space-10);
  display: grid;
  gap: var(--space-8);
  grid-template-columns: minmax(320px, var(--phone-width)) minmax(360px, 1fr);
  align-items: start;
}
.phone {
  background: #111;
  border-radius: 40px;
  padding: 12px;
  box-shadow: 0 30px 80px rgba(26,20,16,.22);
  position: sticky;
  top: 18px;
}
.screen {
  height: min(820px, calc(100vh - 36px));
  min-height: 680px;
  background: var(--color-bg);
  border-radius: 30px;
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
}
.statusbar {
  display:flex; justify-content:space-between; align-items:center;
  padding: 14px 20px 6px;
  font-size: 12px;
  color: var(--color-text-muted);
}
.header {
  display:flex; justify-content:space-between; align-items:flex-start;
  padding: 10px 20px 16px;
  gap: 12px;
}
.header-compact {
  justify-content: flex-end;
  padding-top: 4px;
  padding-bottom: 12px;
}
.header-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: flex-end;
}
.header-actions .pill {
  max-width: 128px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.brand { display:flex; gap: 12px; align-items:center; }
.brand-mark {
  width: 42px; height: 42px; border-radius: 50%;
  background: rgba(255,255,255,.7);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
  display:grid; place-items:center;
  color: var(--color-text);
}
.brand-mark svg { width: 20px; height: 20px; }
.eyebrow {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--color-text-muted);
}
.header-copy strong { display:block; font-size: var(--text-sm); }
.header-copy span { font-size: 12px; color: var(--color-text-muted); }
.icon-btn {
  width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid var(--color-border);
  background: rgba(255,255,255,.72);
  display:grid; place-items:center;
  box-shadow: var(--shadow-sm);
}

.screen-body {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  padding: 0 20px 170px;
}
.screen.no-bottom-bar .screen-body {
  padding-bottom: 20px;
}
/* Guest Receipts dashboard: the bottom tray here is a single row of side-by-side
   buttons (shorter than the stacked trays on other views), so reserve less bottom
   clearance and hand the reclaimed height to the scrolling booking list. */
.screen-body:has(#view-bookings:not(.hidden)) {
  padding-bottom: calc(96px + env(safe-area-inset-bottom));
}
.view:not(.hidden) {
  height: 100%;
  min-height: 0;
  overflow-y: auto;
  display: grid;
  gap: 10px;
  align-content: start;
  padding-bottom: 12px;
}
/* Send/report view: the bottom bar is taller here (step nav + the stacked
   Generate Payment Link / Send Invoice to Guest controls + status lines), so
   give the scroll content extra clearance to keep content above the fixed
   controls. */
#view-report:not(.hidden) {
  padding-bottom: calc(120px + env(safe-area-inset-bottom));
}
/* Guest Receipts dashboard scroll model — SINGLE scroller.
   The whole view scrolls as one column: the summary bubbles + Upcoming/Past
   toggle scroll away and the booking list comes fully into view, with the
   heading pinned (position:sticky) at the top. The booking list itself is a
   plain block (NOT an inner scroll container), so we never get the trapped
   inner-scroll bug where a tall summary section squeezes the list into a 24px
   sliver behind the fixed bottom bar — the "where are the damn guests?"
   regression. We use flex-column (not the generic .view grid) so layout is
   immune to the desktop-capture-hint child being display:none on mobile and
   display:block on desktop. padding-bottom clears the fixed action bar +
   home-indicator safe area so the last card can scroll above the footer. */
#view-bookings:not(.hidden) {
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding-bottom: calc(96px + env(safe-area-inset-bottom));
}
#view-bookings:not(.hidden) #bookingList {
  /* Grow to fit all cards and scroll with the view as one column. flex-shrink:0
     so the list keeps its natural content height instead of being squeezed. */
  flex: 0 0 auto;
  min-height: 0;
}
#bookingList {
  overflow-y: visible;
  /* The selected card draws a 2px outline OUTSIDE its border box. Pad all sides
     by >= the outline width so the green selected outline isn't clipped. */
  padding: 3px 4px;
  align-content: start;
}

.page-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 25px;
  line-height: 1.02;
  letter-spacing: -.02em;
  max-width: none;
  margin: 0;
  white-space: nowrap;
}
.booking-heading {
  position: sticky;
  top: 0;
  z-index: 4;
  gap: 3px;
  padding: 2px 0 8px;
  background: linear-gradient(180deg, var(--color-bg) 0%, rgba(247,244,238,.94) 72%, rgba(247,244,238,0) 100%);
}
.booking-heading .eyebrow {
  font-size: 13px;
  letter-spacing: .22em;
  color: var(--color-text);
}
.booking-heading.with-back {
  padding-top: 4px;
}

/* Manual "Sync to CRM" control — a small green pill at the top of Guest
   Receipts Page 1, plus an inline status line. Styled to match the app's deep
   green accent rather than competing with the bottom primary action bar. */
.crm-sync-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin: -2px 0 10px;
}
.crm-sync-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 16px;
  border: 1px solid var(--color-primary);
  border-radius: 999px;
  background: var(--color-primary);
  color: #f6f2eb;
  font-size: 14px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background .15s ease, opacity .15s ease;
}
.crm-sync-btn:hover { background: var(--color-primary-hover); }
.crm-sync-btn:disabled,
.crm-sync-btn[data-state="running"] {
  opacity: .7;
  cursor: progress;
}
.crm-sync-btn[data-state="done"] {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
}
.crm-sync-status {
  font-size: 13px;
  color: var(--color-muted, var(--color-text));
}
.crm-sync-status[data-tone="ok"] { color: var(--color-primary); }
.crm-sync-status[data-tone="warn"] { color: #7d5920; font-weight: 500; }
.crm-sync-status[data-tone="error"] { color: #b3261e; }
.back-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  margin: 0 0 6px -6px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform .15s ease, background .15s ease;
  -webkit-tap-highlight-color: transparent;
}
.back-chevron:hover { background: #f1ede5; }
.back-chevron:active { transform: scale(.94); }
.back-chevron:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 2px;
}
.lede { color: var(--color-text-muted); font-size: var(--text-sm); max-width: 34ch; margin: 0; }

.hero-card, .card, .pdf-sheet {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
}
.hero-card {
  padding: 10px 12px;
  border-radius: 22px;
  display:grid; gap:8px;
  background: linear-gradient(180deg, rgba(255,255,255,.78), rgba(244,238,230,.95));
}
.card-title { font-size: 15px; }
.hero-stat-grid { display:grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.hero-stat {
  padding: 8px 10px;
  border-radius: 16px;
  background: rgba(255,255,255,.7);
  border: 1px solid var(--color-border);
}
.hero-stat span { display:block; font-size: 11px; color: var(--color-text-muted); }
.hero-stat strong { display:block; font-size: 18px; margin-top: 1px; line-height: 1; }

.hero-stat-btn,
.mini-stat-btn {
  appearance: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
  position: relative;
  transition: transform 80ms ease, box-shadow 80ms ease, border-color 80ms ease;
}
.hero-stat-btn:hover,
.mini-stat-btn:hover {
  border-color: var(--color-accent);
}
.hero-stat-btn:active,
.mini-stat-btn:active { transform: scale(.98); }
.hero-stat-btn[aria-expanded="true"],
.mini-stat-btn[aria-expanded="true"] {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 1px var(--color-accent) inset;
}
.hero-stat-btn::after,
.mini-stat-btn::after {
  content: "›";
  position: absolute;
  top: 6px;
  right: 9px;
  font-size: 12px;
  line-height: 1;
  color: var(--color-text-muted);
  transition: transform 120ms ease;
}
.hero-stat-btn[aria-expanded="true"]::after,
.mini-stat-btn[aria-expanded="true"]::after { transform: rotate(90deg); color: var(--color-accent); }

.glance-panel {
  margin-top: 2px;
  border-radius: 16px;
  background: rgba(255,255,255,.78);
  border: 1px solid var(--color-border);
  padding: 10px 12px;
  display: grid;
  gap: 8px;
  box-shadow: var(--shadow-sm);
}
.glance-panel.hidden { display: none; }
.glance-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.glance-head strong {
  font-size: 13px;
  line-height: 1.2;
}
.glance-head .meta { font-size: 11px; }
.glance-close {
  appearance: none;
  border: 1px solid var(--color-border);
  background: rgba(255,255,255,.85);
  color: var(--color-text-muted);
  border-radius: 999px;
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}
.glance-close:hover { color: var(--color-text); border-color: var(--color-accent); }
.glance-list {
  display: grid;
  gap: 6px;
  max-height: 280px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-right: 2px;
}
.glance-item {
  display: grid;
  grid-template-columns: 1fr auto;
  column-gap: 8px;
  row-gap: 2px;
  padding: 8px 10px;
  border-radius: 12px;
  background: rgba(251,248,243,.92);
  border: 1px solid var(--color-border);
}
/* Tappable guest receipt / invoice rows: button reset + selectable affordance,
   while keeping the exact card layout of the inert .glance-item. */
.glance-item--actionable {
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  align-items: center;
  transition: border-color .15s ease, background .15s ease, transform .05s ease;
  -webkit-appearance: none;
  appearance: none;
}
.glance-item--actionable:hover {
  border-color: var(--color-accent);
  background: rgba(27,91,87,.06);
}
.glance-item--actionable:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.glance-item--actionable:active { transform: scale(.995); }
.glance-item-vendor {
  font-weight: 600;
  font-size: 13px;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.glance-item-amount {
  font-weight: 600;
  font-size: 13px;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.glance-item-meta {
  font-size: 11px;
  color: var(--color-text-muted);
  line-height: 1.25;
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  align-items: center;
}
.glance-item-tag {
  display: inline-block;
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(27,91,87,.10);
  color: var(--color-accent);
  font-size: 10px;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-weight: 600;
}
.glance-item-tag.warn { background: rgba(183,126,72,.18); color: #8a5a2b; }
.glance-item-tag.muted { background: rgba(0,0,0,.06); color: var(--color-text-muted); }
/* Owner Related pill — distinct deep-green chip, shown only when the flag is true. */
.glance-item-tag.owner { background: rgba(47,111,79,.16); color: #2f6f4f; }
.glance-empty {
  text-align: center;
  padding: 18px 12px 16px;
  color: var(--color-text-muted);
  font-size: 12px;
  display: grid;
  gap: 6px;
  justify-items: center;
}
.glance-empty-emoji {
  font-size: 22px;
  line-height: 1;
}
.glance-empty strong {
  font-size: 13px;
  color: var(--color-text);
}

.management-hero {
  margin-top: 2px;
}
.choice-card {
  position: relative;
  appearance: none;
  text-align: left;
  display: grid;
  gap: 4px;
  width: 100%;
  padding: 13px 15px;
  border-radius: 20px;
  border: 1px solid var(--color-border);
  background:
    linear-gradient(135deg, rgba(27,91,87,.08), transparent 50%),
    rgba(255,255,255,.78);
  color: var(--color-text);
  box-shadow: var(--shadow-sm);
}
.choice-card strong {
  font-size: 18px;
  line-height: 1.1;
}
.choice-card span:last-child {
  color: var(--color-text-muted);
  font-size: 13px;
  line-height: 1.4;
}
/* Locked workflow: only a small lock glyph at the upper-right corner — no
   verbose "protected" classification label. Reserve room so the glyph never
   overlaps a long title. */
.choice-card-locked strong { padding-right: 22px; }
.choice-lock {
  position: absolute;
  top: 12px;
  right: 13px;
  display: inline-flex;
  color: var(--color-text-muted);
}
.home-logout-btn {
  margin-top: 18px;
  width: 100%;
}
.scan-toast {
  border-radius: 18px;
  padding: 14px 16px;
  background: rgba(27,91,87,.95);
  color: #fffaf0;
  font-weight: 700;
  text-align: center;
  box-shadow: var(--shadow-md);
}

.unbilled-card {
  background:
    linear-gradient(135deg, rgba(27,91,87,.08), transparent 48%),
    rgba(251,248,243,.92);
}
.drive-preview {
  background:
    linear-gradient(135deg, rgba(183,126,72,.10), transparent 52%),
    rgba(251,248,243,.92);
}
.mini-stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
}
.mini-stat {
  padding: 8px 7px;
  border-radius: 15px;
  background: rgba(255,255,255,.72);
  border: 1px solid var(--color-border);
}
.mini-stat span {
  display: block;
  font-size: 10px;
  line-height: 1.15;
  color: var(--color-text-muted);
}
.mini-stat strong {
  display: block;
  margin-top: 2px;
  font-size: 18px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.segmented {
  display:flex; gap:8px; padding: 6px; border-radius: var(--radius-full);
  border:1px solid var(--color-border); background: rgba(255,255,255,.66);
}
.segmented button {
  flex:1; border:none; background: transparent; color: var(--color-text-muted);
  border-radius: var(--radius-full); padding: 10px 12px; min-height: 42px;
  transition: background .18s ease, color .18s ease;
}
.segmented button.active { background: var(--color-text); color: #f6f2eb; }

/* Upcoming/Past toggle above the Guest Receipts list. Compact, teal selected
   state, soft rounded container — consistent with the SAVINA mobile UI and
   distinct from the dark-fill base .segmented used elsewhere. */
.booking-filter-toggle { gap: 6px; padding: 4px; margin: 0 0 2px; }
.booking-filter-toggle button {
  min-height: 36px; padding: 8px 10px; font-size: 13px; font-weight: 600;
}
.booking-filter-toggle button.active {
  background: var(--color-primary); color: #f6f2eb;
}

.card { border-radius: 22px; padding: 11px 12px; display:grid; gap: 8px; }
.booking-card {
  width: 100%;
  align-self: start;
  border: 1px solid var(--color-border);
  transition: outline-color .18s ease, transform .18s ease;
}
.booking-card.active { outline: 2px solid rgba(27,91,87,.28); background: linear-gradient(180deg, #fffdf9, #f7f1e8); }
/* Selected booking card mirrors the "current step" treatment in the bottom
   nav: light green fill with primary-color text, primary-color outline. */
.booking-card.selected {
  background: rgba(27,91,87,.1);
  border-color: var(--color-primary);
  outline: 2px solid rgba(27,91,87,.45);
  color: var(--color-primary);
}
.booking-card.selected strong,
.booking-card.selected .booking-code,
.booking-card.selected .meta { color: var(--color-primary); }
.booking-card.selected .pill {
  background: rgba(255,255,255,.7);
  color: var(--color-primary);
}

.booking-select-instruction {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .01em;
}
.booking-card-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}
.booking-card-top strong {
  font-size: 15px;
  line-height: 1.2;
}
.booking-code {
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* Step-3 header guest bubble: a distinct soft-rounded card for the primary
   guest. Name (with the "N selected" pill) sits on top; the booking code
   (no "PMS" label) is left-aligned on the next row with the stay dates pushed
   to the right edge. Mirrors the first-page booking card's visual language —
   including its SELECTED-state green treatment, since this bubble always
   represents the one booking the user picked: light green fill, primary-color
   outline + border, and primary-color text. */
.guest-bubble {
  display: grid;
  gap: 4px;
  padding: 10px 12px;
  border-radius: 16px;
  background: rgba(27,91,87,.1);
  border: 1px solid var(--color-primary);
  outline: 2px solid rgba(27,91,87,.45);
  outline-offset: -1px;
  box-shadow: 0 1px 4px rgba(27,91,87,.12);
  color: var(--color-primary);
}
.guest-bubble-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.guest-bubble-top strong {
  font-size: 16px;
  line-height: 1.2;
  overflow-wrap: anywhere;
  color: var(--color-primary);
}
.guest-bubble .pill {
  background: rgba(255,255,255,.7);
  color: var(--color-primary);
}
.guest-bubble-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.guest-bubble-meta .booking-code,
.guest-bubble-meta .meta {
  font-size: 12px;
  color: var(--color-primary);
}
.guest-bubble-meta .meta {
  flex: 0 0 auto;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Compact stacked layout used by every booking card; the selected card
   emphasizes the chip column with vertical stacking, while non-selected
   cards keep a tighter footprint and let chips wrap on the right. */
.booking-card-body {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: start;
}
.booking-card-left {
  display: grid;
  gap: 4px;
  text-align: left;
  min-width: 0;
}
.booking-card-left strong {
  font-size: 15px;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.booking-card-left .meta {
  font-size: 12px;
  line-height: 1.25;
  font-variant-numeric: tabular-nums;
}
.booking-card-left .booking-code {
  font-size: 12px;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}
@media (max-width: 380px) {
  .booking-card-body { gap: 8px; }
  .booking-card-left strong { font-size: 14px; }
  .booking-card-left .meta { font-size: 11px; }
  .booking-card-chips { min-width: 118px; }
}
/* Read-only Calendar list cards. Reuse the booking-card surface but render the
   guest info as a single left-aligned stack with a teal Registration affordance
   underneath. The card itself is the tap target (an <a> opening registration). */
.calendar-card {
  display: block;
  text-decoration: none;
  color: inherit;
  position: relative;
}
/* Leave room at the bottom right so the channel badge never overlaps the
   Registration link / booking code on the narrowest mobile cards. */
.calendar-card .booking-card-left { gap: 5px; padding-right: 64px; }

/* Small booking-channel badge pinned to the bottom right of a Calendar card.
   Compact, non-interactive, and absolutely positioned so it does not reflow the
   guest name / dates / code stack. Colour-coded per channel but kept muted to
   preserve the warm cream + deep green look. */
.calendar-channel-badge {
  position: absolute;
  right: 12px;
  bottom: 12px;
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  line-height: 1.4;
  border: 1px solid transparent;
  pointer-events: none;
}
.calendar-channel-badge.channel-airbnb { background: #ffe9ec; color: #c0395a; border-color: #f6c9d2; }
.calendar-channel-badge.channel-vrbo { background: #e4eefb; color: #1f5fa6; border-color: #c5dbf3; }
.calendar-channel-badge.channel-savina { background: #e7f0ec; color: var(--color-primary); border-color: #c7ddd3; }

/* Single-letter channel chip on the dense Month-view stay bar. Sits flush to
   the bar's right edge, after the label/continuation arrow. */
.calendar-bar-channel {
  flex: 0 0 auto;
  margin-left: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 13px;
  height: 13px;
  padding: 0 3px;
  border-radius: 3px;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  background: rgba(255, 255, 255, .85);
  color: var(--color-primary);
}
.calendar-bar-channel.channel-airbnb { color: #c0395a; }
.calendar-bar-channel.channel-vrbo { color: #1f5fa6; }
.calendar-bar-channel.channel-savina { color: var(--color-primary); }
.calendar-reg-link {
  margin-top: 4px;
  font-size: 12px;
  font-weight: 600;
  color: var(--color-primary);
  letter-spacing: .01em;
}
.calendar-card:active { transform: scale(.99); }

/* List/Month toggle on the Guest Calendar — matches the Upcoming/Past toggle. */
.calendar-view-toggle { gap: 6px; padding: 4px; margin: 0 0 4px; }
.calendar-view-toggle button {
  min-height: 36px; padding: 8px 10px; font-size: 13px; font-weight: 600;
}
.calendar-view-toggle button.active {
  background: var(--color-primary); color: #f6f2eb;
}

/* Read-only Month grid. Warm cream surface + deep green accents, consistent
   with the SAVINA card look. A Sun–Sat 7-column grid; each stay is drawn as a
   horizontal bar spanning its reservation dates (rather than a label repeated
   in every day), with half-day insets at check-in/out and continuation arrows
   when a stay crosses week rows. Bars link to guest registration. */
.calendar-month { display: grid; gap: 10px; }
.calendar-month.hidden { display: none; }

/* Prev / This month / Next navigation. */
.calendar-month-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
}
.calendar-month-nav strong {
  font-size: 16px;
  letter-spacing: .01em;
  min-width: 9.5em;
  text-align: center;
}
.calendar-month-navbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: #fffdf9;
  color: var(--color-primary);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.calendar-month-navbtn:active { transform: scale(.94); }
.calendar-month-hint {
  text-align: center;
  font-size: 12px;
  color: var(--color-text-muted);
}

.calendar-month-grid {
  position: relative;
  border: 1px solid var(--color-border);
  border-radius: 16px;
  padding: 8px;
  background: rgba(255,255,255,.66);
}
.calendar-month-dows {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}
.calendar-month-dow {
  text-align: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--color-text-muted);
  padding: 2px 0 4px;
  text-transform: uppercase;
  letter-spacing: .04em;
}
/* Row geometry is shared between the day-cell grid and the bar overlay so the
   per-row strips line up exactly with the cell rows underneath. --cal-row-h is
   tall enough to hold the day number plus up to --cal-lanes stacked stay bars;
   --cal-row-gap matches the grid gap so the strip `top` offsets land on each
   row. */
.calendar-month-body {
  position: relative;
  --cal-row-gap: 4px;
  --cal-bar-h: 18px;
  --cal-bar-gap: 4px;
  --cal-bar-top: 22px;
  --cal-row-h: calc(var(--cal-bar-top) + max(var(--cal-lanes, 1), 1) * (var(--cal-bar-h) + var(--cal-bar-gap)) + 2px);
}
.calendar-month-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: var(--cal-row-h);
  gap: var(--cal-row-gap);
}
.calendar-month-cell {
  border-radius: 10px;
  padding: 4px;
  background: #fffdf9;
  border: 1px solid var(--color-border);
  overflow: hidden;
}
.calendar-month-cell.is-pad { background: rgba(255,255,255,.35); }
.calendar-month-cell.is-today {
  border-color: var(--color-primary);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}
.calendar-month-daynum { font-size: 12px; font-weight: 600; color: var(--color-text-muted); }
.calendar-month-cell.is-pad .calendar-month-daynum { opacity: .45; }
.calendar-month-cell.is-today .calendar-month-daynum { color: var(--color-primary); }

/* Bars overlay sits on top of the day-cell grid. It is NOT a grid itself — each
   stay segment is positioned by percentage across a full-width week-row strip
   (.calendar-month-barrow) so a bar spans the entire stay continuously rather
   than being clipped to individual day cells. The layer passes pointer events
   through; the bars re-enable clicks. */
.calendar-month-bars {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
/* One strip per week row, the full width of the grid, positioned at the row's
   top via the inline `top` offset (row index * (row height + row gap)). Bars
   inside use left/width percentages of THIS strip = of the whole 7-day row. */
.calendar-month-barrow {
  position: absolute;
  left: 0;
  right: 0;
  height: var(--cal-row-h);
}
.calendar-bar {
  position: absolute;
  top: calc(var(--cal-bar-top) + var(--bar-lane, 0) * (var(--cal-bar-h) + var(--cal-bar-gap)));
  /* left + width are set inline as % of the full row. The 2px horizontal inset
     keeps adjacent/continuing bars from touching the cell edges. */
  margin: 0 2px;
  box-sizing: border-box;
  height: var(--cal-bar-h);
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 0 6px;
  border-radius: 5px;
  background: var(--color-primary);
  color: #f6f2eb;
  font-size: 11px;
  line-height: 1;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  pointer-events: auto;
}
.calendar-bar.is-checkin { border-top-left-radius: 9px; border-bottom-left-radius: 9px; }
.calendar-bar.is-checkout { border-top-right-radius: 9px; border-bottom-right-radius: 9px; }
.calendar-bar-label {
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1 1 auto;
  min-width: 0;
}
.calendar-bar-arrow { font-size: 8px; line-height: 1; opacity: .9; flex: 0 0 auto; }
.calendar-bar-arrow.is-right { margin-left: auto; }
a.calendar-bar:active { transform: scale(.99); filter: brightness(1.05); }
/* Both selected and non-selected booking cards use the same stacked chip
   column on the right. Non-selected cards keep the neutral .pill treatment
   while selected cards use the green metric-chip styling, but the geometry
   stays consistent so cards don't shift when selection changes. */
.booking-card-chips {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: stretch;
  justify-content: flex-start;
  flex: 0 0 auto;
  min-width: 130px;
}
.booking-card-chips .pill,
.booking-card-chips .metric-chip {
  justify-content: center;
  white-space: nowrap;
  width: 100%;
}

.row { display:flex; justify-content:space-between; gap: 12px; align-items:flex-start; }
/* Compact inline settings rows: a label on the left and a token-styled select
   on the right, kept on one line and reusing the .field select look. */
.row > label { align-self:center; }
.row select {
  min-height: 40px; border-radius: 14px; border: 1px solid var(--color-border);
  background: rgba(255,255,255,.76); padding: 8px 12px; text-align: right;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.row select:focus {
  outline: none; border-color: rgba(27,91,87,.45); box-shadow: 0 0 0 3px rgba(27,91,87,.12);
}
/* Tap-to-edit exchange-rate control. The display button looks like the plain
   <strong> rate it replaces but signals it's interactive (subtle underline);
   the numeric input takes its place while editing. */
.fx-rate-row { align-items: center; }
.fx-rate-control { display: inline-flex; align-items: center; }
.fx-rate-display {
  appearance: none; border: none; background: none; padding: 2px 4px; margin: 0;
  cursor: pointer; color: inherit; font: inherit; line-height: 1.2;
  border-bottom: 1px dashed rgba(27,91,87,.45); border-radius: 4px;
  transition: background-color .18s ease, border-color .18s ease;
}
.fx-rate-display:hover { background: rgba(27,91,87,.08); }
.fx-rate-display:focus-visible {
  outline: none; box-shadow: 0 0 0 3px rgba(27,91,87,.18);
}
.fx-rate-display strong { font-size: 17px; }
.fx-rate-display.fx-rate-overridden strong { color: var(--color-primary, #1b5b57); }
.fx-rate-display.fx-rate-overridden { border-bottom-style: solid; }
.fx-rate-input {
  min-height: 40px; width: 6.5rem; border-radius: 14px;
  border: 1px solid var(--color-border); background: rgba(255,255,255,.92);
  padding: 8px 12px; text-align: right; font: inherit;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.fx-rate-input:focus {
  outline: none; border-color: rgba(27,91,87,.45); box-shadow: 0 0 0 3px rgba(27,91,87,.12);
}
.stack { display:grid; gap: 4px; }
.stack strong { font-size: 17px; }
.meta { color: var(--color-text-muted); font-size: 13px; }

.pill {
  display:inline-flex; align-items:center; gap:6px;
  background: var(--color-surface-2);
  color: var(--color-text-muted);
  border-radius: var(--radius-full);
  padding: 5px 9px;
  font-size: 11px;
  white-space: nowrap;
}
.pill.dark { background: var(--color-text); color: #f7f4ee; }
/* "Live mode" pill on the Guest Receipts dashboard — green/teal shaded so it
   matches the invoicing section's selected-bubble pill instead of the dark
   utility fill. Soft green wash, primary-color text + subtle outline. */
.pill.live {
  background: rgba(27,91,87,.12);
  color: var(--color-primary);
  box-shadow: inset 0 0 0 1px rgba(27,91,87,.35);
}
.pill.success { background: #edf4ef; color: #275239; }
.pill.warning { background: #f5efe2; color: #7d5920; }
.pill.error { background: #f5e9e5; color: #7a4337; }
.inline-pills { display:flex; gap:6px; flex-wrap:wrap; }

/* Booking metric chips — interactive pills on the selected booking card.
   Stronger green outline + bolder weight signal they're tappable. Non-selected
   cards keep the subdued static .pill treatment. */
.booking-card.selected .metric-chip {
  background: #fff;
  color: var(--color-primary);
  border: 1.5px solid var(--color-primary);
  font-weight: 700;
  cursor: pointer;
  padding: 5px 11px;
  letter-spacing: .01em;
  transition: background .14s ease, transform .14s ease, box-shadow .14s ease;
  box-shadow: 0 1px 0 rgba(27,91,87,.08);
}
.booking-card.selected .metric-chip:hover,
.booking-card.selected .metric-chip:focus-visible {
  background: var(--color-primary);
  color: #fff;
  outline: none;
}
.booking-card.selected .metric-chip:active { transform: translateY(1px); }
.booking-card.selected .metric-chip .metric-chip-count {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.booking-card.selected .metric-chip[data-empty="true"] {
  opacity: .7;
}

/* Unpaid-invoices alert badge — a red flag under the booking code, distinct
   from the neutral stat bubbles. On the selected card it becomes tappable and
   opens the Invoices-Sent popup filtered to unpaid rows. */
.unpaid-alert-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  justify-self: start;
  width: fit-content;
  max-width: 100%;
  margin-top: 4px;
  background: #f5e3df;
  color: var(--color-error);
  border: 1px solid #e3b8af;
  border-radius: var(--radius-full);
  padding: 3px 9px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .01em;
  white-space: nowrap;
}
.unpaid-alert-count { font-variant-numeric: tabular-nums; font-weight: 800; }
.booking-card.selected .unpaid-alert-badge {
  cursor: pointer;
  transition: background .14s ease, transform .14s ease;
}
.booking-card.selected .unpaid-alert-badge:hover,
.booking-card.selected .unpaid-alert-badge:focus-visible {
  background: var(--color-error);
  color: #fbf3ee;
  outline: none;
}
.booking-card.selected .unpaid-alert-badge:active { transform: translateY(1px); }

/* Step-3 unpaid invoice row: a compact, tappable invoice card (opens the View /
   Mark Paid / Delete action sheet modal) with Sent and Unpaid status pills. */
.unpaid-invoice-trigger {
  display: flex; flex-direction: column; gap: 4px; width: 100%;
  background: none; border: none; padding: 0; margin: 0;
  text-align: left; cursor: pointer; color: inherit;
}
.unpaid-invoice-line {
  display: flex; align-items: center; gap: 8px;
  justify-content: space-between;
}
.unpaid-invoice-id { font-size: 14px; }
.unpaid-invoice-status {
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap;
  justify-content: flex-end;
}

/* Stripe webhook-health banner in the Unpaid Invoices popup. Warns when local
   data suggests payments may not be auto-marking invoices paid. */
.stripe-health-banner {
  margin: 4px 0 2px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.35;
}
.stripe-health-banner[data-level="warning"] {
  background: #fdf2e3;
  border: 1px solid #e6c489;
  color: #7d5920;
}
.stripe-health-banner[data-level="healthy"] {
  background: #eef7ee;
  border: 1px solid #bcdcbc;
  color: #2f6b32;
}
/* Inline status line for the Sync-with-Stripe action. */
.metric-sync-status {
  margin: 2px 0;
  min-height: 18px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
}
.metric-sync-status[data-tone="info"] { color: var(--color-primary); }
.metric-sync-status[data-tone="ok"] { color: var(--color-success); }
.metric-sync-status[data-tone="warn"] { color: #7d5920; }
.metric-sync-status[data-tone="error"] { color: var(--color-error); }
.metric-detail-list {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 320px; overflow-y: auto;
  margin-top: 4px;
}
.metric-detail-row {
  display: flex; flex-direction: column; gap: 2px;
  border: 1px solid var(--color-border);
  background: var(--color-surface-2);
  border-radius: var(--radius-md);
  padding: 10px 12px;
}
/* The whole row header is a tap target that expands the row's actions. */
.metric-detail-trigger {
  display: flex; flex-direction: column; gap: 2px;
  width: 100%;
  background: none; border: none; padding: 0; margin: 0;
  text-align: left; cursor: pointer; color: inherit;
}
.metric-detail-top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.metric-detail-vendor { font-weight: 700; color: var(--color-text); }
.metric-detail-amount { font-weight: 700; color: var(--color-text); font-variant-numeric: tabular-nums; }
.metric-detail-meta { color: var(--color-text-muted); font-size: .82rem; }
/* Unbilled receipt rows are a single tappable trigger: info on the left, amount
   on the right. Tapping opens the receipt action sheet (Edit / Delete / Close). */
.metric-detail-row--receipt { flex-direction: row; align-items: stretch; }
.metric-detail-trigger--receipt {
  display: flex; flex-direction: row; align-items: center; justify-content: space-between;
  gap: 12px; width: 100%;
}
.metric-detail-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* Left-hand vendor/meta truncate before the amount is allowed to wrap, so the
   amount + currency ("$2,795.96 MXN") always stays on a single line. */
.metric-detail-trigger--receipt .metric-detail-vendor,
.metric-detail-trigger--receipt .metric-detail-meta {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.metric-detail-trigger--receipt .metric-detail-amount {
  flex: 0 0 auto;
  white-space: nowrap;
  font-size: .95rem;
}
/* Per-row actions are revealed when the row is expanded. */
.metric-detail-actions { display: none; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.metric-detail-row.is-open .metric-detail-actions { display: flex; }
.metric-detail-actions .action-btn,
.metric-detail-actions .soft-btn,
.metric-detail-actions .danger-btn {
  flex: 1 1 auto; min-height: 42px; font-size: 13px;
}
/* Footer flow shortcuts (capture / send invoice) on the unbilled popup. */
.metric-detail-footer {
  display: flex; flex-direction: column; gap: 10px;
  margin-top: 14px; padding-top: 14px;
  border-top: 1px solid var(--color-border);
}
.metric-detail-empty {
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  padding: 18px 14px;
  text-align: center;
  color: var(--color-text-muted);
  background: var(--color-surface-2);
}
.metric-detail-empty-title { font-weight: 700; color: var(--color-text); margin-bottom: 4px; }

.action-grid { display:grid; gap: 12px; }
.action-btn, .ghost-btn, .soft-btn, .danger-btn {
  min-height: 48px;
  border-radius: 18px;
  border: 1px solid transparent;
  padding: 0 16px;
  display:inline-flex; align-items:center; justify-content:center; gap:10px;
  font-weight: 700;
  transition: transform .14s ease, background .18s ease, box-shadow .18s ease;
  cursor: pointer;
}
.action-btn { background: var(--color-primary); color:#f8f4ed; box-shadow: var(--shadow-md); }
.action-btn:hover { background: var(--color-primary-hover); }
.action-btn:active { transform: translateY(1px); }
.action-btn[disabled] { background: #cdc7be; color: #6b665e; box-shadow: none; cursor: not-allowed; }
.ghost-btn { background: rgba(255,255,255,.72); border-color: var(--color-border); }
.soft-btn { background: var(--color-surface-2); border-color: var(--color-border); }
.ghost-btn[disabled], .soft-btn[disabled] { opacity: .55; cursor: not-allowed; }
/* Ready-to-act emphasis: a button turns the Villa Savina teal once its
   preconditions are met (manual item fully entered, payment link generated).
   This is the same --color-primary the app's primary actions use — never a
   bright green, which staff flagged as off-brand. Disabled stays gray/taupe. */
.soft-btn.is-ready:not([disabled]),
.action-btn.is-ready:not([disabled]) {
  background: var(--color-primary);
  color: #f8f4ed;
  border-color: var(--color-primary);
  box-shadow: var(--shadow-md);
}
.soft-btn.is-ready:not([disabled]):hover,
.action-btn.is-ready:not([disabled]):hover { background: var(--color-primary-hover); }
.danger-btn {
  background: var(--color-error);
  color: #fbf3ee;
  box-shadow: var(--shadow-md);
}
.danger-btn:hover { background: #7a4034; }
.danger-btn:active { transform: translateY(1px); }

.primary-action-row { display: grid; gap: 8px; }
.primary-action-row.paired { grid-template-columns: 1fr 1fr; }
.primary-action-row.submit-pair { grid-template-columns: 1fr 1fr; }
/* Side-by-side buttons (e.g. bookings step: Capture Receipt + Send Invoice)
   must fit on one line: never wrap, shrink the label to fit narrow phones, and
   keep both buttons the same text size so neither looks dominant. min-width:0
   lets the grid cells shrink below their content width instead of overflowing. */
.primary-action-row.paired .action-btn {
  white-space: nowrap;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: clamp(13px, 3.6vw, 15px);
  padding-left: 10px;
  padding-right: 10px;
}

/* Guest Receipts capture heading — short stack with eyebrow + page title +
   meta. Matches Villa Receipts visual rhythm above the receipt illustration. */
.guest-capture-heading {
  gap: 6px;
  margin-bottom: 4px;
}
.guest-capture-heading .eyebrow {
  font-size: 12px;
  letter-spacing: .18em;
  color: var(--color-primary);
  text-transform: uppercase;
}
.guest-capture-heading .meta {
  margin: 0;
  color: var(--color-text-muted);
  font-size: 13px;
  line-height: 1.4;
}

.bottom-bar {
  position: absolute; inset: auto 14px 14px;
  background: rgba(251,248,243,.92);
  border: 1px solid var(--color-border);
  border-radius: 24px;
  padding: 10px;
  backdrop-filter: blur(18px);
  box-shadow: var(--shadow-md);
  display:grid; gap:10px;
}
.nav-tabs { display:grid; grid-template-columns: repeat(4, 1fr); gap:8px; }
.nav-tabs.three-tabs { grid-template-columns: repeat(3, 1fr); }
.nav-tabs button {
  border:none; background: transparent; border-radius: 16px; min-height: 56px; padding: 8px 4px;
  font-size: 11px; color: var(--color-text-muted); display:grid; gap:6px; place-items:center;
  transition: background .18s ease, color .18s ease;
}
.nav-tabs button.active { background: rgba(27,91,87,.1); color: var(--color-primary); }
.nav-icon { width: 20px; height: 20px; border-radius: 7px; border: 1px solid currentColor; display:grid; place-items:center; font-size: 11px; }

/* Step indicator: passive progress UI, not interactive */
.nav-tabs.step-indicator > * {
  border: none;
  background: transparent;
  border-radius: 16px;
  min-height: 56px;
  padding: 8px 4px;
  font-size: 11px;
  color: var(--color-text-muted);
  display: grid;
  gap: 6px;
  place-items: center;
  cursor: default;
  pointer-events: none;
  user-select: none;
  font-weight: 400;
  transition: background .18s ease, color .18s ease, font-weight .18s ease;
}
/* Current step: outlined green + bold */
.nav-tabs.step-indicator > [data-step-state="current"] {
  background: rgba(27,91,87,.1);
  color: var(--color-primary);
  font-weight: 700;
}
/* Completed step: filled green with light text + check inside the icon */
.nav-tabs.step-indicator > [data-step-state="done"] {
  background: var(--color-primary);
  color: #f8f4ed;
  font-weight: 500;
}
.nav-tabs.step-indicator > [data-step-state="done"] .nav-icon {
  background: #f8f4ed;
  color: var(--color-primary);
  border-color: #f8f4ed;
  font-weight: 700;
}
/* Upcoming step: muted */
.nav-tabs.step-indicator > [data-step-state="upcoming"] {
  opacity: .55;
}

/* Send step fixed controls — Generate Payment Link + Send Invoice to Guest
   stacked vertically beneath the step indicators in the bottom bar. Status
   lines sit directly under their buttons, above the bottom safe area. */
.send-cta-stack {
  display: grid;
  gap: 8px;
}
.send-cta-stack.hidden { display: none; }
/* Stripe Link + Send Invoice share one row, splitting the width evenly. Labels
   never wrap; the font shrinks to fit and both buttons use the SAME clamped
   size, so they stay visually matched even when one label is longer. */
.send-cta-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.send-cta-stack .action-btn {
  width: 100%;
  min-width: 0;
  border-radius: 22px;
  min-height: 52px;
  font-size: clamp(12px, 3.4vw, 15px);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-left: 8px;
  padding-right: 8px;
}
.send-cta-stack .stripe-status:empty { display: none; }

.share-message {
  display: grid;
  gap: 8px;
}
.share-message.hidden { display: none; }
.share-message-text {
  width: 100%;
  resize: vertical;
  font-size: 13px;
  line-height: 1.4;
  padding: 8px 10px;
  border: 1px solid var(--color-border, #ccc);
  border-radius: 10px;
  background: var(--color-surface, #fff);
  color: var(--color-text, #222);
}
.share-message .soft-btn { width: 100%; }

.receipt-shot {
  background: linear-gradient(180deg,#efe7db 0%,#e7ddcf 100%);
  border-radius: 24px;
  border:1px solid var(--color-border);
  padding: 18px;
  display:grid; gap:12px;
  transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}
.receipt-shot.is-dragging {
  border-color: rgba(27,91,87,.45);
  box-shadow: 0 18px 38px rgba(27,91,87,.15);
  transform: translateY(-1px);
}

/* Desktop-only capture affordance (drag/drop + paste). Hidden by default so
   touch-primary devices (phones/tablets) never see desktop instructions and
   keep the camera/library-first flow. Revealed only on devices with a precise
   pointer + hover — the same gate isDesktopCapture() uses in JS, so the visible
   hint and the active behavior always agree. */
.desktop-capture-hint { display: none; }
@media (hover: hover) and (pointer: fine) {
  .desktop-capture-hint:not(.hidden) {
    display: block;
    margin: 6px 0 0;
    text-align: center;
    font-size: 12px;
    letter-spacing: .02em;
    color: var(--color-text-muted);
  }
  /* The bookings-step drop target gets a dashed dropzone treatment so the
     drag/paste area reads as interactive. The expense hint is plain text under
     the capture dropzone, so it keeps the .desktop-capture-hint
     defaults above. */
  #reimbursementCaptureZone:not(.hidden) {
    margin-top: 14px;
    padding: 16px;
    border: 1px dashed var(--color-border);
    border-radius: 16px;
    background: var(--color-surface-2);
    transition: border-color .18s ease, background .18s ease;
  }
  #reimbursementCaptureZone.is-dragging {
    border-color: rgba(27,91,87,.55);
    background: rgba(27,91,87,.06);
  }
}
.receipt-paper {
  background: #fffdfa;
  border-radius: 18px;
  padding: 16px 14px;
  min-height: 250px;
  border: 1px solid var(--color-border);
  box-shadow: 0 16px 30px rgba(33,26,20,.08);
  font-size: 12px;
  color:#36312b;
}
.receipt-paper img { width: 100%; height: auto; max-height: 320px; object-fit: contain; border-radius: 12px; }

/* Review-OCR mode: editable fields come first, then a compact thumbnail of the
   scanned receipt. Tapping the thumbnail opens the full-size viewer modal. */
.review-thumb-wrap {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 14px;
}
.review-thumb-label {
  font-size: 12px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.review-thumb {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  width: auto;
  height: auto;
  max-width: 200px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 12px;
  background: var(--color-surface-2);
  overflow: hidden;
  cursor: pointer;
  color: var(--color-text-muted);
  line-height: 0;            /* no inline-baseline gap that strips the image height */
}
/* Empty state still needs a sensible minimum so the placeholder box is tappable. */
.review-thumb:not(.has-image) {
  min-width: 96px;
  min-height: 120px;
}
.review-thumb.has-image { cursor: zoom-in; }
.review-thumb:disabled { cursor: default; }
/* Height drives the thumbnail (tall receipt → tall narrow preview; wide → width-
   capped). object-fit:contain guarantees no distortion if a box is ever forced. */
.review-thumb-img {
  display: block;
  width: auto;
  height: auto;
  object-fit: contain;
  max-width: 200px;
  max-height: 260px;
}
.review-thumb-empty {
  padding: 8px;
  text-align: center;
  font-size: 11px;
  line-height: 1.3;
}

/* Full-size scanned-receipt viewer modal. */
.receipt-image-viewer-card { max-width: min(92vw, 520px); }
.receipt-image-viewer-frame {
  display: flex;
  align-items: center;
  justify-content: center;
  max-height: 70vh;
  overflow: auto;
  border-radius: 12px;
  background: var(--color-surface-2);
}
.receipt-image-viewer-img {
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
  display: block;
}
/* A PDF receipt is shown in an embedded viewer rather than an <img>. */
.receipt-image-viewer-pdf {
  width: min(88vw, 480px);
  height: 70vh;
  border: 0;
  display: block;
  background: #fff;
}

/* A full invoice PDF (View from the unpaid-invoice sheet) needs a near
   full-screen surface so it reads on a phone. */
.viewer-large .receipt-image-viewer-card { max-width: min(96vw, 820px); }
.viewer-large .receipt-image-viewer-frame { max-height: 86vh; }
.viewer-large .receipt-image-viewer-pdf { width: min(94vw, 780px); height: 86vh; }

/* PDF placeholder for the small thumbnails (review/submit/capture preview),
   where a PDF can't be drawn into an <img>. A clear "PDF" badge stands in. */
.pdf-thumb {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 18px 14px;
  min-width: 120px;
  text-align: center;
}
.pdf-thumb-badge {
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--color-surface, #fff);
  background: var(--color-accent, #c0392b);
  border-radius: 6px;
  padding: 4px 10px;
}
.pdf-thumb-label {
  font-size: 11px;
  line-height: 1.3;
  color: var(--color-text-muted, #5b554d);
}

/* Neutral empty state for the Villa Receipts capture step — no receipt
   graphic, just a minimal SAVINA-styled prompt to tap/drop a receipt. */
.receipt-paper.capture-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.capture-empty-inner {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.capture-empty-title {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .02em;
  color: var(--color-text);
}
.capture-empty-hint {
  margin: 0;
  font-size: 13px;
  line-height: 1.4;
  color: var(--color-text-muted);
}
.paper-line { height: 8px; background: linear-gradient(90deg, rgba(36,33,28,.82), rgba(36,33,28,.28)); border-radius: 999px; margin: 8px 0; }
.paper-line.short { width: 48%; }
.paper-line.mid { width: 72%; }
.paper-line.long { width: 94%; }

.field-grid { display:grid; gap: 10px; }
.field { display:grid; gap:6px; }
.field label { font-size: 12px; text-transform: uppercase; letter-spacing: .12em; color: var(--color-text-muted); }
.field input, .field select, .field textarea {
  width: 100%; min-height: 46px; border-radius: 14px; border: 1px solid var(--color-border);
  background: rgba(255,255,255,.76); padding: 11px 13px;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: rgba(27,91,87,.45); box-shadow: 0 0 0 3px rgba(27,91,87,.12);
}
.field textarea { min-height: 88px; resize: vertical; }

.validation { display:grid; gap:10px; }
.validation-row {
  display:flex; justify-content:space-between; gap:12px; align-items:center;
  border-radius: 16px; padding: 11px 13px;
}
.validation-row.ok { background:#edf4ef; color:#245039; }
.validation-row.bad { background:#f6e7e3; color:#7b4038; }
.validation-row.warn { background:#f8f1e5; color:#7d5920; }

/* Edit-first scanned-result rows: each row is the editable control itself,
   keeping the compact mobile look while letting staff edit without scrolling. */
.validation.edit-first { gap: 8px; }
.validation-edit-row {
  display: grid;
  grid-template-columns: 88px 1fr;
  gap: 10px 12px;
  align-items: center;
  border-radius: 16px;
  padding: 8px 12px;
  background: rgba(255,255,255,.62);
  border: 1px solid var(--color-border);
  transition: background-color .18s ease, border-color .18s ease;
}
.validation-edit-row.ok { background:#edf4ef; border-color: rgba(47,111,79,.35); }
.validation-edit-row.warn { background:#f8f1e5; border-color: rgba(155,106,29,.40); }
.validation-edit-row.bad { background:#f6e7e3; border-color: rgba(145,80,65,.45); }
.validation-edit-row.hidden { display: none; }
/* Owner Related: a single-line optional checkbox that lives in the validation
   list but is independent of the category dropdown. */
.owner-related-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 14px;
  color: var(--color-text);
}
.owner-related-toggle input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--color-accent, #2f6f4f);
  cursor: pointer;
}
.owner-related-toggle-text {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .12em;
  font-weight: 600;
  white-space: nowrap;
}
.validation-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .12em;
  color: var(--color-text-muted);
  font-weight: 600;
}
.validation-edit-row.ok .validation-label { color:#245039; }
.validation-edit-row.warn .validation-label { color:#7d5920; }
.validation-edit-row.bad .validation-label { color:#7b4038; }
.validation-input {
  width: 100%;
  height: 40px;
  min-height: 40px;
  box-sizing: border-box;
  border-radius: 12px;
  border: 1px solid var(--color-border);
  background: rgba(255,255,255,.92);
  padding: 8px 11px;
  font: inherit;
  line-height: 1.2;
  color: inherit;
  text-align: left;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color .18s ease, box-shadow .18s ease;
}
textarea.validation-input { height: auto; }
select.validation-input {
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 28px;
}
input.validation-input[type="date"] {
  font-variant-numeric: tabular-nums;
  text-align: left;
}
input.validation-input[type="date"]::-webkit-date-and-time-value {
  text-align: left;
  margin: 0;
}
input.validation-input[type="date"]::-webkit-calendar-picker-indicator {
  margin-left: auto;
  opacity: .55;
  cursor: pointer;
}
.validation-input:focus {
  outline: none;
  border-color: rgba(27,91,87,.45);
  box-shadow: 0 0 0 3px rgba(27,91,87,.12);
}
.validation-textarea { min-height: 64px; resize: vertical; grid-column: 1 / -1; }
.validation-edit-row[data-row="note"] { grid-template-columns: 1fr; gap: 6px; }
.validation-edit-row[data-row="note"] .validation-label { grid-column: 1 / -1; }
.validation-hint {
  grid-column: 2 / -1;
  font-size: 11px;
  letter-spacing: .03em;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
  margin-top: -2px;
}
.validation-edit-row.ok .validation-hint { color:#245039; }
.validation-edit-row.warn .validation-hint { color:#7d5920; }
.validation-edit-row.bad .validation-hint { color:#7b4038; }
.validation-hint:empty { display: none; }
.validation-split {
  display: grid;
  grid-template-columns: 1fr 88px;
  gap: 8px;
  align-items: center;
}
.validation-input[data-confidence="high"] {
  border-color: rgba(47,111,79,.55);
  box-shadow: inset 0 0 0 1px rgba(47,111,79,.20);
}
.validation-input[data-confidence="medium"] {
  border-color: rgba(155,106,29,.55);
  box-shadow: inset 0 0 0 1px rgba(155,106,29,.22);
}
.validation-input[data-confidence="low"] {
  border-color: rgba(145,80,65,.60);
  box-shadow: inset 0 0 0 1px rgba(145,80,65,.24);
}
.validation-input[data-confidence]:focus {
  box-shadow: 0 0 0 3px rgba(27,91,87,.12);
}
@media (max-width: 380px) {
  .validation-edit-row { grid-template-columns: 1fr; gap: 6px; padding: 8px 10px; }
  .validation-hint { grid-column: 1 / -1; }
}

/* ── Vendor typeahead (QuickBooks-backed autocomplete) ────────────────────── */
/* The autocomplete wraps the vendor <input> at runtime so the dropdown can be
   absolutely positioned against it. The wrapper takes the input's old grid cell
   and the input stretches to fill it, so the layout is unchanged. */
.vendor-typeahead {
  position: relative;
  width: 100%;
  min-width: 0;
}
.vendor-typeahead > .validation-input {
  width: 100%;
}
.vendor-typeahead-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 60;
  margin: 0;
  padding: 4px;
  list-style: none;
  max-height: 248px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: 12px;
  box-shadow: 0 12px 28px rgba(31, 49, 41, .18);
}
.vendor-typeahead-menu.hidden { display: none; }
.vendor-typeahead-item {
  padding: 11px 12px;
  min-height: 44px;
  display: flex;
  align-items: center;
  border-radius: 9px;
  font-size: 15px;
  line-height: 1.25;
  color: var(--color-text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.vendor-typeahead-item + .vendor-typeahead-item { margin-top: 2px; }
.vendor-typeahead-item.active,
.vendor-typeahead-item:hover {
  background: #edf4ef;
  color: #245039;
}

/* Per-field confidence colors — high/medium/low map to green/amber/red.
   Applied to the input/select itself so staff can see field health while editing. */
.field input[data-confidence="high"],
.field select[data-confidence="high"] {
  border-color: rgba(47,111,79,.55);
  box-shadow: inset 0 0 0 1px rgba(47,111,79,.25);
  color: #245039;
}
.field input[data-confidence="medium"],
.field select[data-confidence="medium"] {
  border-color: rgba(155,106,29,.55);
  box-shadow: inset 0 0 0 1px rgba(155,106,29,.28);
  color: #7d5920;
}
.field input[data-confidence="low"],
.field select[data-confidence="low"] {
  border-color: rgba(145,80,65,.65);
  box-shadow: inset 0 0 0 1px rgba(145,80,65,.30);
  color: var(--color-error);
}
.field input[data-confidence="high"]:focus,
.field input[data-confidence="medium"]:focus,
.field input[data-confidence="low"]:focus,
.field select[data-confidence]:focus {
  box-shadow: 0 0 0 3px rgba(27,91,87,.12);
}
.queue-item { display:grid; gap: 12px; padding-bottom: 12px; border-bottom:1px solid var(--color-divider); }
.queue-item:not(.manual-item) { grid-template-columns: minmax(0,1fr) auto; align-items: flex-start; }
.queue-item:last-child { padding-bottom: 0; border-bottom: 0; }
.queue-main { display:flex; gap:12px; align-items:flex-start; min-width:0; }
.manual-item-panel {
  display: grid;
  gap: 10px;
  padding: 12px;
  border-radius: 18px;
  border: 1px dashed rgba(27,91,87,.28);
  background: rgba(255,255,255,.52);
}
.manual-item {
  background: rgba(27,91,87,.05);
  border-radius: 16px;
  padding: 10px;
  border-bottom: 0;
}
.compact-fields {
  gap: 8px;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Final manual-item entry row: Amount, Currency, Date and a teal circular "+"
   Add bubble all on one line. The + reuses the .soft-btn / .is-ready mechanism
   (JS toggles disabled + is-ready) so it stays gray/muted until the item is
   ready, then turns Villa Savina teal and tappable. Date is narrow and
   left-justified; the row only wraps at extremely narrow widths. */
.manual-item-entry-row {
  display: flex;
  gap: 10px;
  align-items: flex-end;
}
.manual-item-amount-field {
  flex: 1.2 1 0;
  min-width: 0;
}
.manual-item-currency-field {
  flex: 1.3 1 0;
  min-width: 6.2ch;
}
.manual-item-date-field {
  flex: 0 1 auto;
  min-width: 0;
}
.manual-item-date-field input {
  width: auto;
  max-width: 100%;
  font-size: 0.8rem;
  padding-left: 6px;
  padding-right: 6px;
  text-align: left;
}
.manual-item-add-btn.soft-btn {
  flex: 0 0 auto;
  width: 46px;
  min-width: 46px;
  height: 46px;
  min-height: 46px;
  padding: 0;
  border-radius: 50%;
  font-size: 1.5rem;
  line-height: 1;
}
@media (max-width: 340px) {
  .manual-item-entry-row { flex-wrap: wrap; }
  .manual-item-amount-field,
  .manual-item-currency-field { flex: 1 1 calc(50% - 5px); }
  .manual-item-date-field { flex: 1 1 auto; }
  .manual-item-date-field input { width: 100%; }
  .manual-item-add-btn.soft-btn { margin-left: auto; }
}
.queue-top { display:flex; gap:12px; align-items:flex-start; }
.check {
  width: 22px; height: 22px; border-radius: 7px; flex:0 0 auto;
  border:1px solid var(--color-border); background:#fff; display:grid; place-items:center; margin-top:2px;
}
.check.active { background: var(--color-primary); color:#fff; border-color: transparent; }
.check[disabled] { background: #efe9df; cursor: not-allowed; color: var(--color-text-faint); }
/* Bulk "Select all / Deselect all" pill above the unbilled-receipt checklist.
   Reuses the app's teal (--color-primary) — never a bright green — and mirrors
   the rounded-pill shape of the per-row queue actions. Mobile-first: full-width
   tap target on the left, comfortable min-height. The active (all-selected)
   state fills teal to read as "engaged", matching .check.active. */
.queue-select-all { display:flex; justify-content:flex-start; }
.select-all-btn {
  min-height: 36px; border-radius: 999px;
  border: 1px solid var(--color-primary);
  background: rgba(255,255,255,.68);
  color: var(--color-primary);
  padding: 0 16px; font-size: 13px; font-weight: 700;
  cursor: pointer;
  transition: background .18s ease, color .18s ease;
}
.select-all-btn:hover { background: rgba(27,91,87,.08); }
.select-all-btn.is-active {
  background: var(--color-primary);
  color: #f8f4ed;
  border-color: var(--color-primary);
}
.queue-actions { display:flex; gap:8px; flex-wrap:wrap; }
.queue-actions button {
  min-height: 36px; border-radius: 999px; border:1px solid var(--color-border);
  background: rgba(255,255,255,.68); padding: 0 12px; font-size: 13px;
}
.queue-item:not(.manual-item) .queue-actions {
  flex-direction: column; flex-wrap: nowrap; flex: 0 0 auto; align-items: stretch;
}
.queue-item:not(.manual-item) .queue-actions button { white-space: nowrap; }
.queue-item.queue-item-selectable { grid-template-columns: minmax(0,1fr); }
.queue-receipt-open {
  display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0;
  border: 0; background: transparent; padding: 0; margin: 0;
  text-align: left; cursor: pointer; color: inherit; font: inherit;
}
.queue-receipt-open:active { opacity: .6; }
/* The receipt card variant lives inside the flex .queue-main row beside the
   checkbox, so it must grow to fill the remaining width. */
.send-card--receipt.queue-receipt-open { flex: 1; }

/* Send-invoice page list cards. Both the Unpaid invoices and Unbilled Receipts
   lists use this compact rounded card — vendor/id on the left, amount on the
   right, a metadata row (date · Guest · name) below with status pills. It reuses
   the dashboard drilldown card's cream surface / border / pill language; no new
   shades are introduced. */
.send-card {
  display: flex; flex-direction: column; gap: 4px;
  width: 100%; min-width: 0;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: rgba(251,248,243,.92);
  text-align: left; cursor: pointer; color: inherit; font: inherit;
  -webkit-appearance: none; appearance: none;
  transition: border-color .15s ease, background .15s ease, transform .05s ease;
}
.send-card:hover { border-color: var(--color-accent); background: rgba(27,91,87,.06); }
.send-card:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.send-card:active { transform: scale(.995); }
/* A receipt picked for the invoice gets a green selected outline so the card's
   chosen state reads at a glance, mirroring the selected booking card. */
.send-card.is-selected {
  border-color: var(--color-primary);
  box-shadow: inset 0 0 0 1px var(--color-primary);
  background: rgba(27,91,87,.08);
}
.send-card-top {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.send-card-title {
  font-weight: 700; color: var(--color-text); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.send-card-amount {
  font-weight: 700; color: var(--color-text);
  font-variant-numeric: tabular-nums; white-space: nowrap; flex: 0 0 auto;
}
.send-card-meta {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; flex-wrap: wrap;
}
.send-card-metatext { color: var(--color-text-muted); font-size: .82rem; min-width: 0; }
.send-card-pills { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
/* UNBILLED pill on unbilled receipt cards — uppercase, teal-shaded, matching
   the dashboard drilldown's status tag. */
.pill.send-card-tag-unbilled {
  background: rgba(27,91,87,.10); color: var(--color-accent);
  text-transform: uppercase; letter-spacing: .04em; font-weight: 600;
}

/* Draft totals card mirrors the app's green-shaded selected-card/guest-bubble
   treatment instead of the old dark utility fill: soft green wash, primary
   border + text. */
.totals-card {
  background: rgba(27,91,87,.1);
  color: var(--color-primary);
  border: 1px solid var(--color-primary);
  border-radius: 28px;
  padding: 18px;
  /* Three shared columns: label (flex) | amount (shrink-wrapped, right-aligned)
     | currency (fixed). Rows use display:contents so every row's cells land in
     THESE columns — that's what makes the amount column, and therefore every
     decimal point, stack on one vertical line across all rows. */
  display:grid;
  grid-template-columns: 1fr auto 34px;
  row-gap: 10px;
  align-items: baseline;
  box-shadow: var(--shadow-md);
}
/* Each row is a column-spanning group whose three children flow into the card's
   shared grid columns. */
.totals-row { display:contents; }
.totals-label { font-size: 14px; color: var(--color-primary); font-weight: 700; }
/* AMOUNT: right-aligned + tabular numerals so the grouped "$27,154.01",
   "$1,615.88", the bare "16.80" exchange rate, and "$1,732.51" all align on
   their decimal point. Shrink-wrapped (auto column) so it sits close to the
   currency code rather than detaching at the card edge. */
.totals-amount {
  text-align: right; white-space: nowrap;
  font-size: 14px; color: var(--color-primary); font-weight: 700;
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1, "lnum" 1;
}
.totals-amount strong { color: var(--color-primary); font-weight: 700; }
/* CURRENCY: fixed-width cell immediately right of the amount, left-aligned so
   the MXN/USD codes line up under one another. The Exchange Rate row leaves
   this empty, so the amount column keeps owning the alignment. */
.totals-currency {
  text-align: left; white-space: nowrap;
  padding-left: 6px;
  font-size: 14px; color: var(--color-primary); font-weight: 700;
}
.totals-row strong { color: var(--color-primary); }
/* The Total Due row spans the full width for its top divider, then re-opens its
   own matching 3-column subgrid so its amount still aligns with the rows above. */
.totals-row.total {
  grid-column: 1 / -1;
  display:grid;
  grid-template-columns: subgrid;
  border-top:1px solid rgba(27,91,87,.22); padding-top:10px;
}
.totals-row.total .totals-label,
.totals-row.total .totals-amount,
.totals-row.total .totals-currency { font-size: 16px; }

.desktop {
  display:grid; gap: 18px;
  grid-template-columns: minmax(320px, 420px) minmax(420px, 1fr);
}
.panel, .pdf-sheet { border-radius: 28px; padding: 22px; }
.panel h2, .pdf-sheet h2 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1.7rem, 1.5rem + .4vw, 2.4rem);
  line-height: 1.02;
}
.panel p { margin: 0; color: var(--color-text-muted); }
.panel code { background: rgba(40,37,29,.06); padding: 1px 6px; border-radius: 6px; font-size: 12px; }

.spec-list { display:grid; gap: 0; margin-top: 8px; }
.spec-item {
  padding: 14px 0;
  border-bottom: 1px solid var(--color-divider);
  display:grid; gap: 6px;
}
.spec-item:first-child { padding-top: 0; }
.spec-item:last-child { border-bottom: 0; padding-bottom: 0; }
.spec-item strong { font-size: 15px; }
.spec-item .meta { color: var(--color-text-muted); font-size: 13px; line-height: 1.5; }

/* ── Guest Folio PDF — mobile/narrow layout (matches approved mock) ──────────
   Palette: teal #01696F, cream #F7F3EA, ink #28251D, muted gray #62615D,
   soft card #FBF8F1, hairline border #D4D1CA. */
.pdf-folio {
  --folio-teal: #01696F;
  --folio-ink: #28251D;
  --folio-muted: #62615D;
  --folio-cream: #F7F3EA;
  --folio-card: #FBF8F1;
  --folio-border: #D4D1CA;
}
.pdf-sheet { display:grid; gap: 18px; background: #fff; }
.pdf-folio { background: var(--folio-cream); color: var(--folio-ink); padding: 24px; }

.pdf-folio-header {
  display:flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
}
.pdf-logo { text-align: left; }
.pdf-logo-img {
  display: block;
  height: 40px;
  width: auto;
  max-width: 200px;
}
.pdf-folio-meta { text-align: right; }
.pdf-folio-title { margin: 0; font-size: 20px; font-weight: 700; color: var(--folio-ink); }
.pdf-folio-meta .pdf-note { margin: 3px 0 0; font-size: 12px; }
.pdf-note { color: var(--folio-muted, var(--color-text-muted)); font-size: 14px; }

.pdf-guest-block { display:grid; gap: 3px; }
.pdf-guest-name { margin: 0; font-size: 19px; font-weight: 700; color: var(--folio-ink); }
.pdf-guest-block .pdf-note { margin: 0; }

/* Teal Total Due card: amount left, Pay Now pill right. */
.pdf-total-card {
  display:flex; align-items: center; justify-content: space-between; gap: 16px;
  background: var(--folio-teal); color: #fff;
  border-radius: 16px; padding: 16px 18px;
}
.pdf-total-card-left { display:grid; gap: 4px; }
.pdf-total-label { font-size: 12px; letter-spacing: .06em; opacity: .9; }
.pdf-total-amount, .amount-big { font-size: 28px; font-weight: 700; letter-spacing: -.02em; line-height: 1; }
.pdf-total-card .pdf-pay { margin: 0; }
.pdf-pay-link {
  display: inline-block;
  padding: 9px 22px; border-radius: 999px;
  background: #fff; color: var(--folio-teal); font-weight: 700; font-size: 14px;
  text-decoration: none; white-space: nowrap;
}
.pdf-pay-link:hover { background: #eef6f4; }

.pdf-section-heading {
  margin: 6px 0 0; text-align: center;
  font-size: 16px; font-weight: 700; color: var(--folio-ink);
}

/* Summary card */
/* Equal left/right internal padding (16px both sides) so the card's content —
   labels on the left, amounts on the right — sits inside symmetric margins; the
   amount column's right edge mirrors the label column's left edge. */
.pdf-summary-card {
  background: var(--folio-card);
  border: 1px solid var(--folio-border);
  border-radius: 14px;
  padding: 14px 16px;
}
.pdf-summary-card table { width:100%; border-collapse: collapse; }
.pdf-summary-card td {
  border: 0; padding: 5px 0; font-size: 13px; vertical-align: middle;
  color: var(--folio-muted);
  /* border-box so the TOTAL DUE row's extra horizontal padding stays INSIDE
     the cell and can't nudge the amount column off the shared right edge that
     the plain rows (e.g. Processing Fee) sit on. */
  box-sizing: border-box;
}
/* Three columns: the label flexes to fill the row, then a compact two-part
   value area — a right-aligned AMOUNT column and a small fixed CURRENCY column.
   The label flexes (width:auto) and both value columns shrink-wrap (width:1%)
   so they hug the right side as a tight amount+currency group, NOT detached at
   the far card edge. */
.pdf-summary-card .folio-label {
  text-align: left; width: auto;
  /* Key labels like "Total MXN Receipts (in USD)" must not wrap to two lines. */
  white-space: nowrap;
}
/* AMOUNT column: right-aligned + tabular numerals so every decimal point lines
   up vertically across rows ($8,299.66 / $495.57 / $0.00 / $19.82 / 16.75),
   regardless of the currency code beside it. Shrink-wrapped so the column is
   only as wide as the widest amount and sits close to its currency. */
.pdf-summary-card .folio-amount {
  width: 1%; text-align: right; white-space: nowrap;
  font-weight: 700; color: var(--folio-ink);
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1, "lnum" 1;
  font-family: inherit;
}
/* CURRENCY column: a small FIXED-width cell immediately right of the amount —
   a modest gap (padding-left), left-aligned so the codes line up under one
   another, NOT pushed to the card's far right edge. The exchange-rate row
   leaves this cell empty, so the amount column still owns the alignment.

   The width is FIXED and IDENTICAL on every row (plain rows AND the TOTAL DUE
   pill). Because the amount column shrink-wraps and right-aligns, its right edge
   is pinned by how much horizontal space the currency cell occupies; if the
   TOTAL DUE row's currency cell were any wider than the plain rows' (e.g. from
   its own extra padding-right, or its larger bold font), it would push the
   amount column left and the "$732.54" decimal point would drift left of the
   rows above. So the pill's internal right breathing room is reserved HERE,
   on the shared column (padding-right), and the cell is wide enough to hold
   the larger bold 15.6px "USD" of the pill — keeping one constant right edge,
   and therefore one vertical decimal line, across all rows. */
.pdf-summary-card .folio-currency {
  width: 50px; text-align: left; white-space: nowrap;
  box-sizing: border-box;
  padding-left: 6px; padding-right: 12px;
  color: var(--folio-muted); font-size: 11px;
}
/* TOTAL DUE row: teal rounded pill. ~10% shorter padding + ~20% larger type so
   the total reads as the prominent line. Kept in px so it scales on mobile. */
.pdf-summary-card .folio-total-row td {
  background: var(--folio-teal); color: #fff;
  padding-top: 10px; padding-bottom: 10px;
  font-size: 15.6px;
}
.pdf-summary-card .folio-total-row .folio-label { padding-left: 12px; border-radius: 8px 0 0 8px; font-weight: 700; }
.pdf-summary-card .folio-total-row .folio-amount { color: #fff; }
/* The currency cell is the pill's right end: it carries the rounded right edge
   and (via the shared .folio-currency rule) the matching internal right padding
   so "$515.39 USD" sits comfortably inside the bubble (not crowded/clipped
   against the card edge). It deliberately does NOT add its own padding-right or
   change its width — it keeps the SAME box as every plain row's currency cell so
   the amount column's right edge (and the decimal point above it) stays on one
   vertical line. In the teal pill the USD reads as part of the headline amount —
   full white, bold, and the SAME size as the amount (inherits the 15.6px pill
   font-size), NOT the muted 11px tag the plain rows use. */
.pdf-summary-card .folio-total-row .folio-currency {
  border-radius: 0 8px 8px 0;
  color: #fff; font-size: inherit; font-weight: 700;
}

.pdf-footnote {
  margin: -6px 0 0; padding-left: 8px;
  color: var(--folio-muted); font-size: 11px; line-height: 1.45;
}

/* Included Charges: one compact card per charge. */
.pdf-charges { display:grid; gap: 10px; }
.pdf-charge {
  display:flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--folio-card);
  border: 1px solid var(--folio-border);
  border-radius: 12px; padding: 12px 14px;
}
.pdf-charge--empty { justify-content: center; color: var(--folio-muted); font-size: 13px; }
.pdf-charge-main { display:grid; gap: 4px; min-width: 0; }
.pdf-charge-vendor { font-size: 14px; font-weight: 700; color: var(--folio-ink); }
.pdf-charge-meta { display:flex; gap: 16px; font-size: 12px; color: var(--folio-muted); }
.folio-receipt-btn {
  flex: none; align-self: center;
  padding: 7px 16px; border-radius: 999px;
  background: #E9F3F0; border: 1px solid #9DBFBA; color: var(--folio-teal);
  font-size: 12px; font-weight: 700; text-decoration: none; white-space: nowrap;
}
.folio-receipt-btn:hover { background: #dcece8; }
.folio-receipt-btn.is-disabled { opacity: .45; pointer-events: none; }

.pdf-pencil { display:flex; justify-content: center; padding-top: 6px; }
.pdf-pencil-img { display:block; width: 78%; max-width: 260px; height: auto; }

.money {
  display: inline-block;
  min-width: 112px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "lnum" 1;
}

.pdf-receipts { display:grid; grid-template-columns: 1fr; gap: 18px; }
.pdf-receipt {
  border:1px solid rgba(40,37,29,.08); border-radius: 18px; overflow:hidden; background:#faf8f3;
}
.pdf-receipt .label {
  padding: 12px 14px; border-bottom:1px solid rgba(40,37,29,.08);
  text-transform: uppercase; letter-spacing: .08em; font-size: 12px; color: var(--color-text-muted);
}
.pdf-receipt .img { padding:18px; background:#f4efe6; }
.pdf-receipt .img img { width:100%; height: auto; max-height: 240px; object-fit: contain; border-radius: 12px; background:#fffdfa; }
.pdf-receipt .receipt-img-loading,
.pdf-receipt .receipt-img-fallback {
  display:flex; flex-direction: column; align-items:center; justify-content:center;
  min-height: 120px; text-align:center;
  color: var(--color-text-muted); font-size: 13px; line-height: 1.5;
  border: 1px dashed rgba(40,37,29,.25); border-radius: 12px; background:#fffdfa; padding: 16px;
}
.pdf-receipt .receipt-img-fallback span { font-size: 12px; opacity: .8; }
/* A PDF receipt reference is intentional (not a load failure): solid border +
   accent so it reads as "this receipt is a PDF" rather than a broken image. */
.pdf-receipt .receipt-img-fallback.receipt-pdf-ref {
  border-style: solid;
  border-color: var(--color-accent, #c0392b);
  color: var(--color-text, #28251d);
}
.pdf-receipt .receipt-img-fallback.receipt-pdf-ref strong {
  font-size: 14px;
  letter-spacing: 0.04em;
  color: var(--color-accent, #c0392b);
}

.empty {
  padding: 24px; border-radius: 24px; border:1px dashed var(--color-border); background: rgba(255,255,255,.5); text-align:center; color: var(--color-text-muted);
}
.hidden { display: none !important; }

/* Duplicate-receipt warning modal — mobile-first, polished. */
.duplicate-modal {
  position: fixed; inset: 0; z-index: 1000;
  display: grid; place-items: end center;
  padding: 16px;
}
.duplicate-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(28,25,20,.48);
  backdrop-filter: blur(2px);
}
.duplicate-modal-card {
  position: relative;
  width: 100%;
  max-width: 420px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 22px 20px 18px;
  box-shadow: var(--shadow-md);
  display: flex; flex-direction: column; gap: 12px;
  animation: duplicate-modal-pop .18s ease-out;
}
@keyframes duplicate-modal-pop {
  from { transform: translateY(12px); opacity: 0; }
  to   { transform: translateY(0); opacity: 1; }
}
.duplicate-modal-eyebrow {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--color-warning); font-weight: 700;
}
.duplicate-modal-card h2 {
  margin: 0; font-family: var(--font-display);
  font-size: 1.25rem; line-height: 1.25; color: var(--color-text);
}
.duplicate-modal-body { margin: 0; color: var(--color-text-muted); font-size: .95rem; }
.duplicate-modal-matches {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 220px; overflow-y: auto;
}
.duplicate-match {
  display: flex; flex-direction: column; gap: 2px;
  border: 1px solid var(--color-border);
  background: var(--color-surface-2);
  border-radius: var(--radius-md);
  padding: 10px 12px;
}
.duplicate-match-top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.duplicate-match-vendor { font-weight: 700; color: var(--color-text); }
.duplicate-match-amount { font-weight: 700; color: var(--color-text); }
.duplicate-match-meta { color: var(--color-text-muted); font-size: .8rem; }
.duplicate-modal-actions {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 4px;
}
.duplicate-modal-actions .ghost-btn,
.duplicate-modal-actions .action-btn { width: 100%; }
.cancel-modal-actions {
  grid-template-columns: 1fr;
}
.cancel-modal-actions .ghost-btn,
.cancel-modal-actions .danger-btn,
.cancel-modal-actions .soft-btn { width: 100%; }

/* Action-sheet layout (#invoiceActionModal, #receiptActionModal): the three
   actions sit in one equal-width row with Close on its own full-width row
   underneath. This is the canonical layout shared by the unpaid-invoice popup
   and the receipt (View / Edit / Delete) popup. */
.invoice-action-actions { grid-template-columns: 1fr; }
.invoice-action-row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
}
.invoice-action-row .action-btn,
.invoice-action-row .soft-btn,
.invoice-action-row .danger-btn {
  width: 100%; min-height: 42px; padding-left: 6px; padding-right: 6px;
  white-space: nowrap;
}
.invoice-action-close { width: 100%; }
/* Paid invoice: only View remains in the action row, so collapse the 3-column
   grid to one column and the lone View button fills the width. */
#invoiceActionModal[data-paid="true"] .invoice-action-row { grid-template-columns: 1fr; }
/* Paid-locked receipt: Delete is hidden, leaving View + Edit, so collapse the
   3-column row to two equal columns. */
#receiptActionModal[data-locked="true"] .invoice-action-row { grid-template-columns: repeat(2, 1fr); }
/* Styled explanation shown in place of Delete for a paid-locked receipt (no
   native alert/confirm). Warning-toned to match the eyebrow. */
.receipt-action-lock {
  margin: 0; font-size: .85rem; line-height: 1.35; font-weight: 600;
  color: var(--color-warning);
  background: color-mix(in srgb, var(--color-warning) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-warning) 35%, transparent);
  border-radius: var(--radius-md);
  padding: 8px 12px;
}

.submit-progress-card {
  align-items: center;
  text-align: center;
  padding: 28px 22px 22px;
}
.submit-progress-state {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
}
.submit-progress-state h2 { text-align: center; }
.submit-progress-state .duplicate-modal-body { text-align: center; }
.submit-progress-spinner {
  width: 48px; height: 48px;
  border-radius: 50%;
  border: 4px solid var(--color-border);
  border-top-color: var(--color-primary, #1b5b57);
  animation: submit-progress-spin 0.9s linear infinite;
}
.submit-progress-state[data-state="complete"] .submit-progress-spinner { display: none; }
.submit-progress-state[data-state="complete"] .submit-progress-check { display: flex; }
.submit-progress-check {
  width: 56px; height: 56px;
  border-radius: 50%;
  background: #2f8f6c;
  color: #fff;
  display: none;
  align-items: center; justify-content: center;
  animation: duplicate-modal-pop .2s ease-out;
}
@keyframes submit-progress-spin {
  to { transform: rotate(360deg); }
}

#reimbursementSuccessModal .duplicate-modal-card {
  align-items: center;
  text-align: center;
  padding: 24px 22px 22px;
}
#reimbursementSuccessModal .submit-progress-check { display: flex; margin: 0 auto; }
#reimbursementSuccessModal h2 { text-align: center; }
#reimbursementSuccessModal .cancel-modal-actions .action-btn { width: 100%; }

@media (min-width: 540px) {
  .duplicate-modal { place-items: center; }
}

@media (max-width: 1180px) {
  .shell { grid-template-columns: 1fr; }
  .phone { position: static; width: min(100%, 440px); margin: 0 auto; }
  .desktop { grid-template-columns: 1fr; }
  .pdf-receipts { grid-template-columns: 1fr; }
}

/* Real phone: drop the device-mockup chrome so the app renders as a full-screen
   PWA instead of inside a fake iPhone bezel. The black frame, rounded corners and
   simulated "9:41" status bar are a desktop-only preview affordance; on an actual
   handset they make the staff app look like a mockup rather than an installed app.
   The .desktop column is an engineering-notes/PDF preview panel with no place on a
   phone. .bottom-bar is absolutely positioned within .screen, so a full-viewport
   .screen keeps it correctly anchored. */
@media (max-width: 640px) {
  /* On iOS the layout viewport (100vh) is TALLER than the visible viewport
     (100dvh) because vh reserves room for the collapsible URL bar. The
     .bottom-bar is absolutely positioned inside .screen (100dvh), so when body
     stays at 100vh the bar floats well above the true bottom of the visible
     screen, leaving the large dead gap below it. Pin every ancestor to the
     dynamic viewport so the screen — and the action bar anchored to it — ends
     exactly at the visible bottom. */
  html, body {
    min-height: 100dvh;
    height: 100dvh;
    overflow: hidden;
  }
  .shell {
    width: 100%;
    height: 100dvh;
    margin: 0;
    padding: 0;
    gap: 0;
    grid-template-columns: 1fr;
  }
  .phone {
    position: static;
    width: 100%;
    height: 100dvh;
    margin: 0;
    background: none;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
  }
  .screen {
    height: 100dvh;
    min-height: 100dvh;
    border-radius: 0;
  }
  /* Simulated handset status bar — redundant behind the real one on a phone. */
  .statusbar { display: none; }
  /* Clear the real status bar / notch when running full-screen or installed. */
  .header,
  .header-compact { padding-top: calc(10px + env(safe-area-inset-top)); }
  /* Desktop-only operator notes + PDF preview panel. */
  .desktop { display: none; }
  /* Anchor the action bar to the very bottom of the visible viewport, lifted
     only by the iPhone home-indicator safe area plus a small margin. This pushes
     the Stripe Link / Send Invoice (and Capture Receipt) buttons down to the
     bottom of the screen instead of floating mid-screen. */
  .bottom-bar { inset: auto 10px calc(8px + env(safe-area-inset-bottom)); }
}

.final-review-card { padding: 14px; gap: 10px; }
.final-review-title { font-size: 15px; line-height: 1.25; }
.final-review-body {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 12px;
  align-items: start;
}
.final-review-thumb {
  width: 64px;
  min-height: 64px;
  max-height: 120px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--cream, #f4ede2);
  border: 1px solid rgba(0,0,0,0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(0,0,0,0.45);
  flex-shrink: 0;
}
.final-review-thumb img {
  width: 100%;
  height: auto;
  max-height: 120px;
  object-fit: contain;
  display: block;
}
.final-review-fields {
  margin: 0;
  display: grid;
  gap: 6px;
  min-width: 0;
}
.final-review-row {
  display: grid;
  grid-template-columns: 76px 1fr;
  gap: 8px;
  align-items: baseline;
}
.final-review-row dt {
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(0,0,0,0.55);
  font-weight: 600;
}
.final-review-row dd {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  color: inherit;
  word-break: break-word;
}

/* =========================================================================
   Install prompt — Android/Chromium native banner + iPhone instruction sheet
   ========================================================================= */

/* Persistent "Install SAVINA on your phone" link on the sign-in card. Always
   available so the prompt is never permanently hidden by a 7-day dismissal. */
.install-link {
  margin-top: 2px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.install-link.hidden { display: none; }

.install-banner {
  position: fixed;
  left: 50%;
  bottom: 16px;
  transform: translate(-50%, 24px);
  z-index: 90;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  width: min(calc(100% - 24px), 480px);
  padding: 12px 14px;
  background: var(--color-surface, #fbf8f3);
  color: var(--color-text, #28251d);
  border: 1px solid var(--color-border, rgba(40,37,29,.11));
  border-radius: var(--radius-md, 18px);
  box-shadow: var(--shadow-md, 0 16px 40px rgba(35,28,23,.18));
  opacity: 0;
  transition: opacity .22s ease, transform .22s ease;
  /* Respect iPhone home-indicator safe area. */
  padding-bottom: max(12px, calc(env(safe-area-inset-bottom) + 8px));
  bottom: max(16px, calc(env(safe-area-inset-bottom) + 8px));
}
.install-banner.hidden { display: none; }
.install-banner.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}
.install-banner-icon {
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full, 999px);
  background: var(--color-primary, #1b5b57);
  color: #fff;
}
.install-banner-icon svg { width: 22px; height: 22px; }
.install-banner-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.install-banner-title {
  font-size: 13px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--color-text, #28251d);
}
.install-banner-meta {
  font-size: 11.5px;
  line-height: 1.3;
  color: var(--color-text-muted, #706a63);
}
.install-banner-actions {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: stretch;
}
.install-banner-primary {
  appearance: none;
  border: 0;
  background: var(--color-primary, #1b5b57);
  color: #fff;
  font-family: inherit;
  font-weight: 600;
  font-size: 12.5px;
  padding: 8px 14px;
  border-radius: var(--radius-full, 999px);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color .15s ease;
}
.install-banner-primary:hover,
.install-banner-primary:focus-visible {
  background: var(--color-primary-hover, #144844);
}
.install-banner-dismiss {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--color-text-muted, #706a63);
  font-family: inherit;
  font-size: 11.5px;
  padding: 4px 6px;
  cursor: pointer;
}
.install-banner-dismiss:hover { color: var(--color-text, #28251d); }

@media (min-width: 480px) {
  .install-banner-actions {
    flex-direction: row;
    align-items: center;
  }
}

.install-sheet {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  padding: 16px;
  opacity: 0;
  transition: opacity .18s ease;
}
.install-sheet.hidden { display: none; }
.install-sheet.is-visible { opacity: 1; }
.install-sheet-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 18, 14, 0.5);
}
.install-sheet-card {
  position: relative;
  width: min(100%, 420px);
  background: var(--color-surface, #fbf8f3);
  color: var(--color-text, #28251d);
  border-radius: var(--radius-lg, 26px);
  padding: 22px 22px 18px;
  box-shadow: var(--shadow-md, 0 16px 40px rgba(35,28,23,.20));
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: calc(100vh - 32px);
  overflow-y: auto;
}
.install-sheet-eyebrow {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted, #706a63);
  font-weight: 600;
}
.install-sheet-card h2 {
  margin: 0;
  font-family: var(--font-display, Georgia, serif);
  font-size: 22px;
  line-height: 1.2;
  color: var(--color-text, #28251d);
}
.install-sheet-steps {
  margin: 6px 0 4px;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.install-sheet-steps li {
  display: grid;
  grid-template-columns: 28px 1fr;
  gap: 10px;
  align-items: flex-start;
  font-size: 14px;
  line-height: 1.4;
}
.install-sheet-step-num {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-full, 999px);
  background: var(--color-surface-2, #f0e9de);
  color: var(--color-primary, #1b5b57);
  font-weight: 700;
  font-size: 12px;
}
.install-sheet-step-text strong { font-weight: 700; }
.install-sheet-glyph {
  display: inline-grid;
  place-items: center;
  vertical-align: -4px;
  width: 22px;
  height: 22px;
  margin: 0 2px;
  border-radius: 6px;
  background: var(--color-surface-2, #f0e9de);
  color: var(--color-primary, #1b5b57);
}
.install-sheet-note {
  margin: 0;
  font-size: 12.5px;
  color: var(--color-text-muted, #706a63);
  line-height: 1.4;
}
.install-sheet-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: 4px;
}
.install-sheet-close {
  appearance: none;
  border: 0;
  background: var(--color-primary, #1b5b57);
  color: #fff;
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
  padding: 10px 18px;
  border-radius: var(--radius-full, 999px);
  cursor: pointer;
  transition: background-color .15s ease;
}
.install-sheet-close:hover,
.install-sheet-close:focus-visible {
  background: var(--color-primary-hover, #144844);
}

/* ─── Villa Receipts: 30-day accepted list + search ───────────────────────── */
/* The accepted-receipts list lives on the Villa home (capture step). Rows are
   tappable and open the Villa action popup (View/Edit/Delete/Close). */
.accepted-list-card { margin-top: 12px; }
.accepted-search-wrap { margin: 10px 0 6px; }
.accepted-search-input { width: 100%; }
.accepted-list { display: flex; flex-direction: column; gap: 6px; max-height: 340px; overflow-y: auto; }
.accepted-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; text-align: left; padding: 10px 12px;
  background: var(--color-surface-2); border: 1px solid var(--color-border);
  border-radius: var(--radius-sm); cursor: pointer;
}
.accepted-row:hover, .accepted-row:focus-visible { background: var(--color-surface-accent); }
.accepted-row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.accepted-row-vendor { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.accepted-row-date { font-size: 11px; color: var(--color-text-muted); }
.accepted-row-side {
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
  flex-shrink: 0; text-align: right;
}
.accepted-row-amount { font-weight: 600; }
.accepted-row-tags {
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 4px;
}
.payment-tag, .category-tag {
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
  padding: 2px 8px; border-radius: var(--radius-full);
  background: var(--color-surface-accent); border: 1px solid var(--color-border);
  color: var(--color-text-muted); white-space: nowrap;
}
.accepted-empty { color: var(--color-text-muted); font-size: 13px; padding: 12px 4px; text-align: center; }
.accepted-error {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  color: var(--color-error); font-size: 13px; padding: 12px 4px; text-align: center;
}
.accepted-error .link-button {
  background: none; border: none; padding: 4px 8px; cursor: pointer;
  color: var(--color-accent); font: inherit; font-weight: 600; text-decoration: underline;
}

/* Villa final-submit popup: owner toggle + Form-of-Payment segmented control. */
.final-submit-group { margin: 12px 0; display: flex; flex-direction: column; gap: 6px; text-align: left; }
.final-submit-group > span { font-size: 12px; font-weight: 600; color: var(--color-text-muted); }
.segmented { display: flex; gap: 6px; }
.segmented button {
  flex: 1; padding: 9px 6px; border-radius: var(--radius-sm);
  border: 1px solid var(--color-border); background: var(--color-surface-2);
  font-weight: 600; cursor: pointer; color: var(--color-text);
}
.segmented button[aria-pressed="true"] {
  background: var(--color-primary, #186157); color: #fff; border-color: transparent;
}

/* ── Safe Cash Reconciliation ─────────────────────────────────────────────── */
.accepted-row-meta { font-size: 11px; color: var(--color-text-muted); }
.link-button {
  background: none; border: none; padding: 4px 8px; cursor: pointer;
  color: var(--color-accent); font: inherit; font-weight: 600; text-decoration: underline;
  flex-shrink: 0;
}
.link-button.danger { color: var(--color-error); }

.safe-recon-section { display: flex; flex-direction: column; gap: 10px; }
.safe-recon-add-btn { flex-shrink: 0; }
.safe-recon-balances { margin-top: 12px; }
/* The shared .totals-card is a 3-column grid (label | amount | currency) for the
   guest composer. The Safe Recon summary instead holds a single full-width
   final-review dl, so collapse the inherited grid to one column — otherwise the
   reserved amount/currency tracks push the content left and the card's left and
   right margins look unequal. */
.safe-recon-totals {
  margin-top: 4px;
  grid-template-columns: 1fr;
}
/* Safe Recon summary + balance rows are a clean two-column layout: the label
   sits left on a single row (it shrinks to fit instead of wrapping into a fixed
   76px column) and the amount is right-justified in its own column. Scoped to
   Safe Recon so the shared folio .final-review-row layout is untouched. */
.safe-recon-balances .final-review-row,
.safe-recon-totals .final-review-row {
  grid-template-columns: 1fr auto;
  gap: 12px;
  align-items: baseline;
}
.safe-recon-balances .final-review-row dt,
.safe-recon-totals .final-review-row dt {
  white-space: nowrap;
}
.safe-recon-balances .final-review-row dd,
.safe-recon-totals .final-review-row dd {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  word-break: normal;
}
.safe-recon-queue-row, .safe-recon-item-row { cursor: default; }
.safe-recon-queue-row.is-selected { border-color: var(--color-primary, #186157); }
.safe-recon-queue-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
/* The cash-receipt card sits beside the checkbox in the flex .queue-main row and
   must grow to fill the remaining width (teal selected state comes from the
   shared .send-card.is-selected rule, matching the guest invoice queue). */
.safe-recon-receipt-card { flex: 1; }
/* Full-page Safe Recon preview: the on-screen render of the exact sheet that
   gets shared as the PDF. A single narrow (468px) white column centered on the
   view, mobile-readable, so what staff review is what the guest/owner receives.
   max-width keeps it fluid: on phones narrower than 468px it shrinks to fit
   rather than forcing horizontal scroll. */
.safe-recon-preview-frame {
  max-width: 468px; margin: 0 auto;
  background: #fff; color: #1a1a1a;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 24px 20px;
  box-shadow: 0 1px 4px rgba(0,0,0,.06);
  font-variant-numeric: tabular-nums;
}
.safe-recon-preview-hint {
  max-width: 468px; margin: 12px auto 0;
  color: var(--color-text-muted); font-size: .82rem; text-align: center;
}
/* Payroll row: name on the left, amount field (and optional Remove) pinned to
   the right so every editable amount lines up on the right edge of the card. */
.safe-recon-payout-row { align-items: center; }
.safe-recon-payout-row .accepted-row-vendor { flex: 1; min-width: 0; }
.safe-recon-payout-side {
  display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin-left: auto;
}
.safe-recon-payout-amount {
  width: 96px; padding: 6px 8px; text-align: right;
  border: 1px solid var(--color-border, #d9d9d9); border-radius: 8px;
  font: inherit; font-size: 13px; color: var(--color-text); background: var(--color-surface, #fff);
  font-variant-numeric: tabular-nums;
}
/* "Cash Added to Safe" row: keep the label on one row (it shrinks to its text
   instead of a fixed 88px column that forces a wrap) and give the number field
   its own narrower, right-justified column rather than a full-width input. */
.validation-edit-row[data-row="cash-added"] {
  grid-template-columns: 1fr auto;
  align-items: center;
}
.validation-edit-row[data-row="cash-added"] .validation-label {
  white-space: nowrap;
}
.validation-edit-row[data-row="cash-added"] .validation-input {
  width: 140px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 380px) {
  /* The global 380px rule stacks every edit row to one column; re-assert the
     two-column cash-added layout so its label + amount stay side by side. */
  .validation-edit-row[data-row="cash-added"] {
    grid-template-columns: 1fr auto;
    gap: 10px 12px;
  }
}
.safe-recon-payout-amount:focus { outline: none; border-color: var(--color-primary, #186157); }

/* Safe Cash Adjustment: a +/- sign toggle sits in front of the (positive-entry)
   amount field. The selected button shades green for + (adds to the safe) or red
   for − (removes), so the stored direction is unmistakable. */
.safe-recon-adjust-amount-row {
  display: flex; align-items: center; gap: 10px;
}
.safe-recon-adjust-amount-row .validation-input {
  flex: 1; min-width: 0; text-align: right; font-variant-numeric: tabular-nums;
}
.safe-recon-sign-toggle {
  display: inline-flex; flex-shrink: 0; border-radius: 9px; overflow: hidden;
  border: 1px solid var(--color-border, #d9d9d9);
}
.safe-recon-sign-btn {
  width: 40px; padding: 8px 0; font: inherit; font-size: 1.05rem; font-weight: 700;
  line-height: 1; cursor: pointer; background: var(--color-surface, #fff);
  color: var(--color-text-muted, #6b6b6b); border: none; transition: background .12s, color .12s;
}
.safe-recon-sign-btn + .safe-recon-sign-btn {
  border-left: 1px solid var(--color-border, #d9d9d9);
}
.safe-recon-sign-btn.is-selected-plus {
  background: #d6f3e2; color: #15803d;
}
.safe-recon-sign-btn.is-selected-minus {
  background: #fbdcdc; color: #b91c1c;
}

/* ───────────────────────────────────────────────────────────────────────────
   Desktop Bulk Upload (Phase 1) — Villa Receipts only.

   The Bulk Upload entry control and overlay are DESKTOP ONLY. `.desktop-only-control`
   is hidden by default (touch-primary phones/tablets never see it) and revealed
   only on devices with a precise pointer + hover — the same
   (hover: hover) and (pointer: fine) gate isDesktopCapture() uses in JS, so the
   visible affordance and the active behavior always agree. The mobile
   one-at-a-time camera/library flow is untouched. */
.desktop-only-control { display: none; }
@media (hover: hover) and (pointer: fine) {
  .savina-bulk-open.desktop-only-control:not(.hidden) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    margin: 12px 0 0;
  }
}

/* The overlay is fixed to the full viewport so bulk review has room on desktop,
   escaping the narrow phone shell. Always hidden when `.hidden` is present; JS
   only removes `.hidden` after an isDesktopCapture() guard. */
.savina-bulk-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px 24px;
  background: rgba(20, 18, 13, .55);
  overflow-y: auto;
}
.savina-bulk-overlay.hidden { display: none; }
.savina-bulk-panel {
  width: min(1100px, 100%);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 24px 26px 30px;
  box-shadow: 0 24px 60px rgba(20, 18, 13, .35);
}
.savina-bulk-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}
.savina-bulk-heading h2 { margin: 4px 0 2px; }
.savina-bulk-sub { margin: 0; color: var(--color-text-muted); font-size: 13px; }
.savina-bulk-close { flex: 0 0 auto; }

.savina-bulk-dropzone {
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-2);
  padding: 22px 18px;
  text-align: center;
  transition: border-color .18s ease, background .18s ease;
}
.savina-bulk-dropzone.is-dragging {
  border-color: rgba(27, 91, 87, .55);
  background: rgba(27, 91, 87, .08);
}
.savina-bulk-dropzone-title { margin: 0 0 4px; font-weight: 600; }
.savina-bulk-dropzone-hint { margin: 0 0 14px; color: var(--color-text-muted); font-size: 12px; }

.savina-bulk-statusbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 16px 2px 8px;
}
.savina-bulk-count { font-weight: 600; font-size: 13px; }
.savina-bulk-limit-msg { color: #b91c1c; font-size: 12px; text-align: right; }

.savina-bulk-rows { display: flex; flex-direction: column; gap: 14px; }
.savina-bulk-empty { color: var(--color-text-muted); font-size: 13px; text-align: center; padding: 18px 0; }
.savina-bulk-rows:not(:empty) + .savina-bulk-empty { display: none; }

.savina-bulk-row {
  display: grid;
  grid-template-columns: 96px 1fr auto;
  gap: 16px;
  align-items: start;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  padding: 14px;
}
.savina-bulk-row[data-status="submitted"] { opacity: .72; }
.savina-bulk-row[data-status="error"] { border-color: rgba(185, 28, 28, .55); }

.savina-bulk-thumb {
  width: 96px;
  height: 120px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--color-surface-2);
  border: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: center;
}
.savina-bulk-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.savina-bulk-thumb-pdf { font-size: 11px; font-weight: 600; color: var(--color-text-muted); letter-spacing: .04em; }
button.savina-bulk-pdf-open {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--color-primary, #1b5b57);
  transition: background .16s ease;
}
button.savina-bulk-pdf-open:hover,
button.savina-bulk-pdf-open:focus-visible { background: rgba(27, 91, 87, .08); outline: none; }
.savina-bulk-pdf-badge {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  background: rgba(27, 91, 87, .12);
  color: var(--color-primary, #1b5b57);
}
.savina-bulk-pdf-hint { font-size: 11px; font-weight: 600; text-decoration: underline; }

.savina-bulk-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; }
.savina-bulk-field { display: flex; flex-direction: column; gap: 4px; }
.savina-bulk-field.full { grid-column: 1 / -1; }
.savina-bulk-field label { font-size: 11px; font-weight: 600; color: var(--color-text-muted); }
.savina-bulk-field .validation-input { width: 100%; }
.savina-bulk-amount { display: grid; grid-template-columns: 1fr 88px; gap: 8px; }

.savina-bulk-segmented { display: inline-flex; gap: 6px; }
.savina-bulk-segmented button {
  border: 1px solid var(--color-border);
  background: var(--color-surface-2);
  border-radius: var(--radius-full);
  padding: 5px 12px;
  font-size: 12px;
  cursor: pointer;
}
.savina-bulk-segmented button[aria-pressed="true"] {
  background: #1b5b57;
  color: #fff;
  border-color: #1b5b57;
}

.savina-bulk-side { display: flex; flex-direction: column; align-items: flex-end; gap: 8px; min-width: 130px; }
.savina-bulk-status-pill {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  background: var(--color-surface-2);
  color: var(--color-text-muted);
}
.savina-bulk-row[data-status="ready"] .savina-bulk-status-pill { background: #d6f3e2; color: #15803d; }
.savina-bulk-row[data-status="scanning"] .savina-bulk-status-pill,
.savina-bulk-row[data-status="submitting"] .savina-bulk-status-pill { background: #fef3c7; color: #92400e; }
.savina-bulk-row[data-status="submitted"] .savina-bulk-status-pill { background: #1b5b57; color: #fff; }
.savina-bulk-row[data-status="error"] .savina-bulk-status-pill { background: #fbdcdc; color: #b91c1c; }
.savina-bulk-row-msg { font-size: 11px; color: #b91c1c; text-align: right; max-width: 180px; }
.savina-bulk-row-submit:disabled { opacity: .5; cursor: not-allowed; }
.savina-bulk-row-remove { font-size: 12px; }
