/* AUTO-GENERATED — copied from web/styles.css. Do not edit by hand.
 * Regenerated by scripts/sync-app-styles.js. Edit web/styles.css instead.
 */
:root {
  --bg: #0f0f13; --surface: #25252f; --surface2: #2e2e3a;
  --border: #3a3a4c; --accent: #7c6ff7; --accent-dim: #5a54c4;
  --accent-glow: rgba(124,111,247,0.15);
  --green: #4ade80; --red: #f87171; --yellow: #facc15;
  --text: #e8e8f0; --muted: #8888aa;
  --radius: 14px; --nav-h: 68px;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { height: 100%; scrollbar-gutter: stable; }

/* ── Global scrollbars ─────────────────────────────────────────────────────
   Thin, dark-mode-friendly scrollbars that feel like overlay: the thumb is
   transparent by default and fades in when the scrollable container is
   hovered, then brightens further on direct thumb hover or drag. WebKit/
   Chromium (Chrome, Edge, Safari) reserves the 8px track only when the
   element actually overflows — no always-reserved gutter on inner scrollers.
   Firefox approximates via scrollbar-width + scrollbar-color. This applies
   app-wide so any new scrollable element picks it up automatically. */
* {
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
}
*:hover, *:focus-within {
  scrollbar-color: rgba(255,255,255,0.22) transparent;
}
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
  background: transparent;
}
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: transparent;
  border-radius: 8px;
  border: 2px solid transparent;
  background-clip: padding-box;
  transition: background-color 0.25s ease;
}
*:hover::-webkit-scrollbar-thumb,
*:focus-within::-webkit-scrollbar-thumb {
  background-color: rgba(255,255,255,0.22);
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover,
::-webkit-scrollbar-thumb:active {
  background-color: rgba(255,255,255,0.45);
  background-clip: padding-box;
}
::-webkit-scrollbar-corner { background: transparent; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background-color: var(--bg);
  background-image: linear-gradient(180deg,
    rgba(124, 111, 247, 0.12) 0%,
    rgba(124, 111, 247, 0.04) 35%,
    transparent 100%);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  color: var(--text);
  min-height: 100vh;
  min-height: 100dvh;
}
h1 { font-size: 22px; font-weight: 700; }
h2 { font-size: 17px; font-weight: 600; }
p  { line-height: 1.6; }

/* ── Pages ── */
.page { display: none; padding: 0 16px calc(var(--nav-h) + 28px); padding-top: 84px; max-width: 520px; margin: 0 auto; width: 100%; }
/* Pockets page sits below #app-gtg-wrapper, which already owns the 70px
   header-clear padding — zero out here so the title sits ~20px below the
   GTG hero, matching the Transactions page's hero→title spacing. */
#page-pockets { padding-top: 0; }
#page-pockets { padding-top: 0; }
.page.active { display: block; }
/* ── Splash (shown while auth resolves) ── */
#app-splash { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; min-height: 100vh; min-height: 100dvh; padding: 32px 16px; }
#app-splash[style*="display: none"] { display: none !important; }

/* min-height uses 100dvh (dynamic viewport height) so mobile Chrome/Safari
 * exclude the address bar from the height calculation — using 100vh would
 * force the page to be taller than the visible area while the bar is up
 * and force a pointless scroll. 100vh fallback for older browsers. */
.auth-page { display: none; min-height: 100vh; min-height: 100dvh; align-items: center; justify-content: center; padding: 32px 16px; flex-direction: column; gap: 24px; }
.auth-page.active { display: flex; }

/* ── Fixed top header bar ──
   Visually mirrors the marketing site's <.top-nav>: translucent dark
   background with a backdrop-filter blur, hairline border, and the
   same 16px/28px padding so the chrome reads identically across the
   site → app boundary. */
#app-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  background: rgba(15, 15, 19, 0.72);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.04);
  padding: 16px 28px;
  /* Site nav height is set by the buttons/burger (~40px content) inside
     it; the app header only has ~22px of text content. Pad the floor
     up so the chrome lands at the same height as the site. */
  min-height: 72px;
  /* Flex with align-items:center vertically centers the inner row inside
     the min-height-padded box — without this the brand/GTG sit at the
     top of the padding area instead of the optical center. */
  display: flex;
  align-items: center;
}
.app-header-inner {
  flex: 1;
  max-width: 520px; margin: 0 auto; position: relative;
  display: flex; align-items: center; justify-content: center;
}
/* `#app-header` prefix bumps specificity above .logo-text (defined later
   in the file at 26px), the same way the site uses `.top-nav .logo-text`
   to override the base. Without the prefix, the brand silently renders
   at .logo-text's 26px instead of the 22px we want. */
#app-header .app-header-brand {
  display: inline-flex;
  align-items: center;
  font-size: 22px;
  white-space: nowrap;
}
/* margin-right (not flex gap) so the spacing only sits between the icon
   and the wordmark — gap would also wedge 10px between the "Pockets"
   text node and the <span>by Hoopy</span>, doubling the visible space. */
#app-header .app-header-brand .app-icon { width: 28px; height: 28px; vertical-align: 0; margin-right: 10px; }
.header-gtg-group {
  position: absolute; right: 0; top: 50%;
  transform: translateY(-50%);
  display: flex; align-items: baseline; gap: 8px;
  white-space: nowrap; opacity: 0;
}
.header-gtg-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 2px; color: #8888aa;
}
.header-gtg-amount {
  font-size: 22px; font-weight: 800; letter-spacing: -1px; color: var(--green);
}
.header-gtg-amount.negative { color: var(--red); }

/* ── GTG Hero ── */
#app-gtg-wrapper { display: none; max-width: 520px; margin: 0 auto; padding: 84px 16px 20px; }
#app-gtg-wrapper.visible { display: block; }
.gtg-hero {
  position: relative;
  background:
    radial-gradient(circle at 20% 0%, rgba(124, 111, 247, 0.30), transparent 55%),
    radial-gradient(circle at 80% 100%, rgba(246, 200, 96, 0.18), transparent 55%),
    var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 36px 24px 28px;
  text-align: center;
  box-shadow: 0 10px 32px -20px rgba(0, 0, 0, 0.55);
}

/* ── Loading skeletons ── */
/* Sit in place of the Good-to-Go amount + the pockets list while the
 * initial queries are in flight. The hero outline is preserved so the
 * page doesn't reflow when real data arrives. */
.loading-spinner {
  width: 32px; height: 32px;
  border: 3px solid rgba(255, 255, 255, 0.10);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }
.gtg-hero-loading .gtg-amount-skeleton {
  display: flex; align-items: center; justify-content: center;
  height: 64px;
  padding-top: 5px; padding-bottom: 18px;
}
.pockets-loading {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 48px 16px; gap: 14px; color: var(--muted); font-size: 14px;
}
.app-icon { width: 1.2em; height: 1.2em; vertical-align: -0.15em; display: inline-block; }
.gtg-label { font-size: 20px; color: var(--text); margin: 0; }
.gtg-amount { font-size: 48px; font-weight: 800; letter-spacing: -2px; color: var(--green); line-height: 1; font-variant-numeric: tabular-nums; padding-top: 5px; padding-bottom: 18px; }
.gtg-amount.negative { color: var(--red); }
/* Info button parks in the bottom-right corner of the hero so it doesn't
 * shove the centered label off-center. position:absolute means the rest of
 * the hero's content lays out as if the button weren't there. */
.gtg-info-btn {
  position: absolute; bottom: 12px; right: 12px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; font-size: 14px; font-weight: 700;
  background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12);
  color: rgba(255,255,255,0.5); cursor: pointer;
  font-family: inherit; padding: 0; transition: all 0.15s; line-height: 1;
}
.gtg-info-btn:hover { background: rgba(255,255,255,0.15); color: var(--text); border-color: var(--accent); }
.gtg-balance-age { font-size: 11px; color: var(--muted); margin-top: 12px; opacity: 0.5; letter-spacing: 0.3px; }

/* Single-line Stashed / Bank summary that sits above the Catch Up /
   Fund Now buttons. Intentionally not wrapped in a card — it reads
   as a supporting caption to the GTG hero, not a separate UI block. */
.pockets-summary-stashed {
  font-size: 13px;
  color: var(--muted);
  text-align: center;
  margin: 0 0 10px;
}
.pockets-summary-stashed span { color: var(--text); font-weight: 600; }

/* Catch Up / Fund Now action row groups directly under the hero. The
   paycheck pill itself now lives inside the hero (see .gtg-paycheck-btn
   below); only the action-row pair is rendered into the slot. */
.pockets-actions-group { display: flex; flex-direction: column; gap: 8px; }
.pockets-actions-group .pockets-action-row { margin-bottom: 0; }
#pockets-paycheck-line { display: none; }
#pockets-paycheck-slot:empty { display: none; }

/* ── Cards ── */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; margin-bottom: 12px; }
.card-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); margin-bottom: 10px; }
.card-header-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }

/* ── Inputs ── */
.input-group { display: flex; flex-direction: column; gap: 10px; }
input[type="email"], input[type="password"], input[type="text"],
input[type="number"], input[type="date"], textarea {
  width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: 12px;
  padding: 12px 14px; color: var(--text); font-size: 15px; outline: none;
  caret-color: var(--text);
  transition: border-color 0.2s, box-shadow 0.2s; font-family: inherit;
}
input.input-error, textarea.input-error {
  border-color: var(--red);
  box-shadow: 0 0 0 1px var(--red);
}
select {
  width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: 12px;
  padding: 11px 36px 11px 14px; color: var(--text); font-size: 15px; outline: none;
  transition: border-color 0.2s, box-shadow 0.2s; font-family: inherit;
  -webkit-appearance: none; appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238888aa' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-glow); }
input::placeholder { color: var(--muted); }
select option { background: var(--surface2); }
/* Override browser autofill white-box */
input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--surface2) inset !important;
  -webkit-text-fill-color: var(--text) !important;
  caret-color: var(--text) !important;
  border: 1px solid var(--border) !important;
  border-radius: 12px !important;
  background-clip: content-box !important;
  transition: background-color 5000s ease-in-out 0s;
}
/* Dark calendar picker — color-scheme forces the browser's native widget into dark mode */
input[type="date"] { color-scheme: dark; }
input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(0.7) sepia(0.2) saturate(0.6) hue-rotate(220deg) brightness(1.2); cursor: pointer; border-radius: 4px; }
/* Remove number input spinners */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }

