/*
  Owner/Manager app design tokens — TWO full themes, 2026-08-18. Light was
  built first (matching a reference screenshot, then extended app-wide:
  "make the entire remy white theme just like the catalogue"). Dark is the
  ORIGINAL palette this app launched with, restored here rather than left
  behind — each theme gets values actually designed for it, not one
  theme's choices reused on the other's background. Switched via
  `data-theme="dark"` on `<html>`, set by `src/theme.ts`; light is the
  bare `:root` default so the app still renders correctly even before
  that attribute is applied.

  Every screen in this app is built purely from these tokens plus a
  handful of shared classes below — confirmed by grepping the whole `src`
  tree for hardcoded colors: only this file and (briefly) Catalogue.css
  ever had any. That discipline is what makes a single token swap enough
  to re-theme the entire app both ways, no per-screen work needed.

  `critical` is the one thing that differs in MECHANISM, not just value,
  between the themes — see each block below for why.
*/
:root {
  /* ── Light (default) ──────────────────────────────────────────────── */
  --bg-base: #f5f6f8;
  --surface: #ffffff;
  --surface-raised: #eef0f3;
  --surface-hover: #e4e6ea;
  --border-hairline: #e8e9ec;

  --ink-primary: #16171a;
  --ink-secondary: #6b7280;
  --ink-tertiary: #9ca3af;

  --accent: #16171a; /* the single loud mark — near-black, never a hue */
  --accent-ink: #ffffff;

  /* Semantic, by weight — minimal hue. `positive` is the one place a
     genuine (muted) green is allowed; `attention` a muted amber. On this
     theme `critical` is a real red block, not an inversion: with a
     near-black ACCENT already on this theme, an inverted block would be
     indistinguishable from an ordinary accent button — exactly backwards
     for a "rare, loudest signal" color.

     `positive` is warm/lemon-leaning (hue ~75°, the same family as the
     dark theme's literal accent below) on purpose, 2026-08-19 direct
     correction — the original was a cooler standard emerald that read as
     a completely different, mismatched green next to the tab bar's
     accent once both were visible on the same screen. */
  --positive: #6b8e0f;
  --positive-bg: #eef6d6;
  --attention: #b45309;
  --attention-bg: #fef3c7;
  --critical-bg: #fee2e2;
  --critical-ink: #b91c1c;

  --shadow-card: 0 1px 2px rgba(16, 17, 20, 0.04), 0 1px 12px rgba(16, 17, 20, 0.04);
  --shadow-fab: 0 8px 20px rgba(16, 17, 20, 0.25);
  --pill-count-active-bg: rgba(255, 255, 255, 0.2);

  /* Shape — not color, so identical in both themes. */
  --radius: 14px;
  --radius-lg: 20px;
  --radius-full: 999px;
  --sans: -apple-system, system-ui, 'Segoe UI', Roboto, sans-serif;
}

:root[data-theme="dark"] {
  /* ── Dark (original) ──────────────────────────────────────────────── */
  --bg-base: #0a0a0c;
  --surface: #16161a;
  --surface-raised: #202027;
  --surface-hover: #2a2a32;
  --border-hairline: #2c2c34;

  --ink-primary: #f5f5f7;
  --ink-secondary: #9a9aa5;
  --ink-tertiary: #6a6a75;

  --accent: #c8ff3d; /* the single electric mark — never a second hue */
  --accent-ink: #0a0a0c;

  /* `critical` here IS the inversion — never a red hue. On a near-black
     page, an inverted (light-on-dark-flipped-to-dark-on-light) block is
     the starkest thing on screen and reads as "loud" for free; this is
     the theme that mechanism was actually designed for.

     `positive` IS the accent here (2026-08-19 direct correction) — the
     tab bar's active color and "positive" money/state color used to be
     two different greens (a cooler standard emerald vs. this theme's
     actual lemon accent), which read as a mismatch once seen side by
     side. One green, not two. */
  --positive: var(--accent);
  --positive-bg: rgba(200, 255, 61, 0.12);
  --attention: #ffb020;
  --attention-bg: rgba(255, 176, 32, 0.1);
  --critical-bg: var(--ink-primary);
  --critical-ink: var(--bg-base);

  /* A drop shadow implies a light source falling on a light surface —
     backwards on a dark page, where elevation reads through a LIGHTER
     surface color instead (`--surface-raised` above `--surface`), same
     as this theme always did. The FAB still gets a little lift so it
     doesn't disappear into the page entirely. */
  --shadow-card: none;
  --shadow-fab: 0 8px 24px rgba(0, 0, 0, 0.55);
  --pill-count-active-bg: rgba(0, 0, 0, 0.15);
}

/* ── Mockup-spec alias tokens (2026-08-18) ─────────────────────────────────
   "Remy — The Complete Master Spec" and its companion tab specs embed their
   screens as literal HTML/CSS, styled against a naming scheme
   (`--surface-1`, `--text-muted`, `--fill-primary`, ...) that the spec
   itself says to "provide equivalents for in any host app." These are
   real aliases onto the tokens above, not a second competing palette —
   ported screens use the mockup's own variable names verbatim, cutting
   out an entire class of fidelity-losing hand-translation mistakes. They
   follow the light/dark switch automatically since they're built from
   `var()` references, not separate literal colors.

   `--text-accent`/`--bg-accent`/`--fill-accent` (the money card, links,
   avatar rings, OTP focus ring) alias onto `--positive` rather than a new
   hue — no mockup specifies a literal color for this role, and reusing
   "positive" keeps ONE deliberate accent (WhatsApp-adjacent green,
   money-adjacent "secured" framing) instead of inventing an arbitrary
   second one nobody asked for. */
:root {
  --surface-1: var(--bg-base);
  --surface-2: var(--surface);
  --border: var(--border-hairline);
  --text-secondary: var(--ink-secondary);
  --text-muted: var(--ink-tertiary);
  --text-accent: var(--positive);
  --bg-accent: var(--positive-bg);
  --fill-accent: var(--positive);
  --fill-primary: var(--accent);
  --on-primary: var(--accent-ink);
  --fill-success: var(--positive);
  --bg-success: var(--positive-bg);
  --text-success: var(--positive);
  --fill-control: var(--surface-raised);
  --bg-warning: var(--attention-bg);
  --text-warning: var(--attention);
  --bg-danger: var(--critical-bg);
  --text-danger: var(--critical-ink);

  --border-strong: #d1d5db;
  --on-success: #ffffff;
}

:root[data-theme="dark"] {
  --border-strong: #3a3a42;
  --on-success: #0a0a0c;
}

* {
  box-sizing: border-box;
}

/* Sign-in -> app transition (2026-08-18, see src/viewTransition.ts) — the
   browser's own default view-transition is a flat cross-fade; this swaps
   it for a quick, purposeful "settle": the outgoing screen fades and
   contracts slightly, the incoming one fades in from a touch larger than
   full size. Short (the whole thing is under a third of a second) and
   asymmetric on purpose — leaving is quicker than arriving, which reads
   as responsive rather than as a decoration. `prefers-reduced-motion`
   disables it entirely, not just shortens it. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) {
    animation: app-view-out 180ms cubic-bezier(0.4, 0, 1, 1) both;
  }
  ::view-transition-new(root) {
    animation: app-view-in 320ms cubic-bezier(0.16, 1, 0.3, 1) both;
  }
}

@keyframes app-view-out {
  to {
    opacity: 0;
    transform: scale(0.98);
  }
}

@keyframes app-view-in {
  from {
    opacity: 0;
    transform: scale(1.02);
  }
}

/* Real-device fix (2026-08-19) — without this, iOS Safari and some
   Android browsers auto-boost font sizes on pages taller than the
   viewport ("text inflation"), scaling `rem`-based sizing (the older
   shared classes: .accent-button, .card, .shell-content, Sheet.css) by a
   different factor than the newer ported screens' plain `px` sizing —
   the exact "every single part is a different ratio to the mockup on a
   real phone, fine in a desktop preview" symptom. Locking the root font
   size and disabling the OS's own text-inflation heuristic makes every
   `rem` and `px` value in the app resolve to the same physical size it
   was designed at, on every device. */
html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* Text size setting (2026-08-20, src/textSize.ts) — whole-page zoom, not
   a root font-size change: nearly every screen's type is plain `px` (the
   "Real-device fix" above deliberately locks root font-size so px stays
   consistent across devices), so only a uniform zoom reaches all of it
   at once, the same way a browser's own page zoom would. */
html[data-text-size="small"] {
  zoom: 0.9;
}
html[data-text-size="large"] {
  zoom: 1.2;
}

html,
body,
#root {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg-base);
  color: var(--ink-primary);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

#root {
  display: flex;
  flex-direction: column;
}

button,
input,
select,
textarea {
  font-family: inherit;
}

/* Browser default focus outlines are a hard-edged black rectangle that
   ignores field border-radius — replaced with a themed ring everywhere,
   so keyboard focus stays visible without looking broken. Screens whose
   input sits inside its own rounded wrapper (Login's pill fields) instead
   style the wrapper on :focus-within and opt their input out below, so
   the ring follows the pill shape exactly rather than drawing a rectangle
   inside a rounded corner. */
input,
textarea,
select {
  outline: none;
}

input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--fill-primary);
  outline-offset: 1px;
  border-radius: var(--radius);
}

button {
  cursor: pointer;
  border: none;
  color: inherit;
  background: none;
}

a,
a:visited {
  color: inherit;
  text-decoration: none;
}

/* Tabular figures everywhere a number appears in a column or as a hero
   figure (UX Group 1 §3: "the hero" — large, tabular, high contrast). */
.figure {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.accent-button,
.ghost-button {
  /* Motion Spec G7 — "pre-styled buttons already carry a small active
     scale"; money buttons (.btn-money) get a slightly deeper one. */
  transition: transform var(--dur-instant, 100ms) var(--ease-out, ease-out);
}
.accent-button:active,
.ghost-button:active {
  transform: scale(0.985);
}

.accent-button {
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--radius);
  font-weight: 700;
  padding: 0.85rem 1.5rem;
  min-height: 48px;
}

