/* ═════════════════════════════════════════════════════════════════
   DESIGN v2 — Elevation layer (2026-06-10 remodel)
   Loaded AFTER app.css: the cascade lets this restyle every page
   without editing the base design system. Direction: "quiet luxury"
   — the silver logo + a champagne-gold brand accent, soft layered
   depth, gentle motion. Every class name is unchanged.
═════════════════════════════════════════════════════════════════ */

/* ── v2 tokens ── */
:root {
  --radius: 8px;
  --radius-2: 12px;
  --radius-lg: 16px;
  --t: 160ms cubic-bezier(0.4, 0, 0.2, 1);
  --t-slow: 280ms cubic-bezier(0.4, 0, 0.2, 1);

  /* Single flat brand gold (restrained accent) */
  --gold: #b8932f;
  --gold-2: #c9a542;
  --gold-dim: #8a6f24;
  --gold-ink: #1a1407;
}

:root,
:root[data-theme="dark"] {
  --shadow-1: none;
  --shadow-2: none;
  --shadow-3: none;
  --card-grad: none;
  --nav-glass: var(--surface);
}

:root[data-theme="light"] {
  --shadow-1: none;
  --shadow-2: none;
  --shadow-3: none;
  --card-grad: none;
  --nav-glass: var(--surface);
}

:root[data-theme="night"] {
  --shadow-1: none;
  --shadow-2: none;
  --shadow-3: none;
  --card-grad: none;
  --nav-glass: var(--surface);
}

/* ── Page entrance — content fades up ── */
.page-wrap {
  animation: fs-page-in 360ms cubic-bezier(0.25, 0.6, 0.3, 1) both;
}
@keyframes fs-page-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* ── Top nav — frosted glass ── */
.topnav {
  background: var(--nav-glass);
  -webkit-backdrop-filter: saturate(1.4) blur(14px);
  backdrop-filter: saturate(1.4) blur(14px);
  border-bottom: 1px solid var(--border);
  height: 56px;
}

.topnav__logo { height: 34px; }

/* Active nav: champagne underline instead of just bold */
.topnav__area-link.is-active,
.topnav__area-item.is-active > .topnav__area-link {
  position: relative;
}
.topnav__area-link.is-active::after,
.topnav__area-item.is-active > .topnav__area-link::after {
  content: "";
  position: absolute;
  left: var(--sp-3);
  right: var(--sp-3);
  bottom: -2px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--gold), var(--gold-2));
}

/* Dropdown — elevated, animated */
.topnav__drop-menu {
  border-radius: var(--radius-2);
  box-shadow: var(--shadow-3);
  padding: var(--sp-2);
  min-width: 188px;
}
.topnav__dropdown.is-open .topnav__drop-menu {
  animation: fs-pop 140ms cubic-bezier(0.3, 1.1, 0.4, 1) both;
}
@keyframes fs-pop {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
.topnav__drop-menu li a {
  border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-3);
}
.topnav__drop-menu li a.active {
  color: var(--gold-2);
  background: rgba(206,211,219, 0.12);
}
:root[data-theme="light"] .topnav__drop-menu li a.active { color: var(--gold-dim); }

/* ── Cards & KPI tiles — depth + lift ── */
.card,
.kpi-tile,
.chart-shell {
  background-image: var(--card-grad);
  box-shadow: var(--shadow-1);
  border-radius: var(--radius-2);
  transition: box-shadow var(--t), transform var(--t), border-color var(--t);
}

.kpi-tile {
  position: relative;
  overflow: hidden;
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
}
.kpi-tile:hover {
  box-shadow: var(--shadow-2);
  transform: translateY(-2px);
  border-color: var(--border-2);
}
/* Champagne hairline across the top of each KPI tile */
.kpi-tile::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--gold-dim), var(--gold) 40%, transparent 90%);
  opacity: 0.55;
}
.kpi-tile__value {
  font-size: 1.875rem;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}

/* ── Tables — soft container, calmer rows ── */
.table-wrap {
  border-radius: var(--radius-2);
  box-shadow: var(--shadow-1);
}
.data-table tbody tr { transition: background var(--t); }
.data-table td { padding-top: 11px; padding-bottom: 11px; }