/* ── Buttons ── */
button { cursor: pointer; border: none; border-radius: 10px; font-size: 15px; font-weight: 600; padding: 12px 18px; transition: opacity 0.15s, transform 0.1s, background 0.15s; font-family: inherit; }
button:active { transform: scale(0.97); }
button:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }
.btn-primary { background: var(--accent); color: #fff; width: 100%; }
.btn-primary:hover:not(:disabled) { background: var(--accent-dim); }
.btn-secondary { background: var(--surface2); border: 1px solid var(--border); color: var(--text); }
.btn-secondary:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.btn-ghost { background: transparent; color: var(--muted); font-size: 13px; padding: 6px 10px; }
.btn-ghost:hover { color: var(--text); }
.btn-icon { background: transparent; color: var(--muted); padding: 6px; font-size: 16px; }
.btn-icon:hover { color: var(--text); }
.btn-add-funds { background: var(--accent); color: #fff; font-size: 14px; padding: 8px 16px; border-radius: 10px; font-weight: 600; width: auto; }
.btn-add-funds:hover:not(:disabled) { background: var(--accent-dim); }
.btn-catch-up-pocket { background: var(--surface2); color: var(--text); font-size: 14px; padding: 8px 14px; border-radius: 10px; font-weight: 600; width: auto; border: 1px solid var(--border); }
.btn-catch-up-pocket:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.modal-box-sm { max-width: 340px; }
.btn-sm { background: var(--surface2); border: 1px solid var(--border); color: var(--muted); padding: 10px 12px; border-radius: 12px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all 0.15s; }
.btn-sm:hover { border-color: var(--accent); color: var(--accent); }
.btn-sm.active { background: var(--accent-glow); border-color: var(--accent); color: var(--accent); }

/* ── Alerts ── */
.alert { border-radius: 10px; padding: 12px 14px; font-size: 14px; line-height: 1.5; display: none; margin-top: 4px; }
.alert.show { display: block; }
.alert-error   { background: rgba(248,113,113,0.1); border: 1px solid rgba(248,113,113,0.4); color: var(--red); }
.alert-success { background: rgba(74,222,128,0.1);  border: 1px solid rgba(74,222,128,0.4);  color: var(--green); }
.alert-info    { background: rgba(124,111,247,0.1); border: 1px solid rgba(124,111,247,0.4); color: var(--accent); }
.alert-warning { background: rgba(234,179,8,0.10);   border: 1px solid rgba(234,179,8,0.45);  color: #facc15; }

/* ── Auth ── */
.auth-mark { width: 72px; height: 72px; display: block; margin-bottom: -12px; }
.auth-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 28px; width: 100%; max-width: 380px; display: flex; flex-direction: column; gap: 12px; }

/* ── Password field with reveal toggle ── */
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 46px !important; }
.pw-wrap input::-ms-reveal { display: none; }
.pw-eye-btn {
  position: absolute; right: 0; top: 0; bottom: 0; width: 44px;
  background: transparent; border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); transition: color 0.15s;
}
.pw-eye-btn:hover { color: var(--text); }
.pw-match-hint { font-size: 12px; margin: -4px 0 0; padding: 0 2px; min-height: 14px; }
.pw-match-hint.ok  { color: var(--green); }
.pw-match-hint.err { color: var(--red); }

.logo-text { font-size: 26px; font-weight: 800; letter-spacing: -0.5px; }
.logo-text span { color: var(--accent); }
.auth-subtitle { font-size: 14px; color: var(--muted); text-align: center; margin-top: 4px; }
.auth-link { text-align: center; font-size: 14px; color: var(--muted); }
.auth-link a { color: var(--accent); text-decoration: none; font-weight: 500; }

/* ── Bottom Nav ── */
#bottom-nav { display: none; position: fixed; bottom: 0; left: 0; right: 0; height: var(--nav-h); background: rgba(26,26,34,0.95); backdrop-filter: blur(12px); border-top: 1px solid var(--border); z-index: 100; }
#bottom-nav.visible { display: flex; }
.nav-items { display: flex; width: 100%; max-width: 520px; margin: 0 auto; }
.nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; cursor: pointer; background: transparent; border: none; color: var(--muted); font-size: 10px; font-weight: 500; padding: 14px 0; transition: color 0.15s; border-radius: 0; }
.nav-item svg { width: 30px; height: 30px; stroke-width: 1.8; }
/* The Transactions icon is fill-based (not a stroke outline like the
   others), so its visual weight reads smaller at the same px size.
   Bump it up a couple px to match the optical size of its siblings. */
#nav-transactions svg { width: 36px; height: 36px; }
/* Bank glyph leaves more whitespace inside its viewBox than the Pockets
   wallet, so push it up to the Transactions size to match optically. */
#nav-accounts svg { width: 36px; height: 36px; }
.nav-item.active { color: var(--accent); }
/* Visually hidden labels — kept in DOM so screen readers still hear
   "Pockets / Transactions / Profile" while the visible nav is icon-only. */
.nav-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.nav-item:active { transform: none; }

/* ── Page header ── */
.page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; padding-top: 2px; }
.page-header h1 { font-size: 22px; }

/* ── Connect banner ── */
.connect-banner { background: linear-gradient(135deg, #1e1b40, #271e42); border: 1px solid #3d3070; border-radius: var(--radius); padding: 24px; margin-bottom: 12px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.connect-banner p { font-size: 14px; color: var(--muted); line-height: 1.6; }
.connect-banner h2 { font-size: 17px; }

/* ── Account rows ── */
.account-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--border); }
.account-row:last-child { border-bottom: none; }
.account-name { font-size: 15px; font-weight: 500; }
.account-sub  { font-size: 12px; color: var(--muted); margin-top: 2px; }
.account-balance { font-size: 17px; font-weight: 700; color: var(--text); }
.account-balance.muted { color: var(--muted); }
.account-debt { font-size: 12px; color: var(--red); font-weight: 600; margin-top: 2px; text-align: right; }
/* Loans only have an outstanding balance (no "available"), so the debt
   line takes the primary slot. Same red as the secondary debt line on
   credit cards but sized like the regular balance. */
.account-debt.account-debt-primary { font-size: 17px; margin-top: 0; font-weight: 700; }
.account-debt.account-debt-primary.muted { color: var(--muted); }

/* ── Transactions ── */
.tx-row { display: flex; align-items: center; justify-content: space-between; padding: 13px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; margin-bottom: 8px; cursor: pointer; transition: border-color 0.15s; }
.tx-row:last-child { margin-bottom: 0; }
@media (hover: hover) { .tx-row:hover { border-color: var(--accent); } }
.tx-merchant { font-size: 15px; font-weight: 500; }
.tx-meta { font-size: 12px; color: var(--muted); margin-top: 3px; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.tx-amount { font-size: 16px; font-weight: 700; text-align: right; white-space: nowrap; }
.tx-amount.debit  { color: var(--text); }
.tx-amount.credit { color: var(--green); }

/* ── Badges ── */
.badge { display: inline-flex; align-items: center; font-size: 10px; font-weight: 600; padding: 2px 7px; border-radius: 99px; background: var(--surface2); color: var(--muted); border: 1px solid var(--border); }
.badge.pending  { background: rgba(250,204,21,0.1);  color: var(--yellow); border-color: rgba(250,204,21,0.3); }
.badge.linked   { background: rgba(124,111,247,0.1); color: var(--accent); border-color: rgba(124,111,247,0.3); }
.badge.verified { background: rgba(74,222,128,0.1);  color: var(--green);  border-color: rgba(74,222,128,0.3); }
.badge.gtg      { background: rgba(124,111,247,0.08); color: var(--accent); border-color: rgba(124,111,247,0.2); }

/* ── Multi-select filter ── */
.filter-row { display: flex; gap: 10px; margin-bottom: 12px; }
.multi-select { position: relative; flex: 1; }
.multi-select-btn {
  width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: 12px;
  padding: 10px 36px 10px 14px; font-size: 13px; color: var(--text); cursor: pointer;
  text-align: left; font-family: inherit; font-weight: 500; transition: border-color 0.2s;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238888aa' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
.multi-select-btn:hover { border-color: var(--accent); }
.multi-select-menu { display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; z-index: 50; overflow: hidden; box-shadow: 0 8px 24px rgba(0,0,0,0.4); min-width: 180px; }
.multi-select-menu.open { display: block; }
.multi-select-item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; cursor: pointer; font-size: 14px; transition: background 0.1s; }
.multi-select-item:hover { background: var(--surface2); }
.multi-select-item input[type="checkbox"] { accent-color: var(--accent); width: 16px; height: 16px; flex-shrink: 0; -webkit-appearance: auto; appearance: auto; }
.multi-select-divider { height: 1px; background: var(--border); margin: 2px 0; }

/* ── Transaction toolbar (search + filter + sort) ── */
.tx-toolbar { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.tx-search-row { display: flex; align-items: center; gap: 8px; }
.tx-search-wrap { flex: 1; position: relative; }
.tx-search-wrap svg { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
.tx-search-input { padding-left: 36px !important; font-size: 14px !important; }
.tx-filter-row { display: flex; gap: 8px; flex-wrap: wrap; }
.tx-filter-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 12px; border-radius: 20px; font-size: 12px; font-weight: 600;
  background: var(--surface2); border: 1px solid var(--border); color: var(--muted);
  cursor: pointer; transition: all 0.15s; white-space: nowrap;
}
.tx-filter-chip:hover { border-color: var(--accent); color: var(--accent); }
.tx-filter-chip.active { background: var(--accent-glow); border-color: var(--accent); color: var(--accent); }
.tx-filter-chip .chip-clear { font-size: 14px; color: var(--accent); margin-left: 2px; }
/* Filter panel (dropdown under toolbar) */
.tx-filter-panel { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 14px; display: none; flex-direction: column; gap: 12px; }
/* Two-column filter row (Account | Account Type, Transaction Type | Category). */
.tx-filter-row { display: flex; gap: 10px; }
.tx-filter-row .tx-filter-section { min-width: 0; }
.tx-filter-heading {
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.2px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 2px;
}
.tx-filter-actions {
  display: flex;
  gap: 10px;
  margin-top: 6px;
}
.tx-filter-action-btn {
  flex: 1 1 0;
  min-width: 0;
  padding: 10px 16px;
  font-size: 14px;
}
.tx-filter-panel.open { display: flex; }
.tx-filter-section label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; display: block; margin-bottom: 6px; }
.tx-filter-range { display: flex; align-items: center; gap: 6px; }
.tx-filter-range input { flex: 1; font-size: 13px !important; padding: 8px 10px !important; }
.tx-filter-range span { color: var(--muted); font-size: 12px; }
/* Transaction section headers (Pending / Posted) */
.tx-empty-state {
  text-align: center;
  padding: 40px 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.tx-empty-title { font-size: 16px; font-weight: 600; color: var(--text); margin: 0; }
.tx-empty-sub { font-size: 13px; color: var(--muted); margin: 0 0 10px; max-width: 280px; line-height: 1.5; }
.tx-empty-clear { padding: 8px 16px; font-size: 13px; }
.tx-section-header { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; padding: 10px 0 6px; margin-top: 4px; border-bottom: 1px solid var(--border); margin-bottom: 8px; }
.tx-section-header:first-child { padding-top: 0; }
/* Category group header used when sort=category — a small colored dot +
   the category name, quieter than the Pending/Posted top-level headers. */
.tx-cat-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text);
  font-weight: 600;
  padding: 12px 0 6px;
  margin-top: 4px;
}
.tx-cat-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: 0 0 auto;
}

/* ── Sort controls ── */
.sort-row { display: flex; gap: 12px; align-items: flex-end; margin-bottom: 12px; }
.sort-col { display: flex; flex-direction: column; gap: 4px; flex: 1; }
.sort-col:last-child { flex: 1; }
.sort-label { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); }
.sort-row select { width: 100%; font-size: 13px; padding: 10px 36px 10px 12px; }
.sort-dir-btn { background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; display: flex; align-items: center; justify-content: center; color: var(--text); min-width: 42px; flex-shrink: 0; align-self: flex-end; }
.sort-dir-btn:hover { border-color: var(--accent); color: var(--accent); }