.accent-button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.ghost-button {
  background: var(--surface-raised);
  color: var(--ink-primary);
  border-radius: var(--radius);
  padding: 0.65rem 1.1rem;
  /* 44px (2026-08-14) — the real minimum tap target (Apple HIG/Material),
     used on almost every action in the app (Edit, Cancel, filter chips,
     Sign out); was 40px, just under it. */
  min-height: 44px;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
}

/* The one "loud" block in the whole palette — a critical Sentinel flag,
   an urgent attention-strip item. See the file header for why this is a
   real red on the light theme rather than the dark theme's inversion. */
.critical-block {
  background: var(--critical-bg);
  color: var(--critical-ink);
  border-radius: var(--radius);
}

.attention-block {
  background: var(--attention-bg);
  color: var(--attention);
  border-radius: var(--radius);
}

.positive-block {
  background: var(--positive-bg);
  color: var(--positive);
  border-radius: var(--radius);
}

.read-only-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--ink-secondary);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* ── Pill tabs — 2026-08-18, extracted from Catalogue's own filter pills
   so any screen needing a segmented filter/tab control uses the SAME
   pattern, not a per-screen reimplementation. `.pill-group` for the
   row, `.pill` per option, `.pill-active` on the selected one,
   `.pill-count` for an optional trailing count bubble. */
.pill-group {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
}

.pill {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  border: none;
  border-radius: var(--radius-full);
  padding: 0.55rem 0.9rem;
  font-size: 0.85rem;
  font-weight: 600;
  white-space: nowrap;
  background: var(--surface-raised);
  color: var(--ink-secondary);
}

.pill.pill-active {
  background: var(--accent);
  color: var(--accent-ink);
}

.pill-count {
  background: rgba(107, 114, 128, 0.14);
  color: inherit;
  border-radius: var(--radius-full);
  padding: 0.05rem 0.45rem;
  font-size: 0.75rem;
  font-weight: 700;
}

.pill.pill-active .pill-count {
  background: var(--pill-count-active-bg);
}

/* ── List rows — 2026-08-18, extracted after the SAME bordered-list-of-
   icon+title+summary+chevron/badge-rows pattern appeared identically
   across the Business tab landing and Settings landing (both ported from
   the master spec's own mockups, which use this shape everywhere). One
   definition, not a third near-duplicate CSS block. */
.list-card {
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.list-row {
  width: 100%;
  padding: 11px 12px;
  display: flex;
  gap: 10px;
  align-items: center;
  border-bottom: 0.5px solid var(--border);
  background: none;
  text-align: left;
  color: inherit;
  /* Every list-row navigates somewhere, so every one is ripple-able
     (Motion Spec C4) — folded into the base rule rather than a
     `rippleable` class added at each of the ~15 call sites; the
     container it lives in attaches ONE delegated pointerdown handler
     (motion.ts's `onRippleWithin`). */
  position: relative;
  overflow: hidden;
}

.list-row:last-child {
  border-bottom: none;
}

.list-row-icon {
  color: var(--text-secondary);
  flex-shrink: 0;
}

.list-row-text {
  flex: 1;
  min-width: 0;
}

.list-row-title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

.list-row-summary {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.list-row-chevron {
  color: var(--text-muted);
  flex-shrink: 0;
}

.list-row-badge {
  font-size: 11px;
  padding: 2px 7px;
  border-radius: 10px;
  font-weight: 500;
  flex-shrink: 0;
  /* Motion Spec G6 — every count/status badge in the app shares this
     shape, so the pop-in lives here once rather than being tagged onto
     each usage site. */
  animation: badgePop var(--dur-slow) var(--ease-spring) both;
}

.list-row-badge-warning {
  background: var(--bg-warning);
  color: var(--text-warning);
}

.list-row-badge-accent {
  background: var(--bg-accent);
  color: var(--text-accent);
}

.list-row-badge-success {
  background: var(--bg-success);
  color: var(--text-success);
}

.list-row-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 4px;
  flex-shrink: 0;
}

.list-section-label {
  padding: 0 16px 6px;
  margin: 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
}

/* Balance hide/reveal eye toggle (2026-08-19) — ported from Login's
   password-visibility button; used next to any headline money figure
   (Home's "Secured today", Insights' "Secured this week/today") to mask
   just that figure, never the surrounding counts. */
.money-eye-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-accent);
  opacity: 0.75;
  background: none;
  border: none;
  padding: 4px;
  flex-shrink: 0;
}

/* The real value stays mounted (visibility: hidden, not removed) so its
   count-up animation always has a live target — see the ref comment in
   Home.tsx/Insights.tsx for why swapping it out was a real bug, not
   just unnecessary. The mask is a plain sibling laid on top. */
.money-value-stack {
  position: relative;
}

.money-value-mask {
  position: absolute;
  inset: 0;
  margin: 0;
}
/*
  Motion system — ported from "Remy — Motion & Animation Spec"
  (2026-08-19). Tokens and keyframes are kept verbatim from the spec (Part
  B onward) so every duration/easing traces back to one source; the JS
  glue in motion.ts adapts the spec's vanilla-DOM helpers to React
  idioms (event handlers, refs) where a straight port would fight React's
  render cycle, without changing any visible timing or behavior.

  Load order: index.css (tokens/reset) → this file, per Part I rule 2.
*/
:root {
  --dur-instant: 100ms;
  --dur-fast: 180ms;
  --dur-base: 240ms;
  --dur-slow: 320ms;
  --dur-page: 360ms;
  --dur-splash: 700ms;
  --dur-theme: 360ms;

  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  --scrim: rgba(15, 15, 15, 0.42);
  --shimmer-highlight: rgba(255, 255, 255, 0.35);
}

:root[data-theme="dark"] {
  --scrim: rgba(0, 0, 0, 0.55);
  --shimmer-highlight: rgba(255, 255, 255, 0.08);
}

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

/* ── Theme cross-fade (Appearance & Theme Spec Part E) — added only on
   user-initiated changes (see theme.ts), never on initial load, so
   launch stays instant and only switches animate. */
.theme-animating,
.theme-animating * {
  transition:
    background-color var(--dur-theme) var(--ease-in-out),
    color var(--dur-theme) var(--ease-in-out),
    border-color var(--dur-theme) var(--ease-in-out),
    fill var(--dur-theme) var(--ease-in-out) !important;
}

/* ── C3. Tab switch — content falls from above. Applied directly to each
   top-level screen's own root element (Home, Business, Inbox, Insights,
   Settings) — switching tabs unmounts/remounts that root via React
   Router, so the animation replays for free with no JS needed for the
   common case. */
.tab-content-enter > * {
  animation: fallIn var(--dur-base) var(--ease-out) both;
}
.tab-content-enter > *:nth-child(1) {
  animation-delay: 0ms;
}
.tab-content-enter > *:nth-child(2) {
  animation-delay: 50ms;
}
.tab-content-enter > *:nth-child(3) {
  animation-delay: 100ms;
}
.tab-content-enter > *:nth-child(4) {
  animation-delay: 150ms;
}
.tab-content-enter > *:nth-child(n + 5) {
  animation-delay: 200ms;
}
@keyframes fallIn {
  from {
    opacity: 0;
    transform: translateY(-14px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ── C4. Ripple halo — nav tabs, chips, tiles, navigating rows. */
.rippleable {
  position: relative;
  overflow: hidden;
}
.ripple {
  position: absolute;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.16;
  transform: scale(0);
  pointer-events: none;
  animation: rippleOut 450ms var(--ease-out) forwards;
}
@keyframes rippleOut {
  to {
    transform: scale(2.4);
    opacity: 0;
  }
}

/* ── D1. Full-screen loading overlay — genuine blocking waits only. */
.loading-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  background: var(--scrim);
  backdrop-filter: blur(2px);
  animation: overlayIn var(--dur-fast) var(--ease-out) both;
}
.loading-overlay.leaving {
  animation: overlayOut var(--dur-fast) var(--ease-in-out) forwards;
}
@keyframes overlayIn {
  from {
    opacity: 0;
  }
}
@keyframes overlayOut {
  to {
    opacity: 0;
  }
}
.spinner {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--on-primary) 25%, transparent);
  border-top-color: var(--on-primary);
  animation: spin 800ms linear infinite;
}
.spinner-inline {
  border-color: color-mix(in srgb, var(--text-secondary) 25%, transparent);
  border-top-color: var(--text-secondary);
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ── D2. Skeleton shimmer. */
.skel {
  position: relative;
  overflow: hidden;
  background: var(--fill-control);
  border-radius: 6px;
}
.skel::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--shimmer-highlight), transparent);
  animation: shimmer 1.4s infinite;
}
@keyframes shimmer {
  100% {
    transform: translateX(100%);
  }
}
.skel-circle {
  border-radius: 50%;
}
.skel-line {
  height: 12px;
}
.skel-line.sm {
  height: 10px;
}

/* ── F1. Bottom sheets. */
.sheet-overlay {
  animation: overlayIn var(--dur-fast) var(--ease-out) both;
}
.sheet-card {
  animation: sheetUp var(--dur-base) var(--ease-out) both;
}
.sheet-card.leaving {
  animation: sheetDown var(--dur-fast) var(--ease-in-out) forwards;
}
@keyframes sheetUp {
  from {
    transform: translateY(28px);
    opacity: 0;
  }
}
@keyframes sheetDown {
  to {
    transform: translateY(100%);
    opacity: 0;
  }
}