/* ── Buttons — champagne primary, tactile press ── */
.btn {
  border-radius: var(--radius);
  transition: background var(--t), color var(--t), border-color var(--t),
              box-shadow var(--t), transform var(--t);
}
.btn:active { transform: translateY(1px) scale(0.99); }

.btn--primary {
  background: var(--gold);
  color: var(--gold-ink);
  font-weight: 600;
  border: 1px solid transparent;
}
.btn--primary:hover {
  background: var(--gold-2);
}

.btn--default { box-shadow: var(--shadow-1); }
.btn--default:hover { box-shadow: var(--shadow-2); }

/* ── Form fields — champagne focus ring ── */
.field__input, .field__select, .field__textarea {
  border-radius: var(--radius);
  transition: border-color var(--t), box-shadow var(--t);
}
.field__input:focus, .field__select:focus, .field__textarea:focus {
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(206,211,219, 0.25);
}

/* ── Badges — pills ── */
.badge { border-radius: var(--radius); padding: 2px 10px; }

/* ── Bar chart — champagne fills ── */
.bar-chart__track { height: 9px; border-radius: 5px; }
.bar-chart__fill {
  border-radius: 5px;
  background: linear-gradient(90deg, var(--gold-dim), var(--gold));
}
.bar-chart__row:first-child .bar-chart__fill {
  background: linear-gradient(90deg, var(--gold), var(--gold-2));
}