/* ── Pockets ── */
.pocket-row { padding: 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; cursor: pointer; margin-bottom: 8px; transition: border-color 0.15s; }
.pocket-row:last-child { margin-bottom: 0; }
@media (hover: hover) { .pocket-row:hover { border-color: var(--accent); } }
.pocket-row.paused { opacity: 0.5; filter: grayscale(0.5); }
.pocket-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 7px; gap: 8px; }
.pocket-name { font-size: 15px; font-weight: 600; flex: 1; }
.pocket-amounts { font-size: 13px; color: var(--muted); white-space: nowrap; }
.pocket-amounts strong { color: var(--text); }
.pocket-meta { font-size: 12px; color: var(--muted); margin-top: 6px; display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.progress-track { height: 6px; background: var(--surface2); border-radius: 99px; overflow: hidden; }
.progress-fill { height: 100%; background: var(--accent); border-radius: 99px; transition: width 0.4s ease; }
.progress-fill.full { background: var(--green); }
.progress-fill.over { background: var(--yellow); }
.due-soon { color: var(--yellow); }
.due-next-paycheck { color: #60a5fa; }
.past-due { color: var(--red); }

/* ── Overflow menus ── */
.bank-menu-wrap { position: relative; }
.bank-menu-btn { background: transparent; color: var(--muted); padding: 8px 10px; font-size: 22px; line-height: 1; }
.bank-menu-btn:hover { color: var(--text); }
.bank-menu { display: none; position: absolute; right: 0; top: 100%; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; min-width: 240px; z-index: 50; overflow: hidden; box-shadow: 0 8px 24px rgba(0,0,0,0.4); }
.bank-menu.open { display: block; }
.bank-menu button { display: block; width: 100%; text-align: left; border-radius: 0; padding: 12px 16px; font-size: 14px; font-weight: 500; background: transparent; color: var(--text); }
.bank-menu button:hover { background: var(--surface2); }
.bank-menu button.danger { color: var(--red); }

/* GTG toggle pill in menu */
.menu-toggle-row { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; cursor: pointer; gap: 12px; }
.menu-toggle-row:hover { background: var(--surface2); }
.menu-toggle-row span { font-size: 14px; font-weight: 500; color: var(--text); }

.profile-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.profile-row:last-of-type { border-bottom: none; }
.profile-row-text { flex: 1; min-width: 0; }
.profile-row-label { font-size: 12px; color: var(--muted); margin-bottom: 2px; }
.profile-row-value { font-size: 15px; color: var(--text); word-break: break-word; }
.menu-toggle-disabled { opacity: 0.35; cursor: default; pointer-events: none; }
.menu-toggle-disabled:hover { background: transparent; }
.toggle-pill { width: 38px; height: 22px; border-radius: 99px; background: var(--border); position: relative; transition: background 0.2s; flex-shrink: 0; }
.toggle-pill::after { content: ''; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: left 0.2s; }
.toggle-pill.on { background: var(--accent); }
.toggle-pill.on::after { left: 19px; }
.account-balance.gtg-on { color: var(--green); }

/* ── Modals ── */
/* (Per-modal ID rules used to duplicate .modal-overlay and .modal-box-style
   rules, but their higher specificity fought the fullscreen-mobile media
   query. Class-based rules below are the source of truth.) */
.modal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.modal-header h2 { font-size: 18px; }
.modal-close { background: transparent; color: var(--muted); font-size: 22px; padding: 4px 8px; }
.modal-close:hover { color: var(--text); }
.field-label { font-size: 12px; color: var(--muted); margin-bottom: 4px; }
.field-group { display: flex; flex-direction: column; gap: 4px; }
.modal-actions { display: flex; gap: 10px; margin-top: 8px; }
.modal-actions button { flex: 1; }
/* Save buttons in modals: extra top margin = field-label line-height so there's breathing room */
.modal-body .pocket-modal-actions,
.modal-body .input-group > .btn-primary,
.modal-body > .btn-primary,
#page-accounts .card .btn-primary { margin-top: 16px; }

/* Modal linked transactions */
.modal-txs { border-top: 1px solid var(--border); margin-top: 4px; padding-top: 12px; }
.modal-tx-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); margin-bottom: 8px; }
.modal-tx-row { display: flex; justify-content: space-between; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border); }
.modal-tx-row:last-child { border-bottom: none; }
.modal-tx-merchant { font-size: 14px; font-weight: 500; }
.modal-tx-meta { font-size: 12px; color: var(--muted); margin-top: 2px; }
.modal-tx-amount { font-size: 14px; font-weight: 700; white-space: nowrap; }

/* ── Summary row ── */
.summary-row { display: flex; gap: 20px; flex-wrap: wrap; }
.summary-item { font-size: 13px; color: var(--muted); }
.summary-item span { color: var(--text); font-weight: 600; display: block; font-size: 15px; }

/* ── Empty / loading ── */
.empty { text-align: center; padding: 40px 16px; color: var(--muted); }
.empty-icon { font-size: 36px; margin-bottom: 10px; }
.empty p { font-size: 14px; line-height: 1.6; }
.loading-state { text-align: center; padding: 40px 16px; color: var(--muted); font-size: 14px; }

/* ── Spinner ── */
.spinner { display: inline-block; width: 15px; height: 15px; border: 2px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.65s linear infinite; vertical-align: middle; margin-right: 5px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Toast ── */
#toast { position: fixed; bottom: calc(var(--nav-h) + 12px); left: 50%; transform: translateX(-50%) translateY(20px); background: var(--surface2); border: 1px solid var(--border); color: var(--text); padding: 10px 16px; border-radius: 10px; font-size: 14px; transition: opacity 0.25s, transform 0.25s; z-index: 200; white-space: nowrap; opacity: 0; pointer-events: none; max-width: 90vw; overflow: hidden; text-overflow: ellipsis; }
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
#toast.success { border-color: rgba(74,222,128,0.5);  color: var(--green); }
#toast.error   { border-color: rgba(248,113,113,0.5); color: var(--red); }
#toast.info    { border-color: var(--border); color: var(--muted); }

/* ── Install banner ── */
/* Pinned above the bottom nav so it doesn't cover tappable controls. Sized
   to look like an in-app suggestion, not a takeover. The [hidden] attribute
   is still honored so the JS toggle is the single source of truth. */
.install-banner { position: fixed; bottom: calc(var(--nav-h, 0px) + 12px); left: 12px; right: 12px; max-width: 460px; margin: 0 auto; display: flex; align-items: center; gap: 12px; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 12px 14px; box-shadow: 0 12px 32px rgba(0,0,0,0.45); z-index: 250; }
.install-banner[hidden] { display: none; }
.install-banner-icon { width: 40px; height: 40px; border-radius: 10px; background: #000; display: grid; place-items: center; flex-shrink: 0; }
.install-banner-icon img { width: 40px; height: 40px; border-radius: 10px; }
.install-banner-text { flex: 1; min-width: 0; }
.install-banner-title { font-size: 14px; font-weight: 700; color: var(--text); }
.install-banner-sub { font-size: 12px; color: var(--muted); margin-top: 2px; line-height: 1.35; }
.install-banner-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.install-banner-btn-primary { background: var(--accent); color: #fff; border: none; border-radius: 8px; padding: 8px 14px; font-size: 13px; font-weight: 600; cursor: pointer; }
.install-banner-btn-primary:hover { background: var(--accent-dim); }
.install-banner-btn-primary[hidden] { display: none; }
.install-banner-btn-close { background: transparent; border: none; color: var(--muted); width: 28px; height: 28px; border-radius: 8px; cursor: pointer; font-size: 14px; }
.install-banner-btn-close:hover { background: var(--surface2); color: var(--text); }

/* ── Misc ── */
a { color: var(--accent); text-decoration: none; }

/* ── Page title row ── */
.page-title-row { display: flex; align-items: center; justify-content: space-between; padding-top: 4px; margin-bottom: 14px; gap: 8px; flex-wrap: wrap; }
.page-title-row h1 { font-size: 22px; }

.pockets-header-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.pocket-header-btn { width: auto; padding: 8px 14px; font-size: 13px; white-space: nowrap; }
.pocket-header-btn-primary { padding: 8px 16px; font-size: 14px; }

/* Action pills sit inside the GTG hero below the paycheck button. Natural
   width — they hug their label/amount — centered as a pair. The GTG number is
   the focus of this page, so these buttons stay quiet: subtle secondary
   surface, with the amount rendered as small muted detail text. */
.pockets-action-row { display: flex; gap: 8px; margin-bottom: 12px; }
.pocket-action-btn { flex: 1; display: inline-flex; align-items: baseline; justify-content: center; gap: 6px; padding: 10px 14px; border-radius: 12px; background: var(--surface2); border: 1px solid var(--border); color: var(--text); cursor: pointer; transition: border-color 0.15s, color 0.15s; font: inherit; white-space: nowrap; line-height: 1.2; }
.pocket-action-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.pocket-action-btn:hover:not(:disabled) .pocket-action-amount { color: var(--accent); }
.pocket-action-btn:disabled { cursor: not-allowed; color: var(--muted); opacity: 0.75; }
.pocket-action-btn.is-muted { color: var(--muted); border-color: var(--border); }
.pocket-action-btn.is-muted .pocket-action-amount { color: var(--muted); }
/* Amount turns red when the action would push GTG negative — label stays
   the same so the action remains visually clickable. */
.pocket-action-btn.over-budget .pocket-action-amount { color: var(--red); }
.pocket-action-btn.over-budget:hover .pocket-action-amount { color: var(--red); }
.pocket-action-label { font-size: 14px; font-weight: 600; }
.pocket-action-amount { font-size: 12px; font-weight: 500; color: var(--muted); }
.pocket-action-btn:disabled .pocket-action-amount { display: none; }

/* ── Soft select wrapper (select + custom arrow overlay) ── */
.soft-select-wrap { position: relative; }
.soft-select-wrap select { padding-right: 36px; }
.soft-select-arrow { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); pointer-events: none; color: var(--muted); display: flex; align-items: center; }

/* ── Pocket cards ── */
.pocket-card { background: #2a2a36; border: 1px solid var(--border); border-radius: 12px; padding: 14px 14px 12px; margin-bottom: 10px; cursor: pointer; transition: border-color 0.15s; }
@media (hover: hover) { .pocket-card:hover { border-color: var(--accent); } }
.pocket-card.paused { background: #15151e; border-color: #222234; }
@media (hover: hover) { .pocket-card.paused:hover { border-color: var(--accent); } }
.pocket-card.paused .pocket-name,
.pocket-card.paused .pocket-amounts,
.pocket-card.paused .pocket-meta,
.pocket-card.paused .badge-spending-fund { opacity: 0.65; }
.pocket-card-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.pocket-name-group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; flex: 1; min-width: 0; }
.pocket-name { font-size: 15px; font-weight: 600; color: var(--text); }
.pocket-amounts { font-size: 16px; font-weight: 700; white-space: nowrap; flex-shrink: 0; }
.pocket-stashed { color: var(--text); }
.pocket-sep { color: var(--muted); font-weight: 400; }
.pocket-goal { color: var(--muted); font-weight: 500; }
.pocket-category { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; border-radius: 99px; padding: 2px 8px; border: 1px solid; flex-shrink: 0; margin-bottom: 5px; }
/* Tags row — category pill on the left, status badges on the right.
   Space-between pushes them to the edges of the card so the row reads
   as "what this pocket IS" (category) and "what STATE it's in"
   (badges) at a glance. Wraps if a long category name + many badges
   don't fit. */
.pocket-tags-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.pocket-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.pocket-progress-wrap { height: 10px; background: #35354a; border-radius: 99px; overflow: hidden; margin-top: 8px; }
.pocket-progress-bar { height: 100%; background: var(--accent); border-radius: 99px; transition: width 0.4s ease; min-width: 0; }
.pocket-progress-bar.full   { background: var(--green); }
.pocket-progress-bar.over   { background: var(--green); }
.pocket-progress-bar.behind { background: var(--red); }
.pocket-meta { font-size: 12px; color: var(--muted); display: flex; gap: 10px; flex-wrap: nowrap; align-items: center; overflow: hidden; margin-top: 4px; }

/* ── Transaction cards ── */
.tx-card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 12px 14px; margin-bottom: 10px; cursor: pointer; transition: border-color 0.15s; position: relative; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
@media (hover: hover) { .tx-card:hover { border-color: var(--accent); } }
.tx-card.selectable { padding-left: 44px; }
.tx-card.selectable::before { content: ''; position: absolute; left: 14px; top: 50%; transform: translateY(-50%); width: 20px; height: 20px; border-radius: 50%; border: 2px solid var(--border); background: transparent; transition: background 0.12s, border-color 0.12s; }
.tx-card.selectable.selected { border-color: var(--accent); }
.tx-card.selectable.selected::before { background: var(--accent); border-color: var(--accent); }
.tx-card.selectable.selected::after { content: '✓'; position: absolute; left: 18px; top: 50%; transform: translateY(-50%); color: #fff; font-size: 13px; font-weight: 700; line-height: 1; }
#tx-select-bar { position: fixed; left: 50%; bottom: calc(var(--nav-h) + 12px); transform: translateX(-50%); z-index: 1000; display: flex; align-items: center; gap: 12px; padding: 10px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 10px 30px rgba(0,0,0,0.45); max-width: calc(100% - 32px); }
#tx-select-bar #tx-select-count { font-size: 14px; color: var(--text); white-space: nowrap; font-weight: 500; }
#tx-select-bar .btn-primary { width: auto; padding: 8px 18px; font-size: 14px; }
#tx-select-bar .btn-ghost { padding: 8px 12px; font-size: 14px; }
.tx-card-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 4px; }
.tx-card-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: 12px; color: var(--muted); }
.tx-card-bottom { display: flex; align-items: center; justify-content: space-between; gap: 6px; flex-wrap: wrap; }
.tx-meta-left { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tx-meta-right { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-left: auto; }
.tx-acct-badge { font-size: 10px; font-weight: 600; padding: 2px 7px; border-radius: 99px; background: var(--surface2); color: var(--muted); border: 1px solid var(--border); white-space: nowrap; }
.tx-pocket-badge { font-size: 10px; font-weight: 600; padding: 2px 7px; border-radius: 99px; background: rgba(124,111,247,0.12); color: var(--accent); border: 1px solid rgba(124,111,247,0.3); white-space: nowrap; }
.tx-category { font-size: 11px; color: var(--muted); }
.tx-date { font-size: 11px; color: var(--muted); white-space: nowrap; }
.tx-status { font-size: 10px; font-weight: 600; padding: 2px 7px; border-radius: 99px; }
.tx-status.posted { background: rgba(74,222,128,0.1); color: var(--green); border: 1px solid rgba(74,222,128,0.3); }
.tx-status.pending  { background: rgba(250,204,21,0.1); color: var(--yellow); border: 1px solid rgba(250,204,21,0.3); }

/* ── Transaction modal detail ── */
.tx-detail-merchant { font-size: 18px; font-weight: 700; margin-bottom: 4px; }
.tx-detail-amount { font-size: 26px; font-weight: 800; color: var(--text); margin-bottom: 10px; }
.tx-detail-amount.credit { color: var(--green); }
.tx-detail-meta { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 4px; }

/* ── Linked transaction rows (in pocket modal) ── */
.tx-linked-row { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: 14px; gap: 10px; }
.tx-linked-row:last-child { border-bottom: none; }
.tx-linked-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.tx-linked-date { font-size: 12px; color: var(--muted); }
.tx-linked-right { display: flex; align-items: center; gap: 8px; }
.tx-linked-unlink { background: transparent; border: none; color: var(--muted); font-size: 14px; line-height: 1; padding: 4px 6px; border-radius: 6px; transition: color 0.15s, background 0.15s; cursor: pointer; }
.tx-linked-unlink:hover { color: var(--red); background: rgba(248,113,113,0.1); }
.tx-linked-unlink .tx-link-off { display: none; }
.tx-linked-unlink:hover .tx-link-on { display: none; }
.tx-linked-unlink:hover .tx-link-off { display: inline-block; }

/* ── Collapsible card section (linked tx, funding history) ── */
.card-collapse { border: 0; padding: 0; margin: 0; }
.card-collapse > summary { list-style: none; cursor: pointer; user-select: none; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 0; }
.card-collapse > summary::-webkit-details-marker { display: none; }
.card-collapse > summary .card-label { margin-bottom: 0; flex: 1; }
.card-collapse > summary .card-collapse-chevron { width: 12px; height: 12px; color: var(--muted); transition: transform 0.15s; flex-shrink: 0; }
.card-collapse[open] > summary .card-collapse-chevron { transform: rotate(90deg); }
.card-collapse > .card-collapse-body { padding-top: 4px; }

/* ── Funding history rows (in pay-cycle modal) ── */
.fh-row { display: flex; justify-content: space-between; align-items: flex-start; padding: 8px 0; border-bottom: 1px solid var(--border); gap: 10px; }
.fh-row:last-child { border-bottom: none; }
.fh-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.fh-date { font-size: 14px; color: var(--text); }
.fh-trigger { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.5px; }
.fh-trigger.fh-trigger-auto { color: var(--green); }
.fh-amount { font-size: 14px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }

/* ── Account groups ── */
.account-group-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 12px; }
.account-group-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--muted); margin-bottom: 10px; }
.account-group-list { display: flex; flex-direction: column; }
.account-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--border); gap: 10px; }
.account-row:last-child { border-bottom: none; }
.account-row-disabled .account-name { color: var(--muted); }
.account-row-disabled .account-debt { color: var(--muted); }
.account-row-info { flex: 1; min-width: 0; }
.account-row-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.account-balance-wrap { text-align: right; }
  .account-disabled-badge { font-size: 10px; font-weight: 600; color: var(--muted); border: 1px solid var(--muted); border-radius: 99px; padding: 2px 8px; margin-left: 6px; vertical-align: middle; }