/* ── F2. Blocking modals (grace countdown, PIN prompt, confirms). */
.modal-card {
  animation: modalIn var(--dur-base) var(--ease-spring) both;
}
@keyframes modalIn {
  from {
    opacity: 0;
    transform: scale(0.94) translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ── G2. Success check draw. */
.check path {
  stroke-dasharray: 26;
  stroke-dashoffset: 26;
  animation: checkDraw var(--dur-slow) var(--ease-out) 80ms forwards;
}
@keyframes checkDraw {
  to {
    stroke-dashoffset: 0;
  }
}

/* ── G3. PIN entry — dot fill + wrong-PIN shake. */
.pin-row {
  position: relative;
  display: flex;
  gap: 18px;
  justify-content: center;
  padding: 10px 0;
}
.pin-hidden-input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}
.pin-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1.5px solid var(--border-strong);
  transition:
    transform var(--dur-instant) var(--ease-spring),
    background var(--dur-instant);
}
.pin-dot.filled {
  transform: scale(1.15);
  background: var(--fill-primary);
  border-color: var(--fill-primary);
}
.pin-row.error {
  animation: shake 320ms var(--ease-in-out);
}
@keyframes shake {
  10%,
  90% {
    transform: translateX(-2px);
  }
  20%,
  80% {
    transform: translateX(4px);
  }
  30%,
  50%,
  70% {
    transform: translateX(-5px);
  }
  40%,
  60% {
    transform: translateX(5px);
  }
}

/* ── G4. Priority item resolve — slide out and collapse. */
.resolving {
  animation: slideOutRight var(--dur-base) var(--ease-in-out) forwards;
  overflow: hidden;
}
@keyframes slideOutRight {
  to {
    transform: translateX(16%);
    opacity: 0;
  }
}

/* ── G6. Liveness dot breathing + badge pop. */
.dot-live {
  animation: breathe 2.4s var(--ease-in-out) infinite;
}
@keyframes breathe {
  0%,
  100% {
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--fill-success) 40%, transparent);
  }
  60% {
    box-shadow: 0 0 0 6px transparent;
  }
}
.badge-pop {
  animation: badgePop var(--dur-slow) var(--ease-spring) both;
}
@keyframes badgePop {
  0% {
    transform: scale(0);
  }
  70% {
    transform: scale(1.15);
  }
  100% {
    transform: scale(1);
  }
}

/* ── G7. Money-button press. */
.btn-money {
  transition: transform var(--dur-instant) var(--ease-out);
}
.btn-money:active {
  transform: scale(0.97);
}
/* Mobile-native bottom sheet, desktop centered dialog — one component,
   CSS-driven (same "widen, don't become a different app" rule AppShell's
   own header comment states), extracted 2026-08-14 from 8 screens that
   had each been hand-rolling a fixed-width (380px) centered overlay —
   the exact pattern that sat right at the edge of a 375px phone screen. */
.sheet-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 10;
}

.sheet-card {
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  padding: 1.5rem;
  /* Clears the home-indicator/gesture bar the same way the bottom nav
     does — a sheet's own action buttons must never sit under it. */
  padding-bottom: max(1.5rem, calc(env(safe-area-inset-bottom) + 1rem));
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  /* Rounded top corners only on mobile — it visually continues off the
     bottom edge of the screen, the standard "sheet," not "floating card,"
     read (iOS action sheets / Android bottom sheets both do this). */
  border-radius: var(--radius) var(--radius) 0 0;
  border-bottom: none;
}

/* For sheets that own their full internal layout (header/body/footer,
   each with its own padding) — DetailSheet-family sheets (payment
   confirmation, escalation). */
.sheet-flush {
  padding: 0;
}

@media (min-width: 640px) {
  .sheet-overlay {
    align-items: center;
  }
  .sheet-card {
    width: 420px;
    max-width: 90vw;
    max-height: 90vh;
    border-radius: var(--radius);
    border-bottom: 1px solid var(--border-hairline);
  }
}
/*
  Sign-in page — ported 1:1 from "Remy — Sign In & Authentication Spec v2"
  Part H1 (2026-08-18). The mockup's own outer wrapper (padding + rounded
  frame around the screen) is the design-review tool's device-preview
  chrome, not part of the screen itself — every other screen in this app
  already renders full-bleed on the real viewport (safe-area insets, no
  nested "card floating in a page" treatment), so that part is dropped;
  everything INSIDE it (spacing, copy, order, colors) is kept exactly.
  Uses the mockup-alias tokens in index.css (`--surface-1`, `--fill-
  primary`, `--text-accent`, etc.) so this reads directly against the
  mockup's own variable names.
*/
.auth-page {
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--surface-1);
  display: flex;
  flex-direction: column;
  padding-top: env(safe-area-inset-top);
  padding-bottom: env(safe-area-inset-bottom);
}

.auth-brand {
  padding: 44px 24px 20px;
  text-align: center;
}

.auth-logo {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: var(--fill-primary);
  color: var(--on-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 14px;
}

.auth-title {
  margin: 0;
  font-size: 24px;
  font-weight: 500;
}

.auth-tagline {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--text-secondary);
}

.auth-form {
  padding: 0 24px;
  flex: 1;
  display: flex;
  flex-direction: column;
}

.auth-field-label {
  margin: 0 0 6px;
  font-size: 12px;
  color: var(--text-secondary);
}

.auth-phone-row {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.auth-phone-code {
  border: 0.5px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 0 12px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 500;
  flex-shrink: 0;
}

.auth-input-wrap {
  flex: 1;
  border: 0.5px solid var(--border-strong);
  border-radius: var(--radius);
  padding: 0 12px;
  display: flex;
  align-items: center;
}

.auth-input-wrap:focus-within,
.auth-password-wrap:focus-within {
  border-color: var(--fill-primary);
}

.auth-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  color: var(--ink-primary);
  font-size: 14px;
  padding: 10px 0;
}

.auth-input:focus-visible {
  outline: none;
}

.auth-input::placeholder {
  color: var(--text-muted);
}

.auth-password-wrap {
  border: 0.5px solid var(--border);
  border-radius: var(--radius);
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.auth-eye-btn {
  display: flex;
  align-items: center;
  color: var(--text-muted);
  background: none;
  border: none;
  padding: 8px 0 8px 8px;
}

.auth-forgot {
  margin: 0 0 16px;
  font-size: 12px;
  color: var(--text-accent);
  font-weight: 500;
  text-align: right;
  background: none;
  border: none;
  display: block;
  width: 100%;
}

.auth-submit {
  width: 100%;
  background: var(--fill-primary);
  color: var(--on-primary);
  border: none;
  border-radius: var(--radius);
  min-height: 44px;
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 12px;
}

.auth-submit:disabled {
  opacity: 0.5;
}

.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 4px 0 16px;
}

.auth-divider-line {
  flex: 1;
  height: 0.5px;
  background: var(--border);
}

.auth-divider-text {
  font-size: 11px;
  color: var(--text-muted);
}

.auth-secondary-btn {
  width: 100%;
  border: 0.5px solid var(--border-strong);
  border-radius: var(--radius);
  min-height: 44px;
  background: none;
  color: var(--ink-primary);
  font-size: 14px;
  font-weight: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-bottom: 10px;
}

.auth-secondary-btn:disabled {
  opacity: 0.5;
}

.auth-footer {
  padding: 16px 24px 20px;
  text-align: center;
}

.auth-footer p {
  margin: 0;
  font-size: 11px;
  color: var(--text-muted);
}

.auth-error {
  margin: 0 0 16px;
  font-size: 13px;
  padding: 10px 12px;
  border-radius: var(--radius);
  background: var(--bg-danger);
  color: var(--text-danger);
}
/*
  Shared structural classes for "detail sheet" screens — ported from
  "Remy — Home Screen Spec v2" Part H2 (2026-08-18), reused as-is for the
  escalation sheet here and likely again for Inbox's own result-detail
  screen later (same visual language, same spec family). Not a generic
  utility grab-bag — every class here exists because at least two of
  these mockup screens use it identically.
*/
.detail-sheet-header {
  padding: 12px 16px;
  border-bottom: 0.5px solid var(--border);
  display: flex;
  align-items: center;
  gap: 10px;
}

.detail-sheet-back {
  color: var(--text-secondary);
  background: none;
  border: none;
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.detail-sheet-header-text {
  flex: 1;
  min-width: 0;
}

.detail-sheet-title {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
}

.detail-sheet-subtitle {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}

.detail-sheet-badge {
  font-size: 11px;
  padding: 3px 8px;
  border-radius: 10px;
  background: var(--bg-warning);
  color: var(--text-warning);
  font-weight: 500;
  flex-shrink: 0;
}

.detail-sheet-body {
  padding: 14px 16px;
}

/* ── Chat bubbles (payment confirmation) ──────────────────────────────── */
.chat-bubble-in {
  max-width: 82%;
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  border-bottom-left-radius: 4px;
  padding: 9px 12px;
  margin-bottom: 8px;
}

.chat-bubble-in p {
  margin: 0;
  font-size: 13px;
}

.chat-bubble-amount {
  margin-top: 3px !important;
  font-size: 15px !important;
  font-weight: 500;
}

.chat-receipt {
  max-width: 82%;
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  border-bottom-left-radius: 4px;
  padding: 8px;
  margin-bottom: 8px;
}

.chat-receipt-placeholder {
  height: 110px;
  background: var(--surface-1);
  border-radius: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--text-muted);
}

.chat-receipt-placeholder p {
  margin: 0;
  font-size: 11px;
}

.chat-bubble-out {
  max-width: 82%;
  margin-left: auto;
  background: var(--bg-accent);
  border-radius: 12px;
  border-bottom-right-radius: 4px;
  padding: 9px 12px;
}

.chat-bubble-out p {
  margin: 0;
  font-size: 13px;
  color: var(--text-accent);
}

.chat-bubble-timestamp {
  margin-top: 2px !important;
  font-size: 10px !important;
  text-align: right;
}

.detail-sheet-footer {
  padding: 12px 16px;
  border-top: 0.5px solid var(--border);
}

.detail-sheet-total-row {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  margin-bottom: 12px;
}

.detail-sheet-total-row span:first-child {
  color: var(--text-secondary);
}

.detail-sheet-total-row span:last-child {
  font-weight: 500;
}

.detail-sheet-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.detail-sheet-btn-primary {
  background: var(--fill-primary);
  color: var(--on-primary);
  border: none;
  border-radius: var(--radius);
  min-height: 44px;
  font-weight: 600;
  font-size: 14px;
}

.detail-sheet-btn-secondary {
  background: none;
  border: 0.5px solid var(--border-strong);
  border-radius: var(--radius);
  min-height: 44px;
  font-weight: 500;
  font-size: 14px;
  color: var(--ink-primary);
}