/* ── Bottom tabs (mobile) — frosted, gold active ── */
.bottom-tabs {
  background: var(--nav-glass);
  -webkit-backdrop-filter: saturate(1.4) blur(14px);
  backdrop-filter: saturate(1.4) blur(14px);
  border-top: 1px solid var(--border);
  /* Bar extends into the iOS home-indicator safe area; its icons stay in the
     top 60px while the inset pads the bottom. */
  height: calc(60px + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  box-sizing: border-box;
}
@media (max-width: 640px) {
  /* Clear the FULL bar height incl. the safe-area inset (+buffer) so the last
     element on any page — e.g. a Submit button — is never hidden behind the
     fixed nav. This was the portrait-only "can't see Submit" bug. */
  .shell { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }

  /* Inputs must be ≥16px on mobile or iOS Safari auto-zooms the page on focus
     (the hallmark of a non-native-feeling web app). 16px = no zoom. */
  input, select, textarea, .field__input, .field__select { font-size: 16px !important; }
}
.bottom-tab { transition: color var(--t), transform var(--t); }
.bottom-tab.is-active { color: var(--gold-2); }
:root[data-theme="light"] .bottom-tab.is-active { color: var(--gold-dim); }
.bottom-tab.is-active .bottom-tab__icon { transform: translateY(-1px); }

/* ── Assistant chat — champagne orb ── */
.chat-trigger {
  width: 52px;
  height: 52px;
  background: linear-gradient(145deg, var(--gold-2), var(--gold) 60%, #888e98);
  color: var(--gold-ink);
  box-shadow: var(--shadow-2), inset 0 1px 0 rgba(255,255,255,0.3);
  transition: transform var(--t), box-shadow var(--t);
}
.chat-trigger:hover {
  background: linear-gradient(145deg, #f3f5f8, var(--gold-2) 60%, var(--gold));
  transform: translateY(-2px) scale(1.04);
  box-shadow: var(--shadow-3);
}
.chat-panel {
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-3);
  overflow: hidden;
}
@media (max-width: 640px) {
  .chat-panel {
    border-top-left-radius: var(--radius-lg);
    border-top-right-radius: var(--radius-lg);
  }
}
.chat-msg { border-radius: 14px; }
.chat-msg--user {
  background: linear-gradient(180deg, var(--gold-2), var(--gold));
  color: var(--gold-ink);
}

/* ── Expand toggles, scrollbars ── */
.expand-toggle { border-radius: 6px; width: 20px; height: 20px; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb {
  background: var(--border-2);
  border-radius: 5px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--text-3); background-clip: padding-box; }
::-webkit-scrollbar-track { background: transparent; }

/* ── Splash screen — cinematic logo entrance on every fresh open ──
   Driven by html.fs-splashing (set pre-paint by a head script, once per
   browser session). Sequence:
     0.00s  black/theme screen, soft gold aura blooms behind center
     0.15s  logo materializes: blur-to-sharp, scale 0.8 → 1
     1.30s  logo breathes (gentle glow pulse) — the "hold" beat
     2.05s  whole splash dissolves UP-AND-OUT (opacity + scale 1.05)
            while the app underneath eases in from 98.5% scale
     2.90s  splash node removed
*/
/* FAIL-OPEN DESIGN: the whole timeline is pure CSS with `forwards`
   fill — it completes on its own even if every JS timer dies (iOS
   kills timers when a PWA is terminated and restored from the app
   switcher; with a JS-driven reveal the app stayed invisible forever).
   pointer-events is ALWAYS none, so a lingering splash can never trap
   a tap. JS only does cosmetic node removal afterwards. */
.fs-splash {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  pointer-events: none;
}
html.fs-splashing .fs-splash {
  display: flex;
  animation: fs-splash-seq 2750ms cubic-bezier(0.32, 0.72, 0, 1) forwards;
}
@keyframes fs-splash-seq {
  0%   { opacity: 1; transform: none;        visibility: visible; }
  74%  { opacity: 1; transform: none;        visibility: visible; }
  100% { opacity: 0; transform: scale(1.05); visibility: hidden; }
}

/* Gold aura blooming behind the logo */
.fs-splash::before {
  content: "";
  position: absolute;
  width: min(150vw, 640px);
  height: min(150vw, 640px);
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(206,211,219,0.22) 0%,
    rgba(206,211,219,0.10) 38%,
    transparent 68%);
  opacity: 0;
  transform: scale(0.55);
}
html.fs-splashing .fs-splash::before {
  animation: fs-aura-in 1300ms cubic-bezier(0.22, 0.61, 0.36, 1) 100ms both,
             fs-aura-pulse 1600ms ease-in-out 1400ms 2 alternate both;
}
@keyframes fs-aura-in {
  from { opacity: 0; transform: scale(0.55); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes fs-aura-pulse {
  from { transform: scale(1); }
  to   { transform: scale(1.08); }
}

/* The logo itself: blur-to-sharp materialize, then a breathing glow */
.fs-splash__logo {
  position: relative;
  width: min(56vw, 250px);
  height: auto;
}
html.fs-splashing .fs-splash__logo {
  animation: fs-logo-in 1150ms cubic-bezier(0.22, 0.61, 0.36, 1) 150ms both,
             fs-logo-breathe 1500ms ease-in-out 1350ms 2 alternate both;
}
@keyframes fs-logo-in {
  0%   { opacity: 0; transform: scale(0.8); filter: blur(16px); }
  55%  { opacity: 1; }
  100% { opacity: 1; transform: scale(1); filter: blur(0); }
}
@keyframes fs-logo-breathe {
  from { transform: scale(1);     filter: drop-shadow(0 0 0px rgba(206,211,219,0)); }
  to   { transform: scale(1.025); filter: drop-shadow(0 0 22px rgba(206,211,219,0.35)); }
}

/* The app underneath: hidden during the hold, then eases in as the
   splash dissolves — all CSS (`both` fill: hidden before the 2050ms
   delay, animates to visible, STAYS visible even if the class is
   never removed). No JS in the critical path. */
html.fs-splashing .shell,
html.fs-splashing .login-wrap {
  animation: fs-shell-in 700ms cubic-bezier(0.32, 0.72, 0, 1) 2050ms both;
}
@keyframes fs-shell-in {
  from { opacity: 0; transform: scale(0.985); }
  to   { opacity: 1; transform: none; }
}

/* ── Apple-smooth layer ───────────────────────────────────────────
   Grounded in Apple HIG Motion + WWDC18 "Designing Fluid Interfaces":
   - iOS sheet curve cubic-bezier(0.32, 0.72, 0, 1) for big moves
   - taps respond instantly (touchstart-driven :active, 150ms)
   - persistent chrome: nav + tab bar DON'T cross-fade between pages
   - only transform/opacity animate (compositor thread, 60fps)        */

/* Cross-page continuity, the dependable way: on every internal link
   tap, the CONTENT (not the nav shell) fades down 130ms before the
   browser navigates; the next page's content fades up on arrival.
   Combined with touchstart prefetch, page changes read as one fluid
   move — and it works on every browser, no View Transitions needed.
   The nav bar and bottom tabs stay put = native "stable shell". */
html.fs-leaving .page-wrap {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 130ms cubic-bezier(0.32, 0.72, 0, 1),
              transform 130ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* Kill every "cheap web" tell on iPhone */
html {
  -webkit-tap-highlight-color: transparent;
  background-color: #f0f0f2; /* no white flash between page loads */
}
html[data-theme="dark"]  { background-color: #0f0f0f; }
html[data-theme="night"] { background-color: #18171a; }
body { overscroll-behavior-y: none; }
a, button { touch-action: manipulation; }
.topnav a, .bottom-tab { -webkit-touch-callout: none; user-select: none; }
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* Theme switches glide instead of snapping */
body { transition: background-color 320ms ease, color 320ms ease; }

/* Instant touch response — fingers get feedback the moment they land */
@media (hover: none) {
  .btn:active { transform: scale(0.97); }
  .bottom-tab:active { transform: scale(0.94); }
  .kpi-tile:active { transform: scale(0.985); }
  .chat-trigger:active { transform: scale(0.92); }
  .topnav__drop-menu li a:active { background: var(--surface-3); }
}
.data-table tbody tr:active > td { background: var(--surface-3); }

/* Choreographed first paint: KPI tiles rise in with a 60ms stagger */
.kpi-grid .kpi-tile { animation: fs-page-in 420ms cubic-bezier(0.22, 0.61, 0.36, 1) both; }
.kpi-grid .kpi-tile:nth-child(1) { animation-delay: 40ms; }
.kpi-grid .kpi-tile:nth-child(2) { animation-delay: 100ms; }
.kpi-grid .kpi-tile:nth-child(3) { animation-delay: 160ms; }
.kpi-grid .kpi-tile:nth-child(4) { animation-delay: 220ms; }
@media (prefers-reduced-motion: reduce) {
  .kpi-grid .kpi-tile { animation: none; }
}

/* ── Transactions: keep long titles to one tidy ellipsized line ── */
#txn-table td:nth-child(3) {
  max-width: 420px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Legacy variable bridge — kills the theme-blind spots ──
   Calendar (and main.css) predate the theme system and use --color-*
   names that were defined ONCE with dark values, so in light/night
   mode things like the iCal URL field rendered as near-black boxes
   on a light page. Re-pointing the legacy names at the LIVE theme
   variables makes every old usage theme-aware automatically. */
:root {
  --color-bg:       var(--surface-2);
  --color-surface:  var(--surface);
  --color-border:   var(--border);
  --color-text:     var(--text);
  --color-muted:    var(--text-2);
  --color-accent:   var(--gold);
  --color-positive: var(--positive);
  --color-negative: var(--negative);
}

/* The iCal sync form fields — proper themed inputs with the gold focus */
.sync-form input[type="url"],
.sync-form textarea {
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  border-radius: var(--radius);
  color: var(--text);
  transition: border-color var(--t), box-shadow var(--t);
}
.sync-form input[type="url"]:focus,
.sync-form textarea:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(206,211,219, 0.22);
}

/* Every input on every page gets the same focus language + gold accents */
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(206,211,219, 0.22);
}
input[type="checkbox"], input[type="radio"], progress { accent-color: var(--gold); }

/* Compliance page: its badge/notice text colors were tuned for light
   mode only (dark reds/ambers unreadable on dark surfaces). Re-point
   at the theme-aware semantic tokens. */
.co-notice.warn { border-left-color: var(--warn-text); background: var(--warn); }
.badge-ok       { background: var(--ok);      color: var(--ok-text); }
.badge-warn     { background: var(--warn);    color: var(--warn-text); }
.badge-bad      { background: var(--bad);     color: var(--bad-text); }
.due-overdue    { background: var(--bad);     color: var(--bad-text); }
.due-soon       { background: var(--warn);    color: var(--warn-text); }
.due-ok         { background: var(--ok);      color: var(--ok-text); }
.btn-del:hover  { color: var(--bad-text); border-color: var(--bad-text); }

/* ── Mobile page head — stack instead of squeezing the title ── */
@media (max-width: 640px) {
  .page-head {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-3);
    margin-bottom: var(--sp-6);
  }
  .page-head__title { font-size: 1.375rem; }
  .page-head__actions { justify-content: flex-start; flex-wrap: wrap; }
  .page-wrap { padding: var(--sp-5) var(--sp-4); }
}

/* ── Reduced motion: respect the user ── */
@media (prefers-reduced-motion: reduce) {
  .page-wrap, .fs-splash, .fs-splash__logo,
  .topnav__dropdown.is-open .topnav__drop-menu { animation: none !important; }
  .kpi-tile:hover, .chat-trigger:hover, .btn:active { transform: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   "CASCADE" PREMIUM POLISH (2026-06-12)
   Modeled on the dark fintech-dashboard reel the owner referenced: deeper
   cinematic black, dark-glass cards with a crisp top edge, fully-rounded
   pill controls, and a soft champagne glow on the primary action + active
   nav. Champagne-gold accent kept (on-brand) instead of the reel's green.
   Layered last so it wins; theme-scoped so light mode stays clean.
   ═══════════════════════════════════════════════════════════════════════ */

/* Deeper, cinematic black + a faint champagne "spotlight" wash up top */
html[data-theme="dark"] {
  background-color: var(--bg);
  background-image: none;
}

/* Glass cards — larger radius, hairline border, hover lift */
.card, .kpi-tile, .chart-shell { border-radius: var(--radius-lg); }
.card {
  border: 1px solid var(--border);
  transition: box-shadow var(--t), transform var(--t), border-color var(--t);
}
.card:hover { box-shadow: var(--shadow-2); transform: translateY(-1px); }

/* Crisp top light-edge on dark surfaces (the reel's glassy panel highlight) */
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .kpi-tile,
:root[data-theme="dark"] .chart-shell,
:root:not([data-theme]) .card,
:root:not([data-theme]) .kpi-tile {
  box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.05);
}

/* Pill / lozenge controls — the reel's fully-rounded buttons & chips */
.btn { border-radius: 6px; }

/* Champagne glow on the primary action + the active bottom-tab */
.btn--primary:hover {
  box-shadow: var(--shadow-2), inset 0 1px 0 rgba(255,255,255,0.30),
              0 6px 22px -6px rgba(214,218,224,0.55);
}
.bottom-tab.is-active { filter: drop-shadow(0 0 7px rgba(214,218,224,0.35)); }

/* Big, confident figures (the reel's bold numbers) */
.kpi-tile__value { font-weight: 700; }

/* Generic stack-table → labeled "key → value" cards on mobile (any table that
   opts in with .stack-table; a script fills each cell's data-label from its <th>). */
@media (max-width: 640px) {
  .stack-table thead { display: none; }
  .stack-table, .stack-table tbody { display: block; }
  .stack-table tr { display: block; padding: 11px 14px; border-bottom: 1px solid var(--border); }
  .stack-table td {
    display: flex; justify-content: space-between; align-items: baseline; gap: 14px;
    padding: 5px 0 !important; border: none !important; text-align: right;
  }
  .stack-table td::before {
    content: attr(data-label); flex: 0 0 auto; text-align: left; white-space: nowrap;
    color: var(--text-3); font-size: 0.7rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.03em;
  }
  .stack-table td:not([data-label]) { justify-content: flex-end; }
  .stack-table td:not([data-label])::before { content: ""; }
}

/* To-Do tables → clean stacked cards on mobile (no cramped columns / clipping).
   Pure CSS so the existing tr-based toggle/delete JS keeps working untouched. */
@media (max-width: 640px) {
  .todo-table thead { display: none; }
  .todo-table, .todo-table tbody { display: block; }
  .todo-table tr {
    display: grid; grid-template-columns: auto 1fr auto;
    align-items: start; gap: 6px 12px;
    padding: 13px 14px; border-bottom: 1px solid var(--border);
  }
  .todo-table td { display: block; padding: 0 !important; border: none !important; }
  .todo-table td:nth-child(1) { grid-row: 1 / span 2; align-self: center; }  /* check */
  .todo-table td:nth-child(2) { grid-column: 2; font-size: 0.92rem; line-height: 1.35; } /* task */
  .todo-table td:nth-child(3) { grid-column: 2; }                            /* notes/date */
  .todo-table td:nth-child(4) { grid-column: 3; grid-row: 1; align-self: center; } /* delete */
}

/* Team & Logins → one tidy card per person on mobile (no clipped inputs/buttons). */
@media (max-width: 640px) {
  .team-table thead { display: none; }
  .team-table, .team-table tbody { display: block; }
  .team-table tr { display: block; padding: 14px; border-bottom: 1px solid var(--border); }
  .team-table td { display: block; padding: 0 0 6px !important; border: none !important; }
  .team-table td:nth-child(1) { font-weight: 700; font-size: 1rem; }
  .team-table td:nth-child(2) { font-size: 0.82rem; }
  .team-table td:nth-child(3) { padding-bottom: 10px !important; }
  .team-table td:nth-child(4) form { display: flex; gap: 8px; }
  .team-table td:nth-child(4) input { flex: 1; min-width: 0 !important; }
}

/* File inputs: kill the unstyled white "Choose File" tell — theme the field
   and turn the picker button into a champagne pill, app-wide. */
input[type="file"] {
  font-size: 0.85rem; color: var(--text-2); max-width: 100%;
  border: 1px solid var(--border); border-radius: 10px; padding: 7px 8px;
  background: var(--surface-2);
}
input[type="file"]::file-selector-button,
input[type="file"]::-webkit-file-upload-button {
  font: inherit; font-weight: 600; cursor: pointer;
  margin-right: 10px; padding: 7px 14px; border: none; border-radius: 999px;
  background: linear-gradient(180deg, var(--gold-2), var(--gold) 55%, #9aa0a9);
  color: var(--gold-ink);
}

/* KPI grids must NEVER cram 4–5 tiles across a phone (numbers clip/squish).
   Force 2 columns on mobile regardless of any inline repeat(N) the page sets. */
@media (max-width: 640px) {
  .kpi-grid { grid-template-columns: repeat(2, 1fr) !important; gap: 10px !important; }
  .kpi-tile { padding: 14px 14px 12px !important; }
  .kpi-tile__value { font-size: 1.45rem; }
  .kpi-tile__label { font-size: 0.62rem; }
}

/* Mobile theme toggle — glass pill, top-right (desktop uses the nav button) */
.fs-theme-fab { display: none; }
@media (max-width: 640px) {
  .fs-theme-fab {
    display: flex; align-items: center; justify-content: center;
    position: fixed; top: calc(10px + env(safe-area-inset-top, 0px)); right: 12px;
    z-index: 120; width: 40px; height: 40px; border-radius: 999px;
    background: var(--nav-glass);
    -webkit-backdrop-filter: blur(12px) saturate(1.4); backdrop-filter: blur(12px) saturate(1.4);
    border: 1px solid var(--border); color: var(--text); font-size: 1.05rem; line-height: 1;
    box-shadow: var(--shadow-2); cursor: pointer; -webkit-tap-highlight-color: transparent;
  }
  .fs-theme-fab:active { transform: scale(0.9); }
}

/* Tactile press: tiles + cards give a subtle lift + champagne glow when tapped */
@media (hover: none) {
  .kpi-tile:active { box-shadow: var(--shadow-2), 0 0 18px -6px rgba(214,218,224,0.5); }
  .review-queue__item:active, .month-block:active, .txn-card:active { transform: scale(0.992); }
}

/* Splash: a champagne light sweeps across the logo once (the reel's reveal) */
.fs-splash::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 40%, rgba(214,218,224,0.16) 50%, transparent 60%);
  transform: translateX(-120%); opacity: 0;
}
html.fs-splashing .fs-splash::after {
  animation: fs-shimmer 1150ms ease-in-out 600ms 1 both;
}
@keyframes fs-shimmer {
  0%   { opacity: 0; transform: translateX(-120%); }
  30%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(120%); }
}

/* ═══════════════════════════════════════════════════════════════════════
   REEL FEEL v2 (2026-06-13) — closing the gap to the numeric.ai/Fable 5 reel.
   The reel's "feel" decomposes into 5 repeatable techniques (NOT 3D magic):
     1. a true-black VOID so the UI floats,
     2. a heavy cinematic VIGNETTE framing the eye to center,
     3. a bright SPECULAR top-edge raking across each glass panel,
     4. faint SELF-ILLUMINATION (panels glow from within),
     5. slow, eased MOTION + a moving sheen on lit surfaces.
   We already have 1. This block adds 2–5. Dark-theme-scoped; light stays flat.
   Our app is a 2D ops dashboard, not a rotating 3D render — so we match the
   SURFACE LANGUAGE (glass, light, depth, motion), never literal 3D rotation
   (which would wreck usability for a working tool).
   ═══════════════════════════════════════════════════════════════════════ */

/* 2 — Cinematic vignette: a soft inset frame darkening only the outer edges,
   so the center reads bright and the screen feels like a lit object in a dark
   room. pointer-events:none → never blocks a tap; sits above everything. */
html[data-theme="dark"] body::after { content: none; }
@media (prefers-reduced-motion: no-preference) {
  html[data-theme="dark"] body::after { transition: box-shadow var(--t-slow); }
}

/* 3 — Brighter raking specular along the top edge of glass panels (the reel's
   single studio highlight catching the screen's bezel). Strengthens the faint
   inset highlight already on cards/tiles and adds a hairline light line. */
html[data-theme="dark"] .card,
html[data-theme="dark"] .kpi-tile,
html[data-theme="dark"] .chart-shell {
  box-shadow: var(--shadow-2),
              inset 0 1px 0 rgba(255,255,255,0.10),
              inset 0 0 0 1px rgba(255,255,255,0.012);
}
html[data-theme="dark"] .card { position: relative; }
html[data-theme="dark"] .card > :first-child { position: relative; z-index: 1; }
html[data-theme="dark"] .card::after {
  content: ""; position: absolute; top: 0; left: 14px; right: 14px; height: 1px;
  pointer-events: none; border-radius: 1px;
  background: linear-gradient(90deg, transparent,
              rgba(255,255,255,0.18) 30%, rgba(255,255,255,0.06) 68%, transparent);
}

/* 4 — Self-illumination: KPI tiles + charts emit a faint silver under-glow, as
   if backlit. Subtle (looks like ambient light, not a drop shadow). */
html[data-theme="dark"] .kpi-tile,
html[data-theme="dark"] .chart-shell {
  box-shadow: var(--shadow-2),
              inset 0 1px 0 rgba(255,255,255,0.10),
              0 0 50px -24px rgba(206,211,219,0.28);
}

/* 5a — A moving sheen sweeps the primary button on hover (lit-surface cue). */
.btn--primary { position: relative; overflow: hidden; }
.btn--primary::after {
  content: ""; position: absolute; top: 0; bottom: 0; left: -60%; width: 45%;
  pointer-events: none;
  background: linear-gradient(105deg, transparent, rgba(255,255,255,0.45), transparent);
  transform: skewX(-18deg); opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .btn--primary:hover::after { animation: fs-sheen 720ms ease-out 1; }
}
@keyframes fs-sheen {
  0%   { left: -60%; opacity: 0; }
  18%  { opacity: 1; }
  100% { left: 130%; opacity: 0; }
}

/* 5b — Cinematic numerals: tighter tracking + tabular figures so big numbers
   read as confident product-shot type, like the reel's price displays. */
html[data-theme="dark"] .kpi-tile__value {
  letter-spacing: -0.04em; font-variant-numeric: tabular-nums;
}

/* 5c — Snappy page entrance. Trimmed from 460ms → 200ms so navigations feel
   instant/native (paired with removing the blocking exit-fade). */
.page-wrap { animation: fs-page-in 200ms cubic-bezier(0.22, 0.7, 0.25, 1) both; }
@media (prefers-reduced-motion: reduce) { .page-wrap { animation: none; } }