.connection-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--border); }
.connection-row:last-child { border-bottom: none; }
.connection-info { flex: 1; min-width: 0; }
.connection-name { font-size: 15px; font-weight: 500; }
.connection-count { font-size: 12px; color: var(--muted); margin-top: 2px; }
.menu-item { display: block; width: 100%; text-align: left; border-radius: 0 !important; padding: 12px 16px !important; font-size: 14px !important; font-weight: 500 !important; background: transparent !important; color: var(--text) !important; }
.menu-item:hover { background: var(--surface2) !important; }
.menu-item.danger { color: var(--red) !important; }
/* Soft-gated menu item: dimmed text + a Premium badge on the right.
   Still clickable — the click handler routes to the upsell modal. */
.menu-item-gated { display: flex !important; align-items: center; justify-content: space-between; gap: 8px; color: var(--muted) !important; }
.menu-item-gated:hover { color: var(--text) !important; }
.premium-badge { font-size: 10px; font-weight: 600; letter-spacing: 0.4px; text-transform: uppercase; padding: 2px 6px; border-radius: 4px; background: var(--surface2); color: var(--muted); border: 1px solid var(--border); }
.menu-item-gated:hover .premium-badge { color: var(--text); }

/* ── Dev paid-API-call dashboard ────────────────────────────────────── */
/* Hero stat at the top of the panel — the headline number that drives
   premium pricing decisions: combined cost per active user per month. */
.paid-hero { background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; padding: 14px; text-align: center; margin-bottom: 14px; }
.paid-hero-value { font-size: 26px; font-weight: 700; color: var(--text); line-height: 1.1; }
.paid-hero-label { font-size: 12px; font-weight: 500; color: var(--muted); margin-top: 4px; }
.paid-hero-breakdown { font-size: 11px; color: var(--muted); margin-top: 6px; opacity: 0.8; }