/* ── Escalation sheet ──────────────────────────────────────────────────── */
.escalation-customer-row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}

.escalation-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--fill-control);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  font-size: 14px;
  color: var(--text-secondary);
  flex-shrink: 0;
}

.escalation-customer-text {
  flex: 1;
  min-width: 0;
}

.escalation-customer-name {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
}

.escalation-customer-phone {
  margin: 0;
  font-size: 13px;
  color: var(--text-secondary);
}

.escalation-copy-btn {
  width: 34px;
  height: 34px;
  border: 0.5px solid var(--border);
  border-radius: var(--radius);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  background: none;
  flex-shrink: 0;
}

.escalation-reason-card {
  background: var(--surface-1);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin-bottom: 12px;
}

.escalation-reason-label {
  margin: 0;
  font-size: 12px;
  color: var(--text-secondary);
}

.escalation-reason-text {
  margin: 2px 0 0;
  font-size: 13px;
}

.escalation-whatsapp-btn {
  width: 100%;
  background: var(--fill-success);
  color: var(--on-success);
  border: none;
  border-radius: var(--radius);
  min-height: 44px;
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.escalation-transcript-btn {
  width: 100%;
  background: none;
  border: 0.5px solid var(--border-strong);
  border-radius: var(--radius);
  min-height: 44px;
  font-weight: 500;
  font-size: 14px;
  color: var(--ink-primary);
}

/* ── Real customer orders (OrderDetailSheet, 2026-09-13) ──────────────── */
.detail-sheet-badge-fulfilled,
.detail-sheet-badge-confirmed {
  background: var(--bg-success);
  color: var(--text-success);
}

.detail-sheet-badge-cancelled {
  background: var(--surface-raised);
  color: var(--text-secondary);
}

.detail-sheet-error {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--text-danger);
}

.detail-sheet-btn-primary:disabled,
.detail-sheet-btn-secondary:disabled {
  opacity: 0.6;
}

.detail-sheet-btn-danger {
  border-color: var(--text-danger);
  color: var(--text-danger);
}

.order-lines {
  margin-bottom: 12px;
}

.order-line {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 0.5px solid var(--border);
}

.order-line:last-child {
  border-bottom: none;
}

.order-line-qty {
  font-size: 14px;
  font-weight: 500;
  min-width: 28px;
}

.order-line-text {
  flex: 1;
  min-width: 0;
}

.order-line-name {
  margin: 0;
  font-size: 14px;
}

.order-line-unit {
  margin: 1px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}

.order-line-total {
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}

.order-meta {
  background: var(--surface-1);
  border-radius: var(--radius);
  padding: 4px 12px;
  margin-bottom: 14px;
}

.order-meta-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 8px 0;
  color: var(--text-secondary);
  border-bottom: 0.5px solid var(--border);
}

.order-meta-row:last-child {
  border-bottom: none;
}

.order-meta-contact {
  justify-content: space-between;
  align-items: center;
}

.order-meta-title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-primary);
}

.order-meta-sub {
  margin: 1px 0 0;
  font-size: 12px;
  color: var(--text-secondary);
  overflow-wrap: anywhere;
}

.order-meta-chat {
  font-size: 13px;
  font-weight: 500;
  padding: 5px 12px;
  border-radius: 14px;
  background: var(--fill-success);
  color: var(--on-success);
  text-decoration: none;
}

.escalation-slots {
  background: var(--surface-1);
  border-radius: var(--radius);
  padding: 10px 12px;
  margin-bottom: 12px;
}

.escalation-slot {
  margin: 2px 0 0;
  font-size: 13px;
  overflow-wrap: anywhere;
}

.escalation-resolved-note {
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--text-success);
  text-align: center;
}

.transcript-label {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
}

.transcript {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.transcript .chat-bubble-in,
.transcript .chat-bubble-out {
  margin-bottom: 0;
}

.transcript-text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.transcript .chat-bubble-in .chat-bubble-timestamp {
  text-align: left;
  color: var(--text-muted);
}

.transcript-empty {
  margin: 0;
  font-size: 13px;
  color: var(--text-muted);
}

/* ── Cancelling with a reason, and whether the customer was told (2026-09-13) ── */
.cancel-panel-title {
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--text-secondary);
}

.cancel-reasons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.cancel-reason {
  font-size: 13px;
  padding: 7px 12px;
  border-radius: 16px;
  border: 0.5px solid var(--border-strong);
  background: none;
  color: var(--ink-primary);
}

.cancel-reason.cancel-reason-on {
  background: var(--fill-primary);
  color: var(--on-primary);
  border-color: transparent;
}

.detail-sheet-btn-danger:disabled {
  opacity: 0.5;
}

.notice-result {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
}

.notice-result-ok {
  color: var(--text-success);
}

.notice-result-warn p {
  margin: 0 0 10px;
  color: var(--text-warning);
}

.notice-call {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-decoration: none;
}
/*
  Home screen — ported 1:1 from "Remy — Home Screen Spec v2" Part H1
  (2026-08-18). Same adaptation as Login.css: the mockup's outer device-
  preview frame is dropped (this app already renders full-bleed on the
  real viewport everywhere), everything inside it is kept exactly —
  spacing, copy, order, colors, via the mockup-alias tokens in index.css.
*/
.home-root {
  position: relative;
  display: flex;
  flex-direction: column;
  padding-top: env(safe-area-inset-top);
  /* Extra clearance so the last section can scroll fully past the fixed
     glass pill (Part B1) rather than only ever sitting blurred behind
     it — the blur-through is intended while scrolling past, not as the
     permanent resting state for the bottom of the page. */
  padding-bottom: calc(148px + env(safe-area-inset-bottom));
}

/* Pull-to-refresh indicator (2026-08-21, src/hooks/usePullToRefresh.ts)
   — sits just above the content, revealed as the page is dragged down
   via the inline transform on .home-root itself; spins continuously
   once a refresh actually triggers, otherwise its rotation tracks pull
   progress directly (set inline, proportional to drag distance). */
.pull-refresh-indicator {
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: -18px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  color: var(--text-accent);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.14);
  /* .tab-content-enter > * (motion.css) applies the tab-switch fallIn
     entrance animation to every direct child of .home-root, this
     included — and a CSS animation overrides an inline style regardless
     of specificity, so without this override the indicator's own
     opacity/transform (set inline, driven by pull progress) would get
     clobbered the instant fallIn finishes, leaving it permanently
     visible at rest. Found 2026-08-21 exactly that way. */
  animation: none;
}

.pull-refresh-indicator.spinning {
  animation: pullRefreshSpin 0.7s linear infinite;
}

@keyframes pullRefreshSpin {
  to {
    transform: translateY(-100%) rotate(360deg);
  }
}

.home-header {
  padding: 14px 16px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.home-greeting {
  margin: 0;
  font-size: 13px;
  color: var(--text-secondary);
}

.home-venue-row {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 2px;
}

.home-liveness-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--fill-success);
  flex-shrink: 0;
}

.home-venue-name {
  font-size: 16px;
  font-weight: 500;
}

.home-header-right {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

.home-icon-circle {
  position: relative;
  width: 34px;
  height: 34px;
  border: 0.5px solid var(--border);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  background: none;
}

.home-bell-badge {
  position: absolute;
  top: 6px;
  right: 7px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--fill-danger);
}

.home-money-card {
  margin: 0 16px 12px;
  background: var(--bg-accent);
  border-radius: 12px;
  padding: 18px;
}

.home-money-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.home-money-label {
  margin: 0;
  font-size: 15px;
  color: var(--text-accent);
  font-weight: 500;
}

.home-money-value {
  margin: 4px 0 0;
  font-size: 34px;
  font-weight: 500;
  color: var(--text-accent);
  font-variant-numeric: tabular-nums;
}

.home-money-breakdown {
  margin: 5px 0 0;
  font-size: 15px;
  color: var(--text-accent);
}

.home-section {
  padding: 0 16px 12px;
}

.home-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}

.home-section-title {
  font-size: 16px;
  font-weight: 500;
  color: var(--text-secondary);
}

.home-section-badge {
  font-size: 13px;
  padding: 2px 8px;
  border-radius: 10px;
  background: var(--bg-warning);
  color: var(--text-warning);
  font-weight: 500;
}

.home-section-action {
  font-size: 14px;
  color: var(--text-accent);
  background: none;
  border: none;
  padding: 0;
}