/* Top stat tiles: one row, wraps on narrow screens. */
.paid-stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 8px; }
.paid-stat-row + .paid-stat-row { margin-bottom: 14px; }
.paid-stat-row-secondary .paid-stat-tile { background: transparent; border-style: dashed; }
.paid-stat-tile { background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; min-width: 0; }
.paid-stat-value { font-size: 16px; font-weight: 600; color: var(--text); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.paid-stat-label { font-size: 11px; color: var(--muted); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Section headers between tile group and each list. */
.paid-section-header { font-size: 11px; font-weight: 600; letter-spacing: 0.6px; text-transform: uppercase; color: var(--muted); margin: 14px 0 6px; padding-bottom: 4px; border-bottom: 1px solid var(--border); }

/* Generic row used by all three lists. */
.paid-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 0; border-bottom: 1px dashed transparent; }
.paid-row + .paid-row { border-top: 1px solid var(--border); }
.paid-row-stack { flex-direction: column; align-items: stretch; gap: 2px; }
.paid-row-compact { padding: 4px 0; }
.paid-row-primary { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.paid-row-meta { display: flex; align-items: center; gap: 6px; font-size: 11px; color: var(--muted); flex-wrap: wrap; }
.paid-row-left { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; }
.paid-row-right { display: flex; align-items: baseline; gap: 8px; flex-shrink: 0; }

.paid-name { font-size: 13px; font-weight: 500; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.paid-name-small { font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 120px; }
.paid-endpoint { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.paid-endpoint-small { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.paid-cost { font-size: 13px; font-weight: 600; color: var(--text); white-space: nowrap; }
.paid-cost-small { font-size: 12px; }
.paid-meta { font-size: 11px; color: var(--muted); white-space: nowrap; }
.paid-recent-when { font-size: 12px; font-weight: 500; color: var(--text); }

/* Provider pill — distinguishes Plaid vs Teller cost rows at a glance. */
.paid-provider-pill { font-size: 9px; font-weight: 700; letter-spacing: 0.6px; text-transform: uppercase; padding: 1px 6px; border-radius: 4px; line-height: 1.4; }
.paid-provider-plaid { background: rgba(0, 122, 255, 0.12); color: rgb(0, 122, 255); border: 1px solid rgba(0, 122, 255, 0.25); }
.paid-provider-teller { background: rgba(255, 102, 51, 0.12); color: rgb(232, 90, 40); border: 1px solid rgba(255, 102, 51, 0.25); }

.paid-empty { font-size: 12px; color: var(--muted); font-style: italic; padding: 10px 0; text-align: center; opacity: 0.7; }

/* ── Multi-select filter (wrapping the custom dropdown) ── */
.multi-select-wrap { position: relative; flex: 1; }
.multi-select-btn { width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 36px 10px 14px; font-size: 13px; color: var(--text); cursor: pointer; text-align: left; font-family: inherit; font-weight: 500; transition: border-color 0.2s; display: flex; align-items: center; justify-content: space-between; }
.multi-select-btn:hover { border-color: var(--accent); }
.multi-select-btn svg { color: var(--muted); flex-shrink: 0; }
.multi-select-menu { display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; z-index: 50; overflow: hidden; box-shadow: 0 8px 24px rgba(0,0,0,0.4); min-width: 180px; }

/* ── Modals (new class-based system) ── */
.modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 300; align-items: center; justify-content: center; padding: 16px; }
.modal-overlay.open { display: flex; }
.modal-box { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); width: 100%; max-width: 480px; max-height: 90vh; max-height: 90dvh; overflow-y: auto; display: flex; flex-direction: column; }
.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 20px 20px 0; }
.modal-header h2 { font-size: 18px; }
.modal-header-actions { display: flex; align-items: center; gap: 8px; }
.modal-body { padding: 16px 20px 24px; display: flex; flex-direction: column; gap: 10px; }

/* Opt-in layout for modals that want a fixed header & footer with an internal
   scroll region in the middle. The modal-box caps at 90vh (base rule), its
   body fills remaining vertical space, and any descendant marked
   .modal-scroll-region grows to fill leftover space and scrolls internally.
   Intro copy above and action buttons below stay on screen as the list grows. */
.modal-box.modal-scroll-contained { overflow: hidden; }
.modal-box.modal-scroll-contained .modal-body { flex: 1 1 auto; min-height: 0; }
.modal-scroll-region { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* Mobile: page-like / form modals tagged .fullscreen-mobile fill the viewport
   instead of floating as a 480px card with a dimmed border. Confirmation,
   info, and picker modals stay as floating dialogs even on mobile.
   !important is needed on width/max-width because two overlays in this group
   (fund-confirm, catch-up) carry an inline style="max-width:400px" that
   would otherwise out-rank the class selector. */
@media (max-width: 600px) {
  .modal-overlay.fullscreen-mobile { padding: 0; align-items: stretch; justify-content: stretch; }
  .modal-overlay.fullscreen-mobile > .modal-box {
    width: 100vw !important; height: 100dvh;
    max-width: none !important; max-height: none;
    border-radius: 0; border: none;
  }
}

/* ── Danger button ── */
.btn-danger { background: #dc2626; border: 1px solid #dc2626; color: #fff; font-size: 14px; padding: 10px 16px; width: 100%; }
.btn-danger:hover:not(:disabled) { background: #b91c1c; }

/* ── Pocket modal action row ── */
.pocket-modal-actions { display: flex; gap: 8px; flex-direction: row-reverse; }
.pocket-modal-actions .btn-primary { flex: 1; }
/* Pause = gray (pocket is active, action is to pause it)
   Resume = red  (pocket is paused, action is to resume it) */
.btn-pause { flex: 0 0 35%; font-size: 14px; padding: 10px 12px; border-radius: 12px; cursor: pointer; font-weight: 600; transition: background 0.15s, border-color 0.15s, color 0.15s; text-align: center; }
.btn-pause.state-pause  { background: transparent; border: 1px solid var(--muted); color: var(--muted); }
.btn-pause.state-pause:hover  { border-color: var(--text); color: var(--text); }
.btn-pause.state-resume { background: transparent; border: 1px solid #f87171; color: #f87171; }
.btn-pause.state-resume:hover { background: rgba(248,113,113,0.12); }

/* ── Category combobox ── */
/* .combo-wrap handles outer container; cat-combo-wrap kept for JS selector compat */
.cat-combo-dropdown { position: fixed; background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; z-index: 600; box-shadow: 0 8px 24px rgba(0,0,0,0.5); max-height: 320px; overflow-y: auto; }
.cat-option { display: flex; align-items: center; gap: 10px; padding: 14px 14px; font-size: 14px; cursor: pointer; color: var(--text); border-bottom: 1px solid rgba(255,255,255,0.04); }
.cat-option:last-child { border-bottom: none; }
.cat-option:hover, .cat-option.focused { background: var(--surface); }
.cat-option-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-option-edit {
  background: none; border: none; cursor: pointer; padding: 6px;
  border-radius: 6px; color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.cat-option:hover .cat-option-edit { color: var(--text); }
.cat-option-edit:hover { background: var(--surface); color: var(--accent); }
.cat-option-add { color: var(--accent); font-weight: 600; }
.cat-option-add .cat-add-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent); color: #fff;
  font-weight: 700; font-size: 16px; line-height: 1; flex-shrink: 0;
}
.cat-option-empty { padding: 14px; color: var(--muted); font-size: 13px; }
/* The pocket-modal category input is read-only on purpose so mobile keyboards
   don't pop on tap — but it should still LOOK editable. */
/* Category trigger — sits inside .combo-wrap in place of an <input>. Styled to
 * mirror the input's dimensions/border so the toggle button on the right keeps
 * the same shape. <button> instead of <input> means no text caret, no
 * tap-to-select highlight, and no Android copy/paste popup. */
.cat-trigger {
  flex: 1; min-width: 0;
  display: flex; align-items: center;
  background: var(--surface2); color: var(--text);
  border: 1px solid var(--border); border-right: none;
  border-radius: 12px 0 0 12px;
  padding: 0 12px; height: 44px;
  font-size: 14px; font-family: inherit; text-align: left;
  cursor: pointer;
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.cat-trigger:focus { outline: none; }
.cat-trigger:focus-visible { border-color: var(--accent); }
.cat-trigger-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cat-trigger-text.placeholder { color: var(--muted); }
.cat-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; display: inline-block; }
.pocket-group-header .cat-dot { width: 12px; height: 12px; }
.field-label-action { float: right; font-size: 11px; color: var(--accent); cursor: pointer; font-weight: 400; }

/* ── Category pill on pocket card ── */
.pocket-category { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; border-radius: 99px; padding: 2px 8px; border: 1px solid; flex-shrink: 0; margin-bottom: 5px; }

/* ── Pocket group header (group-by view) ── */
.pocket-group-header { display: flex; align-items: center; gap: 8px; font-size: 17px; font-weight: 700; color: var(--text); margin: 20px 0 8px; cursor: pointer; user-select: none; }
.pocket-group-header:first-child { margin-top: 0; }
.pocket-group-header.muted { color: var(--muted); }
.pocket-group-label { min-width: 0; }
.pocket-group-subtotal {
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
  opacity: 0.82;
  white-space: nowrap;
  margin-left: auto;
  align-self: flex-end;
  padding-bottom: 1px;
}
.pocket-group-toggle { color: var(--muted); transition: transform 0.2s; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; }
.pocket-group-toggle.collapsed { transform: rotate(-90deg); }
.pocket-group-caret { width: 18px; height: 18px; display: block; }
.pocket-group-body.collapsed { display: none; }

/* ── Category edit popup (shared add/edit form) ── */
.cat-edit-modal-box { max-width: 420px; }
.modal-header-actions { display: flex; align-items: center; gap: 4px; }
#cat-edit-color-custom {
  position: absolute; opacity: 0; pointer-events: none;
  width: 1px; height: 1px;
}
.cat-color-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}
.cat-swatch {
  position: relative;
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer; padding: 0;
  -webkit-appearance: none; appearance: none;
  font-family: inherit;
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  background-clip: padding-box;
}
.cat-swatch:hover { border-color: var(--border); }
.cat-swatch.selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(99,102,241,0.35);
  transform: scale(1.08);
}
.cat-swatch-check {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
}
/* Color-wheel button: rainbow conic gradient inside the circle. When the
   user has picked a custom (non-preset) color the wheel hides and the
   button fills with their selection like any other swatch. */
.cat-swatch-custom { background: var(--surface2); }
.cat-swatch-wheel {
  display: block;
  width: 100%; height: 100%;
  border-radius: 50%;
  background: conic-gradient(from 0deg, #ef4444, #f59e0b, #eab308, #22c55e, #06b6d4, #3b82f6, #a855f7, #ec4899, #ef4444);
  pointer-events: none;
}
.cat-edit-modal-actions {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 10px; margin-top: 18px;
}
.cat-edit-modal-actions .btn-primary,
.cat-edit-modal-actions .btn-secondary { width: 100%; }

/* ── Category group reorder mode (flow-based) ── */
.pocket-group-header.reorderable {
  transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
  will-change: transform;
  -webkit-touch-callout: none;
}
#pockets-list.cat-reorder-active .pocket-group-body { display: none; }
#pockets-list.cat-reorder-active .pocket-group-header.reorderable.reorder-card {
  display: flex; align-items: center; gap: 10px;
  margin: 0 0 8px;
  padding: 14px 14px;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 12px;
  cursor: grab;
  /* `pan-y` lets the browser scroll the page naturally while the user is
     swiping. The 220ms press-and-hold gate decides drag vs scroll: movement
     past the slop within that window cancels the timer and the swipe stays
     a scroll; holding still for 220ms commits to a drag, after which the
     window-level pointermove (passive:false, armed at pointerdown) calls
     preventDefault on subsequent moves to take the gesture from the browser. */
  touch-action: pan-y;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  font-size: 16px;
}
#pockets-list.cat-reorder-active .pocket-group-header.reorderable.reorder-card.reorder-dragging {
  transition: none;
  position: relative;
  z-index: 10;
  cursor: grabbing;
  background: var(--surface);
  box-shadow: 0 12px 28px rgba(0,0,0,0.5);
  border-color: var(--accent);
}
#pockets-list.cat-reorder-active .pocket-group-header:not(.reorderable) {
  margin-top: 24px;
  opacity: 0.6;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  pointer-events: none;
}
.pocket-group-dot {
  width: 10px !important; height: 10px !important;
  border-radius: 50%; flex-shrink: 0;
}
.cat-reorder-grip {
  display: inline-flex; flex-direction: column; justify-content: center; gap: 3px;
  width: 14px; height: 14px; flex-shrink: 0;
  margin-right: 2px;
}
.cat-reorder-grip > span {
  display: block; height: 2px; width: 100%;
  background: var(--muted); border-radius: 2px;
}
body.cat-reorder-dragging-body { user-select: none; -webkit-user-select: none; }
body.cat-reorder-dragging-body * { -webkit-user-select: none; }

/* Reorder action bar: floating Cancel / Done above the bottom nav.
   Modelled on #tx-select-bar so it lines up with the multi-select pattern
   the rest of the app already uses. */
.cat-reorder-bar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--nav-h) + 12px);
  transform: translateX(-50%);
  z-index: 1000;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.45);
  max-width: calc(100% - 32px);
}
.cat-reorder-bar .btn-primary { width: auto; padding: 8px 18px; font-size: 14px; }
.cat-reorder-bar .btn-ghost { padding: 8px 12px; font-size: 14px; }
.cat-reorder-bar-title {
  font-size: 13px; color: var(--muted);
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
/* Pre-launch lockout: muted/locked variant of buttons we want regular users
   to see (and tap to get the explainer popup) while devs with the toggle
   on get the real button. Mirrors the .dev-only pattern. */
body:not(.dev-tools-on) .pre-launch-unlocked-only { display: none !important; }
body.dev-tools-on .pre-launch-locked-only { display: none !important; }

/* ── Tx pocket picker ── */
.pocket-select-btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--surface2); border: 1px solid var(--border); border-radius: 12px;
  padding: 12px 14px; color: var(--text); font-size: 15px; font-family: inherit; cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.pocket-select-btn:hover { border-color: var(--accent); }
.pocket-select-label { flex: 1; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pocket-select-caret { color: var(--muted); flex-shrink: 0; }

.tx-pocket-picker-list { margin: 0 -20px -24px; }
.tx-pocket-option { padding: 10px 14px; font-size: 14px; cursor: pointer; color: var(--text); }
.tx-pocket-option:hover, .tx-pocket-option.focused { background: var(--surface2); }
.txp-divider { height: 1px; background: var(--border); }
.txp-card { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; }
.txp-card-left { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.txp-card-name { font-weight: 500; font-size: 15px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.txp-card-due { font-size: 11px; color: var(--muted); }
.txp-card-amounts { font-size: 15px; font-weight: 700; color: var(--text); white-space: nowrap; flex-shrink: 0; }
.txp-card-sep, .txp-card-goal { color: var(--muted); font-weight: 500; }
.txp-gtg .txp-card-name { font-weight: 700; }

/* ── Scrollable fixed dropdowns (no visible scrollbar, thin on hover) ── */
.cat-combo-dropdown { max-height: 260px; overflow-y: auto; }

/* ── Custom select (cs-*) — replaces native <select> everywhere ── */
.cs-wrap { position: relative; }
.cs-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 10px 14px; background: var(--surface2); border: 1px solid var(--border);
  border-radius: 12px; color: var(--text); font-size: 14px; cursor: pointer; text-align: left;
  transition: border-color 0.2s; font-family: inherit; font-weight: 400;
}
.cs-btn:hover { border-color: var(--accent); }
.cs-btn svg { color: var(--muted); flex-shrink: 0; transition: transform 0.2s; }
.cs-btn.open svg { transform: rotate(180deg); }
.cs-menu {
  display: none; position: fixed; background: var(--surface2); border: 1px solid var(--border);
  border-radius: 12px; z-index: 600; box-shadow: 0 8px 24px rgba(0,0,0,0.5);
  max-height: 260px; overflow-y: auto;
}
.cs-opt { padding: 10px 14px; font-size: 14px; cursor: pointer; color: var(--text); }
.cs-opt:first-child { border-radius: 12px 12px 0 0; }
.cs-opt:last-child  { border-radius: 0 0 12px 12px; }
.cs-opt:only-child  { border-radius: 12px; }
.cs-opt:hover, .cs-opt.focused { background: var(--surface); }
.cs-opt.active { color: var(--accent); font-weight: 600; }

/* ── Freq trigger button ── */
.freq-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; padding: 12px 14px; background: var(--surface2); border: 1px solid var(--border);
  border-radius: 12px; color: var(--text); font-size: 15px; cursor: pointer;
  text-align: left; font-family: inherit; font-weight: 400; transition: border-color 0.2s;
}
.freq-trigger:hover { border-color: var(--accent); }
.freq-trigger span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.freq-trigger svg { color: var(--muted); flex-shrink: 0; }

.freq-type-select {
  width: 100%;
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  background: var(--surface2);
  border: 1px solid var(--border);
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.15s;
  -webkit-appearance: menulist;
  appearance: menulist;
}
.freq-type-select:hover:not(:disabled)  { border-color: var(--accent); }
.freq-type-select:focus  { outline: none; border-color: var(--accent); }
/* Match the locked date field: dimmed + non-interactive when Spending Fund
 * forces per_paycheck. pointer-events: none kills the hover-on-disabled
 * cursor that browsers still show by default. */
.freq-type-select:disabled { opacity: 0.55; cursor: default; pointer-events: none; }

/* Stepper */
.freq-stepper-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; }
.freq-stepper-label { color: var(--muted); font-size: 14px; }
.freq-stepper-controls { display: flex; align-items: center; gap: 6px; background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; padding: 4px 8px; }
.freq-step-btn { background: none; border: none; color: var(--text); font-size: 20px; padding: 0 6px; cursor: pointer; border-radius: 6px; line-height: 1.2; font-weight: 300; }
.freq-step-btn:hover:not(:disabled) { background: var(--border); }
.freq-step-btn:disabled { opacity: 0.3; cursor: default; transform: none; }
.freq-every-val { font-size: 16px; font-weight: 700; min-width: 24px; text-align: center; }
.freq-stepper-unit { color: var(--muted); font-size: 14px; }

/* Section sub-labels ("on", "on the") — lowercase intentional, continuation of the stepper sentence */
.freq-section-label { font-size: 12px; color: var(--muted); font-weight: 500; padding-top: 10px; margin-bottom: 6px; }
.freq-day-section-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; padding-top: 4px; }

/* Weekday grid — padded 10% each side → ~20% smaller circles */
.freq-weekday-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; padding: 0 10%; }
.freq-weekday-btn {
  aspect-ratio: 1; border-radius: 50%; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface2); border: 1px solid var(--border); color: var(--muted);
  font-size: 11px; font-weight: 700; cursor: pointer; transition: all 0.15s;
  line-height: 1; text-align: center;
}
.freq-weekday-btn:hover { border-color: var(--accent); color: var(--accent); }
.freq-weekday-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Day-of-month grid */
.freq-day-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.freq-day-btn {
  padding: 6px 4px; border-radius: 8px;
  background: var(--surface2); border: 1px solid var(--border); color: var(--muted);
  font-size: 11px; font-weight: 600; cursor: pointer; transition: all 0.15s;
}
.freq-day-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.freq-day-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.freq-day-hint { grid-column: span 4; font-size: 10px; opacity: 0.5; cursor: default !important; border-style: dashed; text-align: center; }

/* Annual compact month + day selectors */
.freq-annual-compact { display: flex; gap: 12px; align-items: flex-start; }
.freq-annual-date { display: inline-block; font-size: 13px; font-weight: 600; color: var(--text); background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 7px 14px; }

.pocket-paycheck-preview {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface2);
  padding: 10px 14px;
  min-height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pocket-paycheck-preview-value {
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  text-align: center;
}
.pocket-paycheck-preview-value.muted {
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
}
.pocket-paycheck-preview-value.behind { color: var(--red); }

/* ── Pocket modal inline frequency picker ── */
/* One slot for everything: editable bubble (Daily/Weekly/Monthly/Yearly) AND
 * read-only summary (Once / Per Paycheck) share this look. Variable parts
 * inside the bubble use .freq-var (accent color) so the user can scan
 * which words will change if they edit. */
.pm-freq-settings .freq-settings-bubble,
.pc-freq-settings .freq-settings-bubble {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--surface2); border: 1px solid var(--border); border-radius: 12px;
  padding: 10px 14px; flex-wrap: wrap;
  font-size: 14px; color: var(--text); text-align: center;
  min-height: 42px;
}
/* Variable text inside the bubble — accent color + bold so it stands out
 * from the static "Every", "on", connector words (which stay default
 * weight + default text color). Global so the same coloring works inside
 * the funding-schedule summary box at the bottom of the pay cycle modal,
 * not just the inline bubble. */
.freq-var { color: var(--accent); font-weight: 700; }
.freq-var-muted { color: var(--muted); font-style: italic; }
/* Tappable number — looks like a button until tapped, then swaps for
 * an inline numeric input. */
.pm-freq-settings .freq-num-btn,
.pc-freq-settings .freq-num-btn {
  background: rgba(124,111,247,0.1); border: 1px solid rgba(124,111,247,0.3);
  color: var(--accent); font-weight: 700; font-size: 14px;
  padding: 4px 10px; min-width: 36px; border-radius: 8px; cursor: pointer;
  font-family: inherit; transition: background 0.15s;
}
.pm-freq-settings .freq-num-btn:hover,
.pc-freq-settings .freq-num-btn:hover { background: rgba(124,111,247,0.2); }
.pm-freq-settings .freq-num-input,
.pc-freq-settings .freq-num-input {
  background: var(--surface); border: 1px solid var(--accent);
  color: var(--accent); font-weight: 700; font-size: 14px;
  padding: 4px 8px; min-width: 36px; max-width: 60px; border-radius: 8px;
  text-align: center; font-family: inherit; outline: none;
  -moz-appearance: textfield;
  appearance: textfield;
}
.pm-freq-settings .freq-num-input::-webkit-outer-spin-button,
.pm-freq-settings .freq-num-input::-webkit-inner-spin-button,
.pc-freq-settings .freq-num-input::-webkit-outer-spin-button,
.pc-freq-settings .freq-num-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.pm-freq-settings .freq-day-chip,
.pc-freq-settings .freq-day-chip {
  background: rgba(124,111,247,0.1); border: 1px solid rgba(124,111,247,0.3);
  color: var(--accent); font-weight: 700; font-size: 13px;
  padding: 4px 10px; border-radius: 99px; cursor: pointer;
  font-family: inherit;
}
.pm-freq-settings .freq-day-chip:hover,
.pc-freq-settings .freq-day-chip:hover { background: rgba(124,111,247,0.2); }

/* Day-picker popup (anchored beneath the chip, fixed-position so it
 * floats above the rest of the modal layout instead of pushing content
 * down). Replaces the old inline-expand row. */
.freq-pop {
  position: fixed; z-index: 9999;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; padding: 10px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
}
.freq-pop-weekday-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; min-width: 224px; }
.freq-pop-day-grid     { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; min-width: 252px; }
.freq-pop .freq-weekday-btn {
  aspect-ratio: 1; border-radius: 50%; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface2); border: 1px solid var(--border); color: var(--muted);
  font-size: 12px; font-weight: 700; cursor: pointer; transition: all 0.15s;
}
.freq-pop .freq-weekday-btn:hover { border-color: var(--accent); color: var(--accent); }
.freq-pop .freq-weekday-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.freq-pop .freq-day-btn {
  aspect-ratio: 1; border-radius: 6px; padding: 0;
  background: var(--surface2); border: 1px solid var(--border); color: var(--muted);
  font-size: 12px; font-weight: 600; cursor: pointer; transition: all 0.15s;
}
.freq-pop .freq-day-btn:hover:not(.freq-day-hint) { border-color: var(--accent); color: var(--accent); }
.freq-pop .freq-day-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.freq-pop .freq-day-hint {
  grid-column: span 7; aspect-ratio: auto; padding: 4px; font-size: 10px;
  color: var(--muted); cursor: default; opacity: 0.7;
}

/* Locked date field (Spending Fund pins it to next pay date) */
.dp-field-wrap.is-locked { opacity: 0.55; pointer-events: none; }

/* Money input — wraps a number input with a $ glyph on the left.
 * The $ is a non-interactive ::before so the input keeps its native
 * keyboard + validation; the input's left padding makes room for it. */
.money-input-wrap { position: relative; display: block; }
.money-input-wrap::before {
  content: '$'; position: absolute; left: 14px; top: 50%;
  transform: translateY(-50%); color: var(--muted);
  font-size: 15px; pointer-events: none; line-height: 1;
}
.money-input-wrap input { padding-left: 26px; }

/* Spending Fund badge — neutral text + matching outline. Lives in the
 * same name-row slot as Paused/Behind; only one shows at a time. */
.badge-spending-fund { color: var(--text); background: var(--surface2); border-color: var(--text); }

/* ── Pay cycle rows ── */
.paycycle-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; border: 1px solid var(--border); border-radius: 8px; 
  background: var(--surface2); cursor: pointer; gap: 10px; margin-bottom: 8px;
  transition: border-color 0.15s, background-color 0.15s;
}
.paycycle-row:hover { border-color: var(--accent); background: var(--surface); }
.paycycle-row:last-child { margin-bottom: 0; }
/* GTG paycheck pill — red wash when totalNeeded exceeds amount_estimate.
   Soft red fill (matches the soft purple of the default state) plus
   red border + red amount so the over-budget signal is unambiguous. */