.home-queue-list {
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.home-queue-item {
  width: 100%;
  padding: 10px 12px;
  display: flex;
  gap: 10px;
  align-items: center;
  border-bottom: 0.5px solid var(--border);
  background: none;
  text-align: left;
  color: inherit;
}

.home-queue-item:last-child {
  border-bottom: none;
}

.home-queue-item-icon {
  color: var(--text-secondary);
  flex-shrink: 0;
}

.home-queue-item-text {
  flex: 1;
  min-width: 0;
}

.home-queue-item-title {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.home-queue-item-sub {
  margin: 0;
  font-size: 15px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.home-queue-item-chevron {
  color: var(--text-muted);
  flex-shrink: 0;
}

.home-empty-note {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}

.home-glance-card {
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  padding: 12px;
}

.home-glance-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  padding-bottom: 12px;
  margin-bottom: 10px;
  border-bottom: 0.5px solid var(--border);
}

.home-glance-stat {
  text-align: center;
}

.home-glance-stat-value {
  margin: 0;
  font-size: 22px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.home-glance-stat-label {
  margin: 2px 0 0;
  font-size: 13px;
  color: var(--text-muted);
}

.home-glance-row {
  display: flex;
  gap: 10px;
  align-items: center;
  padding-bottom: 10px;
  padding-top: 10px;
  border-bottom: 0.5px solid var(--border);
}

.home-glance-row:first-of-type {
  padding-top: 0;
}

.home-glance-row:last-child {
  padding-bottom: 0;
  border-bottom: none;
}

.home-glance-row-icon {
  color: var(--text-secondary);
  flex-shrink: 0;
}

.home-glance-row-icon-warning {
  color: var(--text-warning);
}

.home-glance-body {
  flex: 1;
  min-width: 0;
}

.home-glance-title {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
}

.home-glance-sub {
  margin: 0;
  font-size: 15px;
  color: var(--text-muted);
}

/* Ask Remy floating glass pill (Ask Remy Spec Part B1, 2026-08-20;
   "liquid glass" recipe replaced 2026-08-20, second pass — a tint+blur
   pill read as a flat colored box rather than real glass, so this swaps
   in a bevel ring + specular glint + inset highlight/shadow on top of
   the blur, mapped onto this app's own tokens (surface-2/on-primary/
   fill-primary/fill-accent/ink-primary/text-secondary already existed,
   so no new tokens needed). Fixed above the bottom nav, detached from
   every edge, so it hovers OVER the dashboard rather than welding to a
   strip; page content scrolls underneath and blurs through the glass —
   there being live content behind it is what makes the blur read at
   all, so this must stay an overlay, never placed on a solid backing.
   Replaces the mockup's manual "Edit prices"/"Availability" shortcuts
   ("we want people to interact with the talk to remy / ask remy now
   instead of manual entry"). z-index sits above scrolling content, below
   the bottom nav (AppShell's nav is a later sibling in the DOM with no
   z-index set, i.e. z-index:auto stacks after this on its own layer —
   verified visually, see the verification screenshots). */
.ask-remy-pill {
  position: fixed;
  left: 14px;
  right: 14px;
  bottom: calc(70px + env(safe-area-inset-bottom));
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: 30px;
  padding: 12px 13px;
  isolation: isolate;
  max-width: 480px;
  margin: 0 auto;
  text-align: left;
  color: inherit;

  /* translucent tint, kept light so the blur reads through */
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--surface-2) 52%, transparent),
    color-mix(in srgb, var(--surface-2) 70%, transparent)
  );

  /* the frost + color richness underneath */
  backdrop-filter: blur(24px) saturate(150%) contrast(1.03);
  -webkit-backdrop-filter: blur(24px) saturate(150%) contrast(1.03);

  /* thickness — bright top inner edge, faint dark bottom edge, float shadow */
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.5),
    inset 0 -1px 1px rgba(0, 0, 0, 0.06),
    0 10px 30px rgba(0, 0, 0, 0.2),
    0 2px 6px rgba(0, 0, 0, 0.12);

  animation: askRemyPillIn var(--dur-slow) var(--ease-spring) both;
  animation-delay: 80ms;
}

/* Lit bevel edge — a masked gradient ring, bright top-left fading to a
   dark bottom-right, standing in for a literal border. */
.ask-remy-pill::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(145deg, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.05) 40%, rgba(0, 0, 0, 0.12) 100%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
  z-index: 3;
}

/* Specular glint — a top sheen plus a narrow diagonal streak. */
.ask-remy-pill::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 1;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0) 42%),
    linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.22) 45%, transparent 52%);
}

.ask-remy-pill > * {
  position: relative;
  z-index: 2;
}

.ask-remy-pill:active {
  transform: scale(0.985);
}

/* Dark mode — soften the white sheen so it reads as smoked glass rather
   than a light-mode pill with the wrong tint. */
:root[data-theme="dark"] .ask-remy-pill {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--surface-2) 46%, transparent),
    color-mix(in srgb, var(--surface-2) 66%, transparent)
  );
  box-shadow:
    inset 0 1px 1px rgba(255, 255, 255, 0.16),
    inset 0 -1px 1px rgba(0, 0, 0, 0.3),
    0 12px 36px rgba(0, 0, 0, 0.55),
    0 2px 8px rgba(0, 0, 0, 0.4);
}
:root[data-theme="dark"] .ask-remy-pill::after {
  background: linear-gradient(145deg, rgba(255, 255, 255, 0.32), rgba(255, 255, 255, 0.03) 42%, rgba(0, 0, 0, 0.4) 100%);
}
:root[data-theme="dark"] .ask-remy-pill::before {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0) 42%),
    linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.08) 45%, transparent 52%);
}

/* Required fallback — never render an unreadable transparent smudge on
   engines without backdrop-filter, or when the OS prefers reduced
   transparency; var(--surface-2) already resolves per-theme, so one
   rule covers both. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ask-remy-pill {
    background: var(--surface-2);
  }
}
@media (prefers-reduced-transparency: reduce) {
  .ask-remy-pill {
    background: var(--surface-2);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

@keyframes askRemyPillIn {
  from {
    opacity: 0;
    transform: scale(0.92) translateY(6px);
  }
}

.ask-remy-pill-icon {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--fill-primary);
  color: var(--on-primary);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
}

.ask-remy-pill-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.ask-remy-pill-title {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.1px;
  color: var(--ink-primary);
}

.ask-remy-pill-hint {
  display: block;
  font-size: 11px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  animation: fallIn var(--dur-base) var(--ease-out) both;
}

.ask-remy-pill-mic {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--fill-accent) 20%, transparent);
  border: 0.5px solid color-mix(in srgb, white 28%, transparent);
  color: var(--fill-accent);
}

.home-stats {
  padding: 0 16px 14px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.home-stat-card {
  background: var(--surface-2);
  border-radius: var(--radius);
  padding: 12px;
}

.home-stat-label {
  margin: 0;
  font-size: 15px;
  color: var(--text-secondary);
}

.home-stat-value {
  margin: 3px 0 0;
  font-size: 28px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
/*
  Ask Remy — chat screen, per "Remy — Ask Remy (Instruction Chat) Spec"
  Part H2 (2026-08-20, pasted in full and confirmed as the source of
  truth). Reuses chat-bubble-out from DetailSheet.css for the owner's own
  bubbles; Remy's bubbles and the structured result/details cards inside
  them are new, matching the spec's exact shapes.
*/
.ask-remy-root {
  height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
}

.ask-remy-header {
  flex-shrink: 0;
  padding: calc(12px + env(safe-area-inset-top)) 16px 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  border-bottom: 0.5px solid var(--border);
  background: var(--surface-2);
}

.ask-remy-back {
  background: none;
  border: none;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  flex-shrink: 0;
  padding: 4px;
  margin-left: -4px;
}

.ask-remy-header-avatar {
  width: 32px;
  height: 32px;
  border-radius: 26%;
  background: var(--fill-primary);
  color: var(--on-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.ask-remy-header-text {
  flex: 1;
  min-width: 0;
}

.ask-remy-header-title {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
}

.ask-remy-header-sub {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ask-remy-header-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--fill-success);
  flex-shrink: 0;
}

/* History sidebar toggle (2026-08-21) — sits at the end of the header,
   after the live dot. */
.ask-remy-history-btn {
  background: none;
  border: none;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  padding: 4px;
  margin-left: 6px;
  flex-shrink: 0;
}

/* Blank-day landing (2026-08-21, "what do you want to do today?") —
   shown instead of the message list whenever the day being viewed has
   no messages yet (today, before the first send). */
.ask-remy-landing {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 24px;
  text-align: center;
}

.ask-remy-landing-avatar {
  width: 56px;
  height: 56px;
  border-radius: 28%;
  background: var(--fill-primary);
  color: var(--on-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ask-remy-landing-title {
  margin: 4px 0 0;
  font-size: 19px;
  font-weight: 600;
  color: var(--ink-primary);
}

.ask-remy-landing-hint {
  margin: 0;
  font-size: 13px;
  color: var(--text-secondary);
  animation: fallIn var(--dur-base) var(--ease-out) both;
}

/* Read-only footer shown in place of the input bar when browsing a past
   day's conversation — that day is closed history, not something new
   gets typed into. */
.ask-remy-readonly-bar {
  flex-shrink: 0;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  border-top: 0.5px solid var(--border);
  background: var(--surface-2);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
}

.ask-remy-readonly-bar p {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}

/* History sidebar (2026-08-21) — a left-edge drawer over the chat, same
   overlay+backdrop idiom as Sheet.css's bottom sheet, just anchored to
   the side instead of the bottom (a phone-width chat history list reads
   naturally as a slide-in drawer, matching the ChatGPT/Claude reference
   the request named). */
.ask-remy-sidebar-overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  animation: overlayIn var(--dur-fast) var(--ease-out) both;
}

.ask-remy-sidebar {
  width: min(84vw, 340px);
  height: 100%;
  background: var(--surface-1);
  display: flex;
  flex-direction: column;
  padding: calc(12px + env(safe-area-inset-top)) 14px 12px;
  gap: 10px;
  animation: askRemySidebarIn var(--dur-base) var(--ease-out) both;
  box-shadow: 4px 0 20px rgba(0, 0, 0, 0.2);
}

@keyframes askRemySidebarIn {
  from {
    transform: translateX(-100%);
  }
}

.ask-remy-sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.ask-remy-sidebar-title {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
}

.ask-remy-sidebar-head button {
  background: none;
  border: none;
  color: var(--text-secondary);
  display: flex;
  padding: 4px;
}

.ask-remy-sidebar-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--surface-2);
  color: var(--text-muted);
}

.ask-remy-sidebar-search input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  font-size: 13px;
  color: var(--ink-primary);
}

.ask-remy-sidebar-today {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 10px;
  border-radius: 10px;
  background: none;
  border: 0.5px solid var(--border-strong);
  color: var(--ink-primary);
  font-size: 13px;
  font-weight: 500;
}

.ask-remy-sidebar-today.active {
  background: var(--fill-primary);
  color: var(--on-primary);
  border-color: transparent;
}

.ask-remy-sidebar-list {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.ask-remy-sidebar-item {
  padding: 9px 10px;
  border-radius: 10px;
  background: none;
  border: none;
  text-align: left;
}

.ask-remy-sidebar-item.active {
  background: var(--surface-2);
}

.ask-remy-sidebar-item-date {
  margin: 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary);
}