.gtg-paycheck-btn.over-budget {
  background: rgba(248, 113, 113, 0.10);
  border-color: rgba(248, 113, 113, 0.45);
}
.gtg-paycheck-btn.over-budget strong { color: var(--red); }
.gtg-paycheck-btn.over-budget:hover {
  background: rgba(248, 113, 113, 0.18);
  border-color: var(--red);
}
.paycycle-info { flex: 1; min-width: 0; }
.paycycle-name { font-size: 15px; font-weight: 500; transition: color 0.15s; }
.paycycle-sub { font-size: 12px; color: var(--muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.paycycle-row svg { color: var(--muted); flex-shrink: 0; }
.paycycle-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.paycycle-fund-btn { padding: 7px 10px; font-size: 12px; white-space: nowrap; }

/* ── Card label row with action button ── */
.card-label-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.card-label-row .card-label { margin-bottom: 0; }

/* ── Account tab section labels ── */
.acct-section-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--muted); margin: 18px 0 8px; padding: 0 2px;
}
.acct-section-label:first-of-type { margin-top: 4px; }

/* ── GTG paycheck pill — lives inside .gtg-hero, mirrors the marketing
   site's preview pill so brand and product feel like one family. Pill
   shape (border-radius:999px), soft-accent fill, no full-width stretch
   since it's centered under the GTG amount, not part of an action row. */
.gtg-paycheck-btn {
  display: inline-flex; align-items: baseline; justify-content: center; gap: 4px;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--text);
  background: var(--surface2);
  border: 1px solid rgba(124, 111, 247, 0.30);
  border-radius: 999px;
  padding: 10px 18px;
  cursor: pointer; line-height: 1.2;
  white-space: nowrap;
  transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.gtg-paycheck-btn:hover {
  border-color: var(--accent);
  background: var(--surface);
}
.gtg-paycheck-btn[disabled] { cursor: default; }
.gtg-paycheck-btn strong { color: var(--text); font-weight: 700; }
.gtg-paycheck-label { font-size: 12px; font-weight: 500; color: var(--muted); }
.gtg-paycheck-btn.muted { color: var(--muted); background: transparent; border-color: var(--border); }

/* ── Two-column field row (e.g. Stashed / Goal) ── */
.field-row-2col { display: flex; gap: 12px; }
.field-row-2col > .field-group { flex: 1; min-width: 0; }

/* ── Per-paycheck meta badge ── */
.meta-per-paycheck { color: var(--accent); font-weight: 700; margin-left: auto; white-space: nowrap; flex-shrink: 0; }
.meta-per-paycheck.behind { color: var(--red); }
.meta-per-paycheck.next-cycle { color: var(--muted); font-style: italic; }

/* ── Behind badge + card ── */
.badge-behind { background: rgba(248,113,113,0.15); color: var(--red); border-color: rgba(248,113,113,0.4); }
.pocket-card.behind { border-color: rgba(248,113,113,0.3); }
@media (hover: hover) { .pocket-card.behind:hover { border-color: var(--red); } }

/* ── Custom date picker field — text input IS the display ── */
/* Date field — input on the left (typeable), calendar-icon button on the
 * right (opens the picker). Mirrors .combo-wrap + .combo-toggle-btn
 * exactly so the date and combobox patterns read as siblings. The
 * !important on the input border-radius is required to win over the
 * generic input[type="text"] rule (matches the combobox approach). */
.dp-field-wrap { position: relative; display: flex; align-items: stretch; }
.dp-field-wrap .dp-input {
  flex: 1; min-width: 0;
  border-radius: 12px 0 0 12px !important;
  border-right: none !important;
  cursor: pointer;
}
.dp-field-wrap .dp-input:focus { border-color: var(--accent); box-shadow: none; }
.dp-field-wrap:focus-within .dp-input { border-color: var(--accent); }
.dp-field-wrap:focus-within .dp-cal-btn { border-color: var(--accent); }
.dp-cal-btn {
  background: var(--surface2); border: 1px solid var(--border);
  border-left: none;
  border-radius: 0 12px 12px 0; padding: 0 13px;
  cursor: pointer; display: flex; align-items: center;
  color: var(--muted); transition: color 0.15s, border-color 0.15s;
  flex-shrink: 0;
}
.dp-field-wrap:hover .dp-input,
.dp-field-wrap:hover .dp-cal-btn { border-color: var(--accent); }
.dp-field-wrap:hover .dp-cal-btn { color: var(--accent); }

/* ── Custom date picker panel — scaled up for readability ── */
#dp-panel {
  position: fixed; z-index: 3000;
  background: #2d2d3e; border: 1px solid rgba(255,255,255,0.12);
  border-radius: 16px; padding: 14px; width: 340px;
  box-shadow: 0 16px 48px rgba(0,0,0,0.65);
  overflow: hidden;
}
.dp-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px; gap: 4px;
}
.dp-nav {
  width: 42px; height: 42px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.12);
  border-radius: 10px; color: var(--text); font-size: 18px;
  cursor: pointer; transition: background 0.15s, border-color 0.15s, color 0.15s;
  flex-shrink: 0;
}
.dp-nav:hover { background: rgba(255,255,255,0.14); border-color: var(--accent); color: var(--accent); }
.dp-header .dp-nav:first-child { margin-right: 2px; }
.dp-header .dp-nav:last-child  { margin-left:  2px; }
.dp-title-group { display: flex; gap: 6px; flex: 1; justify-content: center; align-items: center; min-width: 0; }
.dp-title-btn {
  background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.12);
  border-radius: 10px; color: #dde; font-weight: 700; font-size: 15px;
  padding: 8px 14px; cursor: pointer; font-family: inherit; line-height: 1;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.dp-title-btn:hover { background: rgba(255,255,255,0.14); border-color: var(--accent); color: var(--accent); }