.ask-remy-sidebar-item-preview {
  margin: 2px 0 0;
  font-size: 13px;
  color: var(--ink-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ask-remy-sidebar-empty {
  margin: 16px 0 0;
  font-size: 13px;
  color: var(--text-muted);
  text-align: center;
}

.ask-remy-body {
  flex: 1;
  overflow-y: auto;
  padding: 16px 12px;
  display: flex;
  flex-direction: column;
}

.ask-remy-day-label {
  margin: 0 auto 10px;
  font-size: 11px;
  color: var(--text-muted);
  background: var(--surface-1);
  padding: 3px 10px;
  border-radius: 10px;
}

.ask-remy-bubble {
  margin-bottom: 10px;
  animation: bubbleIn var(--dur-fast) var(--ease-out) both;
}

/* Part C2 — Remy's own bubbles: surface-1 (not surface-2/chat-bubble-in),
   left-aligned, can carry prose plus an embedded structured block. */
.ask-remy-remy-bubble {
  max-width: 90%;
  background: var(--surface-1);
  border-radius: 12px;
  border-bottom-left-radius: 4px;
  padding: 10px 12px;
}

.ask-remy-remy-bubble p {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
}

.ask-remy-remy-bubble p + p,
.ask-remy-remy-bubble p + div,
.ask-remy-remy-bubble div + p {
  margin-top: 8px;
}

.ask-remy-fine-print {
  font-size: 11px !important;
  color: var(--text-muted);
  line-height: 1.5 !important;
}

/* Part C2 — inline action chips beneath a Remy bubble. */
.ask-remy-chip-row {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  flex-wrap: wrap;
}

.ask-remy-chip {
  font-size: 12px;
  padding: 6px 12px;
  border-radius: 16px;
  font-weight: 500;
}

.ask-remy-chip-primary {
  background: var(--fill-primary);
  color: var(--on-primary);
}

.ask-remy-chip-secondary {
  border: 0.5px solid var(--border);
  color: var(--text-secondary);
  font-weight: 400;
}

/* Part C3 step 5 — the result card: an icon-row list summarizing what
   Remy actually did. */
.ask-remy-result-card {
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.ask-remy-result-row {
  padding: 9px 11px;
  display: flex;
  gap: 9px;
  align-items: center;
  border-bottom: 0.5px solid var(--border);
}

.ask-remy-result-row:last-child {
  border-bottom: none;
}

.ask-remy-result-row p {
  margin: 0;
  font-size: 12px;
  flex: 1;
}

.ask-remy-result-icon-success {
  color: var(--text-success);
}

.ask-remy-result-icon-neutral {
  color: var(--text-secondary);
}

.ask-remy-result-icon-warning {
  color: var(--text-warning);
}

/* Part C4 — the details table (e.g. refund account details Remy
   collected and is handing back, never acting on itself). */
.ask-remy-details-table {
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 10px;
  padding: 10px 11px;
}

.ask-remy-details-title {
  margin: 0 0 6px;
  font-size: 11px;
  color: var(--text-muted);
}

.ask-remy-details-row {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  padding: 2px 0;
}

.ask-remy-details-row span:first-child {
  color: var(--text-secondary);
}

.ask-remy-details-value {
  font-weight: 500;
}

.ask-remy-system-note {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--text-muted);
  text-align: center;
  font-style: italic;
  animation: fallIn var(--dur-base) var(--ease-out) both;
}

.ask-remy-input-bar {
  position: relative;
  flex-shrink: 0;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 0.5px solid var(--border);
  background: var(--surface-2);
  display: flex;
  align-items: flex-end;
  gap: 6px;
}

.ask-remy-attachment-chip {
  position: absolute;
  bottom: 100%;
  left: 12px;
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  padding: 5px 10px;
  border-radius: var(--radius-full);
  background: var(--bg-accent);
  color: var(--text-accent);
}

.ask-remy-attachment-chip button {
  background: none;
  border: none;
  color: inherit;
  display: flex;
  align-items: center;
  opacity: 0.75;
}

.ask-remy-attach-row {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

.ask-remy-attach-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  background: none;
  border: none;
}

/* Part H2's input bar: one rounded pill holding the text field, the mic
   circle, and the send circle. */
.ask-remy-input-pill {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  border: 0.5px solid var(--border-strong);
  border-radius: 20px;
  padding: 6px 6px 6px 14px;
}

.ask-remy-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  font-size: 15px;
  color: var(--ink-primary);
  padding: 6px 0;
}

.ask-remy-input::placeholder {
  color: var(--text-muted);
}

.ask-remy-mic-btn {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  background: var(--surface-1);
  border: none;
}

.ask-remy-send-btn {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--fill-primary);
  color: var(--on-primary);
  border: none;
}

.ask-remy-send-btn:disabled {
  opacity: 0.4;
}
/*
  Business tab landing — ported 1:1 from "Remy — Business Tab Spec v2"
  Part H1 (2026-08-18). Same adaptation pattern as every other ported
  screen: mockup's outer device-frame dropped, everything inside kept
  exactly via the mockup-alias tokens in index.css.
*/
.biz-root {
  padding-top: env(safe-area-inset-top);
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
}

.biz-header {
  padding: 14px 16px 10px;
}

.biz-title {
  margin: 0;
  font-size: 18px;
  font-weight: 500;
}

.biz-subtitle {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}

.biz-modules {
  padding: 0 16px 12px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.biz-module-card {
  border: 0.5px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  background: var(--surface-2);
  text-align: left;
  color: inherit;
}

.biz-module-icon {
  color: var(--text-secondary);
}

.biz-module-name {
  margin: 6px 0 0;
  font-size: 14px;
  font-weight: 500;
}

.biz-module-summary {
  margin: 1px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}

/* The shared sections list itself uses .list-card/.list-row/etc from
   index.css (2026-08-18) — Business was the first of two screens with
   this exact pattern, now extracted there rather than duplicated. */
.biz-sections {
  margin: 0 16px 12px;
}

.biz-info-card {
  margin: 0 16px 12px;
  background: var(--surface-2);
  border-radius: 12px;
  padding: 12px;
}

.biz-info-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
}

.biz-info-icon {
  color: var(--text-secondary);
  margin-top: 1px;
  flex-shrink: 0;
}

.biz-info-title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

.biz-info-desc {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.5;
}

.biz-info-link {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--text-accent);
  font-weight: 500;
  background: none;
  border: none;
  padding: 0;
}

.biz-add-row {
  width: calc(100% - 32px);
  margin: 0 16px 14px;
  border: 0.5px dashed var(--border-strong);
  border-radius: 12px;
  padding: 11px 12px;
  display: flex;
  gap: 10px;
  align-items: center;
  background: none;
  text-align: left;
}

.biz-add-icon {
  color: var(--text-accent);
  flex-shrink: 0;
}

.biz-add-title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-accent);
}

.biz-add-desc {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}
/*
  Inbox tab — ported 1:1 from "Remy — Inbox Tab Spec" Part G1 (2026-08-18).
  Same outer-frame adaptation as every other ported screen.
*/
.inbox-root {
  padding-top: env(safe-area-inset-top);
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
}

.inbox-header {
  padding: 14px 16px 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.inbox-title {
  margin: 0;
  font-size: 18px;
  font-weight: 500;
}

.inbox-search-btn {
  width: 34px;
  height: 34px;
  border: 0.5px solid var(--border);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  background: none;
}

.inbox-chips {
  padding: 0 16px 12px;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.inbox-chip {
  font-size: 12px;
  padding: 6px 12px;
  border-radius: 16px;
  border: 0.5px solid var(--border);
  color: var(--text-secondary);
  background: none;
}

.inbox-chip.inbox-chip-active {
  background: var(--fill-primary);
  color: var(--on-primary);
  font-weight: 500;
  border: none;
}

.inbox-day-label {
  padding: 0 16px 8px;
  margin: 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
}

.inbox-card-group {
  margin: 0 16px 12px;
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.inbox-card {
  width: 100%;
  padding: 12px;
  display: flex;
  gap: 10px;
  border-bottom: 0.5px solid var(--border);
  background: none;
  text-align: left;
  color: inherit;
}

.inbox-card:last-child {
  border-bottom: none;
}

.inbox-card-icon {
  color: var(--text-secondary);
  margin-top: 1px;
  flex-shrink: 0;
}

.inbox-card-body {
  flex: 1;
  min-width: 0;
}

.inbox-card-top-row {
  display: flex;
  justify-content: space-between;
  gap: 8px;
}

.inbox-card-title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

.inbox-card-amount {
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
}

.inbox-card-context {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--text-muted);
}

.inbox-status-pill {
  display: inline-block;
  margin-top: 6px;
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 10px;
  font-weight: 500;
}

.inbox-status-warning {
  background: var(--bg-warning);
  color: var(--text-warning);
}

.inbox-status-success {
  background: var(--positive-bg);
  color: var(--positive);
}

.inbox-status-neutral {
  background: var(--surface-raised);
  color: var(--text-secondary);
}

.inbox-empty-priority {
  margin: 0 16px 14px;
  background: var(--surface-2);
  border-radius: 12px;
  padding: 14px;
  text-align: center;
}

.inbox-empty-icon {
  color: var(--text-muted);
}

.inbox-empty-text {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--text-secondary);
}

.inbox-nothing-here {
  padding: 40px 16px;
  text-align: center;
  color: var(--text-muted);
  font-size: 13px;
}
/*
  Insights tab — ported 1:1 from "Remy — Insights Tab Spec" Part G
  (2026-08-18). Same outer-frame adaptation as every other ported screen.
*/
.insights-root {
  padding-top: env(safe-area-inset-top);
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
}

.insights-header {
  padding: 14px 16px 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.insights-title {
  margin: 0;
  font-size: 18px;
  font-weight: 500;
}

.insights-period-chips {
  display: flex;
  gap: 6px;
}

.insights-period-chip {
  font-size: 12px;
  padding: 5px 10px;
  border-radius: 14px;
  border: 0.5px solid var(--border);
  color: var(--text-secondary);
  background: none;
}

.insights-period-chip.insights-period-chip-active {
  background: var(--fill-primary);
  color: var(--on-primary);
  font-weight: 500;
  border: none;
}

.insights-money-wrap {
  position: relative;
  margin: 0 16px 12px;
}

.insights-money-card {
  background: var(--bg-accent);
  border-radius: 12px;
  padding: 18px;
}

.insights-money-eye {
  position: absolute;
  top: 14px;
  right: 14px;
}

.insights-money-label {
  margin: 0;
  font-size: 15px;
  color: var(--text-accent);
  font-weight: 500;
}

.insights-money-value {
  margin: 4px 0 0;
  font-size: 34px;
  font-weight: 500;
  color: var(--text-accent);
  font-variant-numeric: tabular-nums;
}

.insights-money-count {
  margin: 3px 0 12px;
  font-size: 15px;
  color: var(--text-accent);
}

.insights-bars-row {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 56px;
}

.insights-bar-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
}

.insights-bar {
  width: 100%;
  background: var(--fill-accent);
  opacity: 0.45;
  border-radius: 3px;
}

.insights-bar.insights-bar-peak {
  opacity: 1;
}

.insights-bar-label {
  font-size: 10px;
  color: var(--text-accent);
}

.insights-bar-label.insights-bar-label-peak {
  font-weight: 500;
}

.insights-stats {
  padding: 0 16px 12px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.insights-stat-card {
  background: var(--surface-2);
  border-radius: var(--radius);
  padding: 14px;
}

.insights-stat-label {
  margin: 0;
  font-size: 15px;
  color: var(--text-secondary);
}

.insights-stat-value {
  margin: 3px 0 0;
  font-size: 28px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.insights-stat-sub {
  font-size: 16px;
  color: var(--text-secondary);
  font-weight: 400;
}

.insights-section {
  padding: 0 16px 12px;
}

.insights-section-title {
  margin: 0 0 8px;
  font-size: 16px;
  font-weight: 500;
  color: var(--text-secondary);
}

.insights-hour-card {
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  padding: 12px;
}

.insights-hour-bars {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 44px;
  margin-bottom: 4px;
}

.insights-hour-bar {
  flex: 1;
  background: var(--fill-control);
  border-radius: 2px;
}

.insights-hour-bar.insights-hour-bar-peak {
  background: var(--fill-primary);
}

.insights-hour-axis {
  display: flex;
  justify-content: space-between;
}

.insights-hour-axis span {
  font-size: 10px;
  color: var(--text-muted);
}

.insights-takeaway {
  margin: 8px 0 0;
  font-size: 15px;
  color: var(--text-secondary);
}

.insights-list-card {
  background: var(--surface-2);
  border: 0.5px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.insights-list-row {
  padding: 10px 12px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 0.5px solid var(--border);
}

.insights-list-row:last-child {
  border-bottom: none;
}

.insights-list-name {
  font-size: 16px;
}

.insights-list-count {
  font-size: 16px;
  font-weight: 500;
}

.insights-list-revenue {
  color: var(--text-muted);
  font-weight: 400;
}

.insights-worth-card {
  background: var(--surface-2);
  border: 0.5px solid var(--attention);
  border-radius: 12px;
  overflow: hidden;
}

.insights-worth-row {
  padding: 11px 12px;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  border-bottom: 0.5px solid var(--border);
}

.insights-worth-row:last-child {
  border-bottom: none;
}

.insights-worth-icon {
  color: var(--text-warning);
  margin-top: 1px;
  flex-shrink: 0;
}

.insights-worth-text {
  margin: 0;
  font-size: 16px;
}

.insights-worth-text strong {
  font-weight: 500;
}

.insights-worth-action {
  margin: 4px 0 0;
  font-size: 15px;
  color: var(--text-accent);
  font-weight: 500;
  background: none;
  border: none;
  padding: 0;
}

.insights-worth-advisory {
  margin: 4px 0 0;
  font-size: 15px;
  color: var(--text-muted);
}
/*
  Appearance sub-page — ported from "Remy — Appearance & Theme Spec"
  Parts C1-C3 (2026-08-19), values translated onto this app's own real
  tokens (see Appearance.tsx's header comment for why).
*/
.appearance-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* Part C2 — the quick-knob: 56×30 pill, 24px thumb, springs across on
   toggle (Motion Spec G5's toggle-spring pattern). */
.appearance-knob {
  width: 56px;
  height: 30px;
  border-radius: 16px;
  background: var(--surface-1);
  border: 0.5px solid var(--border-strong);
  position: relative;
  flex-shrink: 0;
}

.appearance-knob-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-secondary);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  transition: transform var(--dur-fast) var(--ease-spring);
}

.appearance-knob[data-dark="true"] .appearance-knob-thumb {
  transform: translateX(26px);
}

.appearance-label {
  margin: 14px 0 8px;
  font-size: 12px;
  color: var(--text-secondary);
}

/* Part C1 — segmented control, same "active fills with the accent"
   language as the app's existing .pill-active. */
.appearance-seg {
  display: flex;
  gap: 0;
  border: 0.5px solid var(--border-strong);
  border-radius: 12px;
  overflow: hidden;
}

.appearance-seg-option {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px 0;
  font-size: 13px;
  color: var(--text-secondary);
  background: none;
}

.appearance-seg-option.on {
  background: var(--fill-primary);
  color: var(--on-primary);
  font-weight: 500;
}

.appearance-hint {
  margin: 10px 0 0;
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.5;
}

/* Part C3 — the live preview, real tokens/components so it doubles as a
   both-modes smoke test the same way the spec intends. */
.appearance-preview {
  overflow: hidden;
  padding: 0;
}

.appearance-preview-money {
  padding: 12px;
  background: var(--bg-accent);
}

.appearance-preview-money-label {
  margin: 0;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-accent);
}

.appearance-preview-money-value {
  margin: 2px 0 0;
  font-size: 22px;
  font-weight: 500;
  color: var(--text-accent);
}

.appearance-preview-row {
  padding: 11px 12px;
  display: flex;
  gap: 10px;
  align-items: center;
  border-top: 0.5px solid var(--border);
}

.appearance-preview-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--fill-success);
  flex-shrink: 0;
}

.appearance-preview-row-text {
  flex: 1;
  min-width: 0;
}

.appearance-preview-row-title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

.appearance-preview-row-sub {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}

.appearance-preview-price {
  font-size: 14px;
  font-weight: 500;
}
/*
  Settings tab landing — ported 1:1 from "Remy — Settings Tab Spec" Part
  H1 (2026-08-18). Section lists reuse the shared .list-card/.list-row
  classes in index.css (same pattern as Business's landing); this file
  holds only what's genuinely specific to Settings — the profile card's
  avatar row and section spacing.
*/
.settings-root {
  padding-top: env(safe-area-inset-top);
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
}

.settings-header {
  padding: 14px 16px 10px;
}

.settings-title {
  margin: 0;
  font-size: 18px;
  font-weight: 500;
}

.settings-card {
  margin: 0 16px 12px;
}

.settings-profile-row {
  width: 100%;
  padding: 12px;
  display: flex;
  gap: 12px;
  align-items: center;
  border-bottom: 0.5px solid var(--border);
  background: none;
  text-align: left;
  color: inherit;
}

.settings-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--bg-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  font-size: 14px;
  color: var(--text-accent);
  flex-shrink: 0;
}

.settings-profile-text {
  flex: 1;
  min-width: 0;
}

.settings-profile-name {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
}

.settings-profile-sub {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}
/*
  Catalogue's own layout — 2026-08-18. Originally a self-contained parallel
  light theme (its own header, bottom nav, and duplicated color tokens),
  folded back into the shared app-wide theme the same day once the user
  asked for the light theme everywhere, not just here — `index.css` now
  carries the palette, `AppShell` now carries the business header and
  bottom nav on every top-level route, and `.pill`/`.pill-group` in
  index.css now carries the segmented-filter pattern. What's left here is
  genuinely Catalogue-specific: the product card layout, the search/
  filter/sort row, and the create/edit form fields — nothing that
  duplicates what every other screen already gets for free.
*/

.cl-root {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-bottom: 5rem; /* clears the floating action button */
}

.cl-title {
  font-size: 2rem;
  font-weight: 800;
  margin: 0;
  letter-spacing: -0.02em;
}

.cl-subtitle {
  margin: 0.3rem 0 0;
  color: var(--ink-secondary);
  font-size: 0.95rem;
}

/* ── Search + filter + sort row ───────────────────────────────────────── */
.cl-search-row {
  display: flex;
  gap: 0.5rem;
}

.cl-search {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--surface);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  padding: 0.7rem 0.9rem;
  color: var(--ink-tertiary);
}

.cl-search input {
  flex: 1;
  border: none;
  background: transparent;
  color: var(--ink-primary);
  font-size: 0.92rem;
}

.cl-search input::placeholder {
  color: var(--ink-tertiary);
}

.cl-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-primary);
  position: relative;
}

.cl-icon-btn.cl-icon-btn-active {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}

.cl-sort-btn {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink-primary);
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0 0.85rem;
  flex-shrink: 0;
}

/* ── Popover menus (filter / sort) ────────────────────────────────────── */
.cl-popover-wrap {
  position: relative;
}

.cl-popover {
  position: absolute;
  top: calc(100% + 0.4rem);
  right: 0;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card);
  min-width: 180px;
  padding: 0.4rem;
  display: flex;
  flex-direction: column;
}

.cl-popover-item {
  border: none;
  background: transparent;
  text-align: left;
  padding: 0.6rem 0.7rem;
  border-radius: calc(var(--radius) - 4px);
  font-size: 0.88rem;
  color: var(--ink-primary);
}

.cl-popover-item.cl-popover-item-active {
  background: var(--surface-raised);
  font-weight: 700;
}