.dp-list {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  max-height: 260px; overflow-y: auto; padding: 2px;
}
.dp-list-years { grid-template-columns: repeat(4, 1fr); }
.dp-list-item {
  height: 40px; display: flex; align-items: center; justify-content: center;
  border-radius: 9px; font-size: 14px; font-weight: 500; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: #dde;
  font-family: inherit; padding: 0;
  transition: background 0.1s, border-color 0.1s;
}
.dp-list-item:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.15); }
.dp-list-item.selected { background: var(--accent); border-color: var(--accent); color: #fff; }
.dp-weekdays {
  display: grid; grid-template-columns: repeat(7, 1fr);
  margin-bottom: 3px;
}
.dp-weekdays span {
  text-align: center; font-size: 11px; color: rgba(200,200,230,0.6);
  font-weight: 700; padding: 4px 0;
}
.dp-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; width: 100%; }
.dp-day {
  height: 40px; width: 100%;
  display: flex; align-items: center; justify-content: center;
  border-radius: 9px; font-size: 14px; font-weight: 500; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: #dde;
  transition: background 0.1s, border-color 0.1s; padding: 0;
}
.dp-day:hover { background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.15); }
.dp-day.focused { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-glow); }
.dp-day.other-month { color: rgba(200,200,230,0.25); }
.dp-day.today { border-color: var(--accent); color: var(--accent); }
.dp-day.selected { background: var(--accent); border-color: var(--accent); color: #fff; }
.dp-day.today.selected { background: var(--accent); border-color: var(--accent); color: #fff; }
/* Footer sits below the calendar grid; Clear empties the currently-open
   field from inside the picker so any date field in the app can be cleared. */
.dp-footer { display: flex; justify-content: flex-end; padding-top: 10px; margin-top: 6px; border-top: 1px solid rgba(255,255,255,0.08); }
.dp-clear-btn {
  background: transparent;
  border: none;
  padding: 6px 8px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  border-radius: 6px;
  transition: color 0.15s, background 0.15s;
}
.dp-clear-btn:hover { color: var(--red); background: rgba(248,113,113,0.08); }


/* ── Unified combobox: text input + caret toggle button ── */
.combo-wrap { position: relative; display: flex; align-items: stretch; }
.combo-wrap input {
  flex: 1; min-width: 0;
  border-radius: 12px 0 0 12px !important;
  border-right: none !important;
}
.combo-wrap input:focus { border-color: var(--accent); box-shadow: none; }
.combo-wrap:focus-within input { border-color: var(--accent); }
.combo-toggle-btn {
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: 0 12px 12px 0; padding: 0 13px;
  cursor: pointer; display: flex; align-items: center;
  color: var(--muted); transition: color 0.15s, border-color 0.15s;
  flex-shrink: 0;
}
.combo-toggle-btn:hover { border-color: var(--accent); color: var(--accent); }
.combo-wrap:focus-within .combo-toggle-btn { border-color: var(--accent); }
.combo-caret { transition: transform 0.2s; }
.combo-toggle-btn.open .combo-caret { transform: rotate(180deg); }

/* Tx type filter pills */
.tx-type-pills { display: flex; gap: 6px; }
.tx-type-pill, .tx-acct-type-pill {
  flex: 1; padding: 6px 8px; border-radius: 20px; font-size: 12px; font-weight: 600;
  background: var(--surface2); border: 1px solid var(--border); color: var(--muted);
  cursor: pointer; transition: all 0.15s; text-align: center;
}
.tx-type-pill:hover, .tx-acct-type-pill:hover { border-color: var(--accent); color: var(--accent); }
.tx-type-pill.active, .tx-acct-type-pill.active { background: var(--accent); border-color: var(--accent); color: #fff; }

/* ── Spending Hero (Transactions tab) ──────────────────────────────────────
   Last 30 days of spending as a donut, one slice per pocket category, plus
   a "From GTG" slice for unlinked transactions (transfers are excluded from
   that slice). No legend, no labels — hovering a slice slides it outward,
   dims the others, and the center shows category + amount + %. Clicking
   commits the selection and filters the transactions list below. */
.gtg-spend-hero-wrap {
  margin: 0 0 20px;
  padding: 24px 20px 26px;
  border-radius: var(--radius);
  background:
    radial-gradient(circle at 50% 0%, rgba(124, 111, 247, 0.30) 0%, rgba(124, 111, 247, 0.08) 55%, transparent 82%),
    linear-gradient(160deg, #201d44 0%, #1a1a28 100%);
  border: 1px solid #3d3070;
  box-shadow: 0 10px 32px -20px rgba(0, 0, 0, 0.55);
}
.gtg-spend-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}
.gtg-spend-heading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
}
.gtg-spend-title {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.6px;
  line-height: 1.15;
  color: #ffffff;
}
.gtg-spend-subtitle {
  font-size: 12px;
  color: var(--muted);
  letter-spacing: 0.02em;
  line-height: 1.4;
}
.gtg-spend-summary {
  font-size: 13px;
  color: var(--text);
  letter-spacing: 0.01em;
  line-height: 1.4;
  margin-top: 2px;
  font-weight: 500;
}
.gtg-spend-pie-stage {
  position: relative;
  width: 260px;
  height: 260px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.gtg-spend-pie-svg { display: block; overflow: visible; }
.gtg-pie-slice {
  cursor: pointer;
  transition: opacity 0.2s, filter 0.2s;
  will-change: opacity, filter;
}
/* Hover / selected = subtle glow in the slice's own color. Other slices dim
   so focus is unmistakable without the effect feeling heavy-handed. */
.gtg-pie-slice:hover,
.gtg-pie-slice.is-selected {
  filter: brightness(1.08) drop-shadow(0 0 3px var(--slice-glow, rgba(255,255,255,0.35)));
}
/* Dim only when a slice is actually the :hover target, not whenever the
   mouse is anywhere over the stage (the donut hole + corners of the SVG
   were triggering a full-pie dim with nothing highlighted). */
.gtg-spend-pie-stage:has(.gtg-pie-slice:hover) .gtg-pie-slice:not(:hover),
.gtg-spend-pie-stage.has-focus .gtg-pie-slice:not(.is-selected):not(:hover) {
  opacity: 0.28;
}
.gtg-spend-pie-center {
  position: absolute;
  pointer-events: none;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  max-width: 150px;
  transition: color 0.15s;
}
.gtg-spend-pie-center-label {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1.2;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gtg-spend-pie-center-amount {
  font-size: 26px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
}
.gtg-spend-pie-center-sub {
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}


/* ── Welcome flow ──
   Three full-screen fade-in screens shown right after signup. Sits above
   every other page (z-index 9000) and dismisses when the flow completes.
   Animations use CSS keyframes with staggered delays so each line lands
   on its own beat — the user can also tap anywhere to skip ahead. */
.welcome-overlay {
  position: fixed; inset: 0; z-index: 9000;
  background:
    radial-gradient(circle at 50% 0%, rgba(124, 111, 247, 0.18) 0%, transparent 60%),
    linear-gradient(160deg, #1a1832 0%, var(--bg) 100%);
  display: flex; flex-direction: column; align-items: center;
  padding: 8vh 20px 24px; overflow-y: auto;
  cursor: pointer;
}
/* Close button — sits in the upper-right of the overlay regardless of
 * which screen is rendered. Tap-to-advance is wired on the overlay
 * itself, so the close button needs to stop propagation to avoid
 * accidentally advancing instead of dismissing. */
.welcome-close-btn {
  position: fixed; top: 14px; right: 14px;
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.15);
  color: var(--muted); font-size: 18px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; padding: 0; line-height: 1;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
  z-index: 9001;
}
.welcome-close-btn:hover { color: var(--text); border-color: var(--accent); background: rgba(255,255,255,0.1); }
.welcome-screen {
  width: 100%; max-width: 520px;
  display: flex; flex-direction: column;
  flex: 1; min-height: 100%;
}
/* Top zone: brand wordmark + spacer pushing content down a bit */
.welcome-screen-top {
  text-align: center; margin-bottom: 32px;
  font-size: 14px; color: var(--muted); letter-spacing: 0.5px;
}
.welcome-content {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 32px; text-align: center;
}
.welcome-content > * {
  /* Each child fades in as a fade-stage; the screen renderer assigns delays
   * + per-element durations from data-duration on the element. */
  opacity: 0;
  animation: welcomeFade 1000ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}
/* Screen 1: pin the quote to the viewport's vertical centerline using
 * position:fixed (relative to the viewport, since the welcome-overlay is
 * itself fixed). Auto-margin centering inside welcome-content drifted off
 * 50dvh because of the asymmetric padding above (8vh) vs below (24px).
 * Fixed positioning ignores the surrounding flow so 50% always means 50%.
 *
 * The blockquote stays opaque so each .qpiece inside can manage its own
 * opacity timeline. Per-section accent bars on each <p> child fade in/out
 * with their respective sections (see .welcome-quote-main.bar-on etc).  */
.welcome-content > .welcome-quote {
  opacity: 1;
  animation: none;
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: calc(100% - 40px);
  max-width: 460px;
  margin: 0;
}
/* Quote pieces "type in" left-to-right via an animated mask. We can't use
 * clip-path here because the parenthetical pieces are plain inline text
 * (so they flow as one wrapping paragraph rather than stacking per chunk
 * — clip-path on inline is unreliable across browsers).
 *
 * The trick: a CSS Houdini @property declaration lets us animate a
 * percentage variable smoothly, which we plug into a mask-image gradient.
 * The gradient is opaque up to --reveal-pos and transparent after, so as
 * the variable sweeps 0% → 100% the text reveals from left to right.
 *
 * Fallback: browsers without @property support (very old Safari) treat
 * --reveal-pos as a regular custom property — it can't animate, but its
 * default of 100% leaves the mask fully opaque, and the opacity animation
 * still gives a clean fade-in. */
@property --reveal-pos {
  syntax: '<percentage>';
  initial-value: 100%;
  inherits: false;
}
.qpiece {
  display: inline;
  --reveal-pos: 100%;
  opacity: 0;
  -webkit-mask-image: linear-gradient(90deg, #000 var(--reveal-pos), transparent var(--reveal-pos));
          mask-image: linear-gradient(90deg, #000 var(--reveal-pos), transparent var(--reveal-pos));
  animation: welcomeTypeIn 1000ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}
.qpiece-block {
  display: block;
  --reveal-pos: 100%;
  opacity: 0;
  -webkit-mask-image: linear-gradient(90deg, #000 var(--reveal-pos), transparent var(--reveal-pos));
          mask-image: linear-gradient(90deg, #000 var(--reveal-pos), transparent var(--reveal-pos));
  animation: welcomeTypeIn 1000ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}
@keyframes welcomeTypeIn {
  from { opacity: 0; --reveal-pos: 0%; }
  to   { opacity: 1; --reveal-pos: 100%; }
}
/* Brand block on screen 1 — logo above, wordmark below with "by Hoopy"
 * in brand purple, then the tagline tucked directly under. Tagline animates
 * separately (own opacity:0 + animation) so the brand-name lands first
 * with the tagline arriving on its own beat shortly after. */
.welcome-brand {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
}
.welcome-brand img { width: 72px; height: 72px; margin-bottom: 4px; }
.welcome-brand-name {
  font-size: 28px; font-weight: 800; letter-spacing: -0.5px; color: var(--text);
  line-height: 1.1;
}
.welcome-brand-name .brand-accent { color: var(--accent); font-weight: 800; }
.welcome-brand-tagline {
  /* Sub-feel comes from a smaller size + lighter weight than the wordmark
   * above it — full text color, no italic, just a clean tagline. */
  font-size: 16px; color: var(--text);
  font-weight: 500;
  letter-spacing: 0.2px;
  /* Animates independently from its parent's fade-in so it can land on its
   * own stopwatch beat per the welcome timing chart. */
  opacity: 0;
  animation: welcomeFade 1000ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}
/* Body copy "by Hoopy" highlight — used inside paragraphs on screens 2/3
 * so the brand reads as styled wherever it's mentioned. */
.brand-accent { color: var(--accent); font-weight: 700; }
@keyframes welcomeFade {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.welcome-line {
  font-size: 18px; line-height: 1.45; color: var(--text);
  max-width: 480px;
}
.welcome-line-primary {
  font-size: 22px; font-weight: 700; line-height: 1.35;
}
/* Welcome-line paragraphs opt out of the welcome-content > * opacity fade
 * so the .qpiece spans inside can drive the type-in timing themselves.
 * Otherwise the paragraph's own fade stacks (multiplicatively) with each
 * piece's mask animation and the result reads as half-faded mush. */
.welcome-content > .welcome-line { opacity: 1; animation: none; }

/* Strikethrough animation. Used on page 2 to line out "towel" before
 * "money" gets injected. text-decoration-color is animatable, so the
 * line fades in over 500ms via the .struck class added by JS at the
 * right beat. */
.strikable {
  text-decoration: line-through;
  text-decoration-color: transparent;
  text-decoration-thickness: 2px;
  transition: text-decoration-color 500ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.strikable.struck { text-decoration-color: currentColor; }

/* Word injection — used on page 2 to slide "money" into place between
 * struck-out "towel" and "is!". Starts at display:none so it occupies no
 * layout space, and "is!" sits flush against "towel". When .injected is
 * added, display becomes inline (instant layout reflow — "is!" jumps
 * right) and opacity transitions from 0 to 1 over 600ms. */
.word-injection {
  display: none;
  opacity: 0;
  transition: opacity 600ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.word-injection.injected {
  display: inline;
  opacity: 1;
}
/* Brand-purple highlight for words like "hoopy", "simple", "Good-to-Go" */
.welcome-accent { color: var(--accent); font-weight: 700; }
/* Hitchhiker's quote block. Hierarchy is established with font-size and
 * style (italic / not, weight) rather than dimmed colors — full-strength
 * text reads as content the user is meant to engage with, not an aside
 * to skim past. */
.welcome-quote {
  font-size: 17px; line-height: 1.55; color: var(--text);
  font-style: italic; max-width: 460px;
  text-align: left;
  /* border-left + padding-left moved onto each <p> child below so each
   * section can have its own accent bar that fades in/out with the section
   * it belongs to. */
}
/* Per-section accent bar. The bar fades in via the .bar-on class (added
 * by JS at the section's scheduled time) and out when the next section
 * begins, so only the section currently revealing has a visible bar. */
.welcome-quote-main,
.welcome-quote-aside,
.welcome-quote-cite {
  border-left: 2px solid transparent;
  padding-left: 14px;
  margin: 0;
  transition: border-left-color 600ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.welcome-quote-main.bar-on,
.welcome-quote-aside.bar-on,
.welcome-quote-cite.bar-on {
  border-left-color: var(--accent);
}
/* Each section "owns" the gap that follows it (via padding-bottom rather
 * than the next section's padding-top). When a section's bar lights up,
 * it extends slightly past the section's text, hinting that more content
 * is coming. The final section (cite/Douglas) has no trailing padding so
 * its bar lands flush — a visual "we're done" signal. Visible text
 * positions are identical to the previous padding-top arrangement; only
 * the bar coverage shifts. */
.welcome-quote-main  { font-size: 18px; font-weight: 500; padding-bottom: 10px; }
.welcome-quote-aside { font-size: 15px; font-weight: 400; padding-bottom: 14px; }
.welcome-quote-cite  { font-size: 14px; font-style: normal; font-weight: 500; }
/* GTG demo on screen 3 — wraps the live hero markup. Constrained width so
 * it doesn't stretch on desktop, and its own pointer-events:none so taps
 * fall through to the overlay's tap-to-advance handler. */
.welcome-gtg-demo {
  width: 100%; max-width: 420px;
  pointer-events: none;
}
.welcome-gtg-demo .gtg-info-btn { display: none; }
/* Bottom: button row anchored to the bottom of the screen */
.welcome-actions {
  display: flex; justify-content: center; padding-top: 24px;
}
.welcome-btn {
  background: var(--accent); color: #fff; border: 0;
  border-radius: 12px; padding: 12px 28px; font-size: 15px; font-weight: 700;
  cursor: pointer; opacity: 0;
  animation: welcomeFade 700ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
  transition: background 0.15s, transform 0.1s;
}
.welcome-btn:hover { background: var(--accent-dim); }
.welcome-btn:active { transform: scale(0.97); }


/* ── Responsive ── */
@media (max-width: 720px) {
  /* Match the site's .top-nav narrow-viewport padding so the header
     proportions stay aligned across site → app on mobile. */
  #app-header { padding: 12px 20px; min-height: 64px; }
}
@media (max-width: 539px) {
  .header-gtg-label { display: none; }
}

/* Dev tools visibility gate. Dev-only UI is rendered into the DOM at init
   for any dev account, then the toggle in Profile flips body.dev-tools-on
   to show it. Pure CSS so the toggle is an instant UI flip with no
   re-renders. Non-dev users never get the body class, so .dev-only stays
   hidden for them too. */
body:not(.dev-tools-on) .dev-only { display: none !important; }