/* ── Stats + Add Product row ──────────────────────────────────────────── */
.cl-stats-row {
  background: var(--surface-raised);
  border-radius: var(--radius-lg);
  padding: 0.9rem 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.cl-stats {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.cl-stat-label {
  margin: 0;
  font-size: 0.75rem;
  color: var(--ink-secondary);
}

.cl-stat-value {
  margin: 0.1rem 0 0;
  font-size: 1.1rem;
  font-weight: 800;
}

.cl-stat-divider {
  width: 1px;
  align-self: stretch;
  background: var(--border-hairline);
}

.cl-add-btn {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--accent);
  color: var(--accent-ink);
  border: none;
  border-radius: var(--radius-full);
  padding: 0.7rem 1.1rem;
  font-size: 0.88rem;
  font-weight: 700;
  white-space: nowrap;
}

/* ── Product cards ─────────────────────────────────────────────────────── */
.cl-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.cl-empty {
  color: var(--ink-secondary);
  text-align: center;
  padding: 2rem 0;
}

.cl-card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

/* Out-of-stock rows grey out automatically — there's no real "enabled"
   flag anywhere in this schema, so this is the one, honest, data-derived
   signal (quantity_on_hand === 0) rather than a fake toggle control. */
.cl-card.cl-card-out {
  opacity: 0.6;
}

.cl-card-main {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 1rem;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
}

.cl-thumb {
  width: 72px;
  height: 72px;
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: var(--ink-tertiary);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.cl-card.cl-card-out .cl-thumb {
  filter: grayscale(1);
}

.cl-card-body {
  flex: 1;
  min-width: 0;
}

.cl-card-name {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cl-card-desc {
  margin: 0.1rem 0 0;
  font-size: 0.83rem;
  color: var(--ink-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cl-card-price {
  margin: 0.4rem 0 0;
  font-size: 1.05rem;
  font-weight: 800;
}

.cl-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.45rem;
  padding: 0.2rem 0.6rem;
  border-radius: var(--radius-full);
  font-size: 0.75rem;
  font-weight: 700;
}

.cl-badge-in {
  background: var(--positive-bg);
  color: var(--positive);
}

.cl-badge-out {
  background: var(--surface-raised);
  color: var(--ink-secondary);
}

.cl-badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: currentColor;
}

.cl-chevron {
  color: var(--ink-tertiary);
  flex-shrink: 0;
}

.cl-card-actions {
  display: flex;
  align-items: center;
  border-top: 1px solid var(--border-hairline);
  padding: 0.2rem 0.4rem;
}

.cl-card-action {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  border: none;
  background: none;
  color: var(--ink-primary);
  font-size: 0.8rem;
  font-weight: 600;
  padding: 0.75rem 0.4rem;
}

/* Honest stub — no image storage and no reachable price-edit flow exist
   anywhere in this schema/API (see Catalogue.tsx's own comment). Present
   in the row for visual fidelity to the reference, but visibly inert
   rather than pretending to do something real. */
.cl-card-action.cl-card-action-stub {
  color: var(--ink-tertiary);
}

.cl-card-action-more {
  flex: 0 0 auto;
  width: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  color: var(--ink-tertiary);
}

/* ── Floating action button ───────────────────────────────────────────── */
.cl-fab {
  position: fixed;
  right: 1.25rem;
  bottom: calc(84px + env(safe-area-inset-bottom));
  width: 56px;
  height: 56px;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--accent-ink);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-fab);
  z-index: 15;
}

/* ── Modal (Add/Edit) form fields ─────────────────────────────────────── */
.cl-field {
  padding: 0.75rem 0.9rem;
  border-radius: var(--radius);
  border: 1px solid var(--border-hairline);
  background: var(--bg-base);
  color: var(--ink-primary);
  font-size: 0.92rem;
}

.cl-field::placeholder {
  color: var(--ink-tertiary);
}

.cl-toggle-row {
  display: flex;
  gap: 0.5rem;
}

.cl-toggle-btn {
  flex: 1;
  min-height: 44px;
  border-radius: var(--radius);
  border: 1px solid var(--border-hairline);
  background: var(--bg-base);
  color: var(--ink-primary);
  font-size: 0.88rem;
  font-weight: 600;
}

.cl-toggle-btn.cl-toggle-btn-active {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}

.cl-hint {
  color: var(--ink-tertiary);
  font-size: 0.8rem;
  margin: 0;
}

.cl-modal-actions {
  display: flex;
  gap: 0.5rem;
}

.cl-btn-secondary {
  border: 1px solid var(--border-hairline);
  background: var(--surface);
  color: var(--ink-primary);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  font-weight: 600;
  font-size: 0.9rem;
}

.cl-btn-primary {
  flex: 1;
  border: none;
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  font-weight: 700;
  font-size: 0.9rem;
}

.cl-btn-primary:disabled {
  opacity: 0.5;
}
/* Grouped icon-tile grid, matching the reference design: a small gray
   section label above each group, rounded-square tiles with a centered
   icon over a short label. 3 columns (2026-08-14, direct user correction
   — 4 columns "looked weird," 3 gives each tile more breathing room). */
.tile-section-label {
  color: var(--ink-tertiary);
  font-size: 0.8rem;
  margin: 0 0 0.6rem 0.25rem;
}

.tile-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.6rem;
}

.tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.85rem 0.5rem;
  text-decoration: none;
  text-align: center;
  min-height: 80px;
}

.tile-icon {
  width: 36px;
  height: 36px;
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.tile-label {
  color: var(--ink-primary);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.2;
}
/* The list-row pattern from the reference design: an icon in a rounded
   square, title (+ optional description), then either a chevron (drills
   into an action) or a toggle (a boolean setting) on the right. */
.settings-section-label {
  color: var(--ink-tertiary);
  font-size: 0.8rem;
  margin: 0 0 0.5rem 0.25rem;
}

.settings-row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  width: 100%;
  padding: 0.75rem 1rem;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border-hairline);
  min-height: 44px;
}

.settings-row:last-child {
  border-bottom: none;
}

.settings-row:disabled {
  opacity: 0.5;
  cursor: default;
}

.settings-row-icon {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: var(--radius);
  background: var(--surface-raised);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.settings-row-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.settings-row-desc {
  color: var(--ink-tertiary);
  font-size: 0.8rem;
}

.settings-row-chevron {
  flex-shrink: 0;
  color: var(--ink-tertiary);
}

/* A minimal pill toggle — no existing switch component anywhere in this
   app to reuse (checkboxes only, e.g. Order.tsx's comp checkbox), built
   small and self-contained rather than pulling in a whole component. */
.toggle {
  flex-shrink: 0;
  width: 44px;
  height: 26px;
  border-radius: 999px;
  background: var(--surface-raised);
  border: 1px solid var(--border-hairline);
  position: relative;
  cursor: pointer;
}

.toggle[data-checked="true"] {
  background: var(--accent);
  border-color: var(--accent);
}

.toggle-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--ink-primary);
  transition: transform 0.15s ease;
}

.toggle[data-checked="true"] .toggle-thumb {
  transform: translateX(18px);
  background: var(--accent-ink);
}
/*
  Responsive by CSS, one build (UX Group 1 §1.4 / rule 7): "the same
  components widen and reveal more inline detail at desktop width; they
  do not become a different app." Side panel on desktop/web, bottom tab
  bar on mobile — Design Standards §10: "Not a widened phone."
*/
.shell {
  display: flex;
  flex-direction: column;
  /* 100vh alone is the layout viewport, which on installed Android/PWA
     Chrome (2026-08-19, reported on a Galaxy S22 Ultra) can render TALLER
     than what's actually visible, pushing the bottom nav below the fold
     and forcing the whole page to scroll to reach it. 100dvh tracks the
     real visible viewport; same vh-then-dvh fallback pattern as
     Login.css's .auth-page. */
  min-height: 100vh;
  min-height: 100dvh;
}

.shell-body {
  display: flex;
  flex: 1;
  min-height: 0;
}

.shell-content {
  flex: 1;
  overflow-y: auto;
  padding: 1.5rem;
}

/* Top-level screens draw their own full-bleed layout (see AppShell.tsx). */
.shell-content-flush {
  padding: 0;
}

.shell-nav {
  display: none;
}

/* Always visible now (2026-08-14, direct correction) — a centered page
   title needs somewhere to live even on a top-level screen with no back
   arrow, so the topbar itself is no longer conditional on `!isTopLevel`.
   Three-part flex (side / title / side, both sides the same width) is the
   standard way to center a title while a left-side element (the back
   arrow) can appear or disappear without the title visibly shifting. */
.shell-topbar {
  display: flex;
  align-items: center;
  padding: 0.85rem 1.25rem;
  border-bottom: 1px solid var(--border-hairline);
  /* Real-device testing (2026-08-14) — a notched/dynamic-island phone
     draws its status bar over this otherwise, `viewport-fit=cover` in
     index.html is what makes env() resolve to something non-zero here. */
  padding-top: max(0.85rem, env(safe-area-inset-top));
}

.shell-topbar-side {
  flex: 1;
  display: flex;
}

.shell-topbar-title {
  flex: 2;
  text-align: center;
  font-size: 1rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Bare icon, no button-box background (2026-08-14, direct correction —
   "the back arrow in a box looks old, lets have just the back arrow"). */
.shell-back {
  background: none;
  border: none;
  color: var(--ink-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-left: -0.5rem;
}

.shell-bottom-nav {
  display: flex;
  border-top: 1px solid var(--border-hairline);
  background: var(--surface);
  /* Keeps tap targets clear of the home-indicator gesture bar on iOS/
     gesture-nav Android, same env() dependency as the topbar above. */
  padding-bottom: env(safe-area-inset-bottom);
}

.shell-bottom-nav a,
.shell-nav a {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--ink-secondary);
  text-decoration: none;
  font-size: 0.85rem;
  /* A real 44px minimum tap target (Apple HIG / Material both name this
     figure) — the PREVIOUS bottom-nav height depended on font-line-height
     alone and could sit under it on some zoom/font-scale settings. */
  min-height: 44px;
}

.shell-bottom-nav a {
  flex: 1;
  flex-direction: column;
  justify-content: center;
  padding: 0.6rem 0.25rem;
  gap: 0.2rem;
  font-size: 0.7rem;
}

.shell-bottom-nav a.active,
.shell-nav a.active {
  color: var(--accent);
}

@media (min-width: 900px) {
  .shell-bottom-nav {
    display: none;
  }
  .shell-nav {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    width: 220px;
    flex-shrink: 0;
    padding: 1.25rem 0.75rem;
    border-right: 1px solid var(--border-hairline);
  }
  .shell-nav a {
    padding: 0.6rem 0.75rem;
    border-radius: var(--radius);
  }
  .shell-nav a.active {
    background: var(--surface-raised);
  }
}
