/* Colors, type and component styling follow the Tally style guide
   (docs/tally/tally.css). Token names are the app's own; values are Tally's. */
:root {
  /* Neutrals */
  --color-bg: #f5f2eb;            /* Paper: page background */
  --color-surface: #fbfaf6;       /* Surface: cards, panels */
  --color-surface-2: #fffefb;     /* Field background */
  --color-border: #e2dccf;        /* Rule: borders, dividers */
  --color-border-soft: #ece7dc;   /* Soft rule, hover, segmented track */
  --color-border-strong: #d6cfbf; /* Field border */
  --color-row-hover: #f3efe6;
  --color-text: #1e1c18;          /* Ink */
  --color-text-muted: #5b564c;    /* Ink 2 */
  --color-text-faint: #766f62;    /* Ink 3: labels, captions */
  --color-text-disabled: #9a9385; /* Ink 4 */
  --color-disabled-bg: #efebe2;

  /* Ledger green: income, primary action */
  --color-accent: oklch(0.48 0.09 155);
  --color-accent-hover: oklch(0.42 0.09 155);
  --color-accent-soft: oklch(0.94 0.03 155);
  --color-accent-text: oklch(0.45 0.09 155);
  --color-accent-soft-text: oklch(0.38 0.08 155);

  /* Clay: over budget, errors, delete */
  --color-danger: oklch(0.55 0.11 45);
  --color-danger-hover: oklch(0.49 0.11 45);
  --color-danger-soft: oklch(0.94 0.03 45);
  --color-danger-text: oklch(0.48 0.11 45);
  --color-danger-soft-text: oklch(0.45 0.11 45);

  --color-success: oklch(0.42 0.09 155);
  --color-success-soft: oklch(0.94 0.03 155);

  --focus-ring: 0 0 0 3px oklch(0.52 0.09 155 / 0.18);

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.5rem;

  --radius-xs: 5px;
  --radius-sm: 8px;
  --radius-md: 10px;
  --radius-lg: 10px;

  --font-sans: "Manrope", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-display: "Newsreader", Georgia, serif;
  --font-mono: "IBM Plex Mono", ui-monospace, monospace;
  --field-height: 42px;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.125rem;
  --font-size-xl: 1.5rem;

  --transition-fast: 120ms ease;
  --content-max-width: 1600px;
  /* Deliberately narrower than --content-max-width: the dashboard/report
     grids want the full width, but a handful of nav links and a short
     footer look stretched-out and off-balance spanning that same width —
     this keeps them a visibly centered column instead. */
  --nav-max-width: 1280px;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  font-family: var(--font-sans);
  font-size: 15px;
  color: var(--color-text);
  background: var(--color-bg);
  margin: 0;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Newsreader for page titles; Manrope 600 for section and card headings. */
h1, h2, h3, h4, h5, h6 { font-family: var(--font-sans); font-weight: 600; }
h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 36px;
  line-height: 42px;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-5);
}
h2 { font-size: 20px; line-height: 28px; margin: 0 0 var(--space-3); }

a { color: var(--color-accent-text); text-decoration: none; }
a:hover { color: var(--color-text); text-decoration: underline; }

/* --- App shell: top nav + main content --- */

.app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.topnav {
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 30;
}

.topnav-inner {
  max-width: var(--content-max-width);
  width: 100%;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-3) var(--space-6);
  box-sizing: border-box;
}

.topnav-brand {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  white-space: nowrap;
}

.topnav-brand-logo { height: 71px; width: auto; display: block; }

.topnav-links {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex: 1;
}

.topnav-link {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--font-size-sm);
  font-weight: 600;
  line-height: 1.5;
  background: none;
  border: none;
  cursor: pointer;
  padding: var(--space-2) var(--space-3);
  border-radius: 7px;
  font-family: inherit;
}

.topnav-link:hover { background: var(--color-border-soft); color: var(--color-text); text-decoration: none; }

/* --- Icons — standalone files under /static/icons/, swap the file to
   change an icon's artwork. Colors are baked into each file to match the
   context it's used in (see the table of file/color pairings this block's
   authors kept in the design plan), so recoloring an icon means editing or
   replacing its .svg, not overriding CSS color here. */
.icon {
  display: inline-block;
  flex: none;
  width: 25px;
  height: 25px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

.icon-12 { width: 18px; height: 18px; }
.icon-14 { width: 20px; height: 20px; }
.icon-28 { width: 36px; height: 36px; }
.icon-36 { width: 45px; height: 45px; }

.icon-dashboard { background-image: url("/static/icons/dashboard.png"); }
.icon-receipt { background-image: url("/static/icons/receipt.png"); }
.icon-receipt-empty { background-image: url("/static/icons/receipt-empty.svg"); }
.icon-wallet { background-image: url("/static/icons/wallet.png"); }
.icon-wallet-empty { background-image: url("/static/icons/wallet-empty.svg"); }
.icon-people { background-image: url("/static/icons/family.png"); }
.icon-bar-chart { background-image: url("/static/icons/bar-chart.png"); }
.icon-arrow-up-circle { background-image: url("/static/icons/incoming.png"); }
.icon-calendar-check { background-image: url("/static/icons/calendar-check.png"); }
.icon-shopping-cart { background-image: url("/static/icons/non-regular.png"); }
.icon-coin-stack { background-image: url("/static/icons/savings.png"); }
.icon-pie-chart { background-image: url("/static/icons/non-regular-transaction.png"); }
.icon-pencil { background-image: url("/static/icons/pencil.svg"); }
.icon-trash { background-image: url("/static/icons/trash.svg"); }
.icon-shield-check { background-image: url("/static/icons/shield-check.svg"); }
.icon-sync { background-image: url("/static/icons/sync.svg"); }
.icon-check-circle { background-image: url("/static/icons/check-circle.svg"); }
.icon-line-chart { background-image: url("/static/icons/chart1.png"); }
.icon-alt-update { background-image: url("/static/icons/chart2.png"); }
.icon-wave { background-image: url("/static/icons/flow.png"); }


.topnav-caret { font-size: 2.5em; line-height: 1; align-self: flex-start; margin-top: -0.17em; }

.beta-badge {
  display: inline-flex;
  flex: none;
  align-items: center;
  white-space: nowrap;
  height: 24px;
  padding: 0 9px;
  border-radius: var(--radius-xs);
  background: var(--color-accent-soft);
  color: var(--color-accent-soft-text);
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
}

.beta-badge:hover { background: var(--color-accent); color: #fff; text-decoration: none; }

.topnav-right {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.topnav-account-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-text);
  font-size: var(--font-size-sm);
  font-weight: 600;
  font-family: inherit;
  padding: var(--space-2) var(--space-3);
  border-radius: 7px;
}

.topnav-account-toggle:hover { background: var(--color-border-soft); }

.topnav-dropdown { position: relative; }

.topnav-account-dropdown { display: flex; align-items: center; gap: var(--space-2); }

.topnav-avatar-link { display: inline-flex; flex: none; }

.topnav-avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
}

.topnav-avatar-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-border-soft);
  color: var(--color-text-muted);
  font-size: 0.7rem;
  font-weight: 700;
}

.topnav-dropdown-menu {
  display: none;
  position: absolute;
  top: calc(100% + var(--space-1));
  left: 0;
  min-width: 200px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 8px 24px rgba(30, 28, 24, 0.1);
  padding: var(--space-2);
  flex-direction: column;
  gap: var(--space-1);
}

.topnav-dropdown-menu-right { left: auto; right: 0; }

.topnav-dropdown.open .topnav-dropdown-menu { display: flex; }

.topnav-dropdown-menu a,
.topnav-dropdown-item-btn {
  display: block;
  width: 100%;
  text-align: left;
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--font-size-sm);
  font-weight: 500;
  padding: var(--space-2) var(--space-3);
  border-radius: 7px;
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
}

.topnav-dropdown-menu a:hover,
.topnav-dropdown-item-btn:hover { background: var(--color-border-soft); color: var(--color-text); text-decoration: none; }

.topnav-logout-form { margin: 0; }

.nav-toggle {
  display: none;
  appearance: none;
  background: none;
  border: none;
  font-size: var(--font-size-lg);
  line-height: 1;
  cursor: pointer;
  color: var(--color-text);
  padding: var(--space-1);
}

.app-main {
  flex: 1;
  min-width: 0;
  padding: var(--space-6);
  max-width: var(--content-max-width);
  margin: 0 auto;
  width: 100%;
}

.app-footer {
  border-top: 1px solid var(--color-border);
  margin-top: auto;
}

.app-footer-inner {
  max-width: var(--nav-max-width);
  width: 100%;
  margin: 0 auto;
  padding: var(--space-7) var(--space-6) var(--space-5);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-6) var(--space-7);
  box-sizing: border-box;
}

.app-footer-brand { min-width: 240px; }

.app-footer-logo { height: 42px; width: auto; display: block; }

.app-footer-tagline {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  max-width: 32rem;
  margin: var(--space-2) 0 0;
}

.app-footer-social {
  display: flex;
  gap: var(--space-3);
  margin: var(--space-4) 0;
}

.app-footer-social a {
  color: var(--color-text-faint);
  display: inline-flex;
}

.app-footer-social a:hover { color: var(--color-text-muted); }

.app-footer-badges {
  display: flex;
  align-items: flex-start;
  align-self: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  flex-shrink: 0;
}

.app-footer-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--color-text);
  color: var(--color-surface) !important;
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  font-size: 0.7rem;
  line-height: 1.2;
}

.app-footer-badge span { display: flex; flex-direction: column; }
.app-footer-badge strong { font-size: var(--font-size-sm); }

.app-footer-trust {
  max-width: var(--nav-max-width);
  width: 100%;
  margin: 0 auto;
  padding: var(--space-4) var(--space-6) 0;
  border-top: 1px solid var(--color-border);
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-5);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  box-sizing: border-box;
}

.app-footer-trust span { display: inline-flex; align-items: center; gap: var(--space-2); }

.app-footer-bottom {
  max-width: var(--nav-max-width);
  width: 100%;
  margin: 0 auto;
  padding: var(--space-4) var(--space-6);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  color: var(--color-text-faint);
  font-size: var(--font-size-sm);
  box-sizing: border-box;
}

.app-footer-legal { display: flex; gap: var(--space-5); }
.app-footer-legal a { color: var(--color-text-faint); text-decoration: none; }
.app-footer-legal a:hover { color: var(--color-text-muted); }

.app-footer-disclosure {
  max-width: var(--nav-max-width);
  width: 100%;
  margin: 0 auto var(--space-6);
  padding: 0 var(--space-6);
  box-sizing: border-box;
}

.app-footer-disclosure p {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin: 0;
  color: var(--color-text-muted);
  font-size: 0.8rem;
  line-height: 1.6;
}

.app-footer-disclosure strong { color: var(--color-text); }

.app-footer-disclosure a { color: var(--color-text-muted); text-decoration: underline; }
.app-footer-disclosure a:hover { color: var(--color-text); }

/* --- Cards --- */

.card,
.item-group {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  margin-bottom: var(--space-4);
}

.form-card {
  max-width: 400px;
  margin: 0 auto var(--space-4);
}

.form-card form + form { margin-top: var(--space-3); }

.profile-picture-preview {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  margin-bottom: var(--space-4);
}

/* --- Buttons --- */

/* Default (unmodified) buttons use Tally's quiet style. */
button, .btn {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: normal;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border-strong);
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.btn { min-height: 40px; padding: 0 18px; }

button:hover, .btn:hover { background: var(--color-border-soft); text-decoration: none; }

.btn-primary {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #ffffff;
}
.btn-primary:hover { background: var(--color-accent-hover); border-color: var(--color-accent-hover); color: #ffffff; }

.btn-secondary {
  background: transparent;
  border-color: var(--color-text);
  color: var(--color-text);
}

.btn-secondary:hover { background: var(--color-border-soft); }

.btn-danger {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: #ffffff;
}
.btn-danger:hover { background: var(--color-danger-hover); border-color: var(--color-danger-hover); color: #ffffff; }

.btn-sm {
  min-height: 32px;
  padding: 0 12px;
  border-radius: 7px;
  font-size: 13px;
}
.btn-sm:not(.btn-primary):not(.btn-danger) { border-color: var(--color-border-strong); }

button:disabled, .btn:disabled,
button:disabled:hover, .btn:disabled:hover {
  background: var(--color-border);
  border-color: var(--color-border);
  color: var(--color-text-disabled);
  cursor: not-allowed;
}

/* The current page button is disabled so it can't be re-clicked, but it
   should still read as the selected page, not as unavailable. */
.pagination .btn-primary:disabled {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #ffffff;
  cursor: default;
}

/* Clay stays out of ledger rows so it keeps its "over budget" meaning —
   row deletes use the small quiet style (hx-confirm still guards them). */
.transactions-table .btn-danger {
  background: transparent;
  border-color: var(--color-border-strong);
  color: var(--color-text);
}
.transactions-table .btn-danger:hover { background: var(--color-border-soft); color: var(--color-text); }

/* --- Button loading state — .htmx-request is added/removed automatically
   by htmx around every hx-* request; .is-loading is the same idea applied
   by hand (base.html's global submit listener, and the two fetch()-based
   Plaid Link handlers in accounts.html) for the handful of buttons htmx
   doesn't cover. Matches both the triggering element itself (a button with
   its own hx-* attributes) and a submit button whose *form* is the hx-*
   element (e.g. the Add rule / Filter forms), without also lighting up an
   unrelated sibling button like an inline edit row's Cancel. --- */

.btn.htmx-request,
form.htmx-request > .btn[type="submit"],
.btn.is-loading {
  opacity: 0.65;
  pointer-events: none;
}

.btn.htmx-request::after,
form.htmx-request > .btn[type="submit"]::after,
.btn.is-loading::after {
  content: "";
  width: 0.85em;
  height: 0.85em;
  margin-left: var(--space-2);
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  display: inline-block;
  vertical-align: -0.15em;
  animation: btn-spin 0.6s linear infinite;
}

@keyframes btn-spin {
  to { transform: rotate(360deg); }
}

/* --- Forms --- */

form {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 320px;
}

form.inline-form {
  flex-direction: row;
  flex-wrap: wrap;
  max-width: none;
  align-items: center;
  margin-bottom: var(--space-6);
  gap: var(--space-3);
}

.period-switcher {
  display: inline-flex;
  align-items: center;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-2);
  gap: var(--space-2);
}

.period-switcher-checkbox {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-weight: 600;
  color: var(--color-text);
  cursor: pointer;
  transition: background-color var(--transition-fast);
}

.period-switcher-checkbox:hover { background-color: var(--color-border-soft); }

.inline-form.report-period-switcher {
  flex-direction: column;
  align-items: flex-start;
  padding: var(--space-4);
  gap: var(--space-4);
}

.period-switcher-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-3);
}

.period-select {
  min-height: 40px;
  font-size: 14px;
  font-weight: 600;
  color: var(--color-text);
  transition: background-color var(--transition-fast);
}

.period-select:hover { background-color: var(--color-row-hover); }

.filter-bar { margin-bottom: var(--space-4); gap: var(--space-4); display: flex; flex-direction: column; }

.filter-bar-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.filter-bar-inline-form { display: contents; }

.filter-bar-filters {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-end;
  max-width: none;
  margin-bottom: 0;
  gap: var(--space-3);
}

/* Without a cap, a <select> sizes its closed box to its widest option —
   the account filter's options (institution + account name + mask +
   member email) are much longer than any other filter's, so it alone
   would blow past the card edge while every other select stays put. */
.filter-bar-filters select { max-width: 220px; }

label, .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
}

input, select, textarea {
  font-family: inherit;
  font-size: 15px;
  font-weight: 400;
  color: var(--color-text);
  background: var(--color-surface-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  padding: var(--space-2) 12px;
}

/* :where() keeps this at plain element specificity, so compact in-table
   editors (.row-text-input etc.) can override the height with one class. */
input:where(:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="hidden"])),
select {
  min-height: var(--field-height);
  padding-top: 0;
  padding-bottom: 0;
}

select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 32px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M0 0h10L5 6z' fill='%23766f62'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 9px 6px;
  cursor: pointer;
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: var(--focus-ring);
}

input:disabled, select:disabled, textarea:disabled {
  border-color: var(--color-border);
  background-color: var(--color-disabled-bg);
  color: var(--color-text-disabled);
  cursor: not-allowed;
}

input[type="number"], input[inputmode="decimal"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

input[type="file"] { padding: var(--space-2); font-size: 14px; }

input[type="checkbox"],
input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  padding: 0;
  border: 1.5px solid #b9b1a0;
  border-radius: var(--radius-xs);
  background: var(--color-surface-2) no-repeat center;
  cursor: pointer;
}
input[type="radio"] { border-radius: 50%; }

input[type="checkbox"]:checked {
  border-color: var(--color-accent);
  background-color: var(--color-accent);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='10' viewBox='0 0 12 10'%3E%3Cpath d='M1 5l3.5 3.5L11 1' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 12px 10px;
}

input[type="radio"]:checked {
  border-color: var(--color-accent);
  background-image: radial-gradient(circle, var(--color-accent) 0 5px, transparent 5.5px);
}

section { margin-bottom: var(--space-7); }

.dashboard-section { margin-bottom: var(--space-7); }

.dashboard-section > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  list-style: none;
  margin-bottom: var(--space-3);
  user-select: none;
}

.dashboard-section > summary::-webkit-details-marker { display: none; }

.dashboard-section > summary::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid var(--color-text-muted);
  border-bottom: 2px solid var(--color-text-muted);
  transform: rotate(-45deg);
  transition: transform var(--transition-fast);
}

.dashboard-section[open] > summary::before { transform: rotate(45deg); }

.dashboard-section > summary h2 { margin: 0; }

/* --- Alerts --- */

.error, .alert-error,
.success, .alert-success,
.notice, .alert-notice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
}

.error::before, .alert-error::before,
.success::before, .alert-success::before,
.notice::before, .alert-notice::before {
  content: "";
  flex: none;
  width: 1.1em;
  height: 1.1em;
  margin-top: 0.1em;
  background: no-repeat center / contain;
}

.error, .alert-error {
  color: var(--color-danger-soft-text);
  background: var(--color-danger-soft);
  border-left: 3px solid var(--color-danger);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
}

.error::before, .alert-error::before {
  background-image: url("/static/icons/alert-triangle.svg");
}

.success, .alert-success {
  color: var(--color-accent-soft-text);
  background: var(--color-success-soft);
  border-left: 3px solid var(--color-success);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
}

.success::before, .alert-success::before {
  background-image: url("/static/icons/check-circle.svg");
}

.notice, .alert-notice {
  color: var(--color-text-muted);
  background: var(--color-border-soft);
  border-left: 3px solid var(--color-border-strong);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
}

.notice::before, .alert-notice::before {
  background-image: url("/static/icons/info-circle.svg");
}

/* --- Pagination --- */

.pagination {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-4) 0;
}

/* --- MFA setup QR code --- */

.qr-code { max-width: 220px; margin-bottom: var(--space-3); }
.qr-code svg { width: 100%; height: auto; }

/* --- Danger zone --- */

.danger-zone {
  border: 1px solid var(--color-danger);
  background: var(--color-danger-soft);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}

/* --- Tags --- */

.shared-tag, .tag, .owner-label {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 10px;
  color: var(--color-text-muted);
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: 14px;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
}

/* --- Tables --- */

.table-wrapper { overflow-x: auto; }

.table-wrapper-narrow { max-width: 700px; margin: 0 auto; }

.table-wrapper td input,
.table-wrapper td select:not(.category-pill-select) { width: 100%; box-sizing: border-box; }

.table-add-row td { background: var(--color-bg); border-bottom: 2px solid var(--color-border-strong); }

table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: var(--space-3); border-bottom: 1px solid var(--color-border-soft); font-size: 14px; }
th {
  border-bottom-color: var(--color-border);
  color: var(--color-text-faint);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
tbody tr:hover { background: var(--color-row-hover); }

.table-empty { padding: 48px 20px; text-align: center; font-size: 14px; color: var(--color-text-faint); }

.table-actions { display: flex; gap: var(--space-2); justify-content: flex-end; }

/* --- Transactions table (compact/dense) --- */

.transactions-table th,
.transactions-table td {
  padding: 0 var(--space-2);
  font-size: 14px;
  border-bottom: 1px solid var(--color-border-soft);
  white-space: nowrap;
  /* A row with an editable input/select/button (your own transactions) vs.
     one with plain text or nothing at all (other family members' rows)
     otherwise end up different heights, since an empty or plain-text cell
     has no border/padding of its own to match an input's box. A shared
     minimum height keeps every row the same regardless of which is
     rendered, with content vertically centered inside it either way. */
  height: 52px;
  vertical-align: middle;
}

.transactions-table th { height: 40px; font-size: 11px; border-bottom: 1px solid var(--color-border); }
.transactions-table th:first-child,
.transactions-table td:first-child { padding-left: var(--space-4); }
.transactions-table th:last-child,
.transactions-table td:last-child { padding-right: var(--space-4); }

/* Sortable column headers — look like the plain headers until hovered. */
.th-sort {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
}
.th-sort:hover { background: none; }
.th-sort:hover,
.th-sort.is-active { color: var(--color-text); }
.th-sort:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; border-radius: 2px; }
/* Tally shows the arrow only on the sorted column; the others reveal a
   faint ↕ on hover so they still read as sortable. */
.th-sort-indicator { opacity: 0; }
.th-sort:hover .th-sort-indicator { opacity: 0.5; }
.th-sort.is-active .th-sort-indicator { opacity: 1; }

/* Filter total, above the headings and below the last row. */
.transactions-table .totals-row td { height: 44px; border-bottom: 0; }
.transactions-table .totals-row-bottom td { border-top: 1px solid var(--color-border); }
.transactions-table .totals-label { text-align: right; font-size: 13px; color: var(--color-text-muted); }
.transactions-table .totals-amount { font-weight: 600; }
.transactions-table tbody tr:hover { background: var(--color-row-hover); }

/* Every figure is mono + tabular. */
.num, .dash-txn-amount { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

.transactions-table .num { text-align: right; }

/* Income green with "+", expenses in Ink with "−"; clay never in a ledger row. */
.num-credit { color: var(--color-success); font-weight: 400; }
.num-debit { color: var(--color-text); font-weight: 400; }

.row-text-input { font-size: 14px; padding: 0 var(--space-2); width: 100%; min-width: 8rem; box-sizing: border-box; }
input.row-text-input { min-height: 32px; height: 32px; border-radius: 7px; }

.transactions-table .dash-txn-date {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--color-text-muted);
}

.cell-primary { font-weight: 600; }
.cell-secondary { color: var(--color-text-muted); font-size: var(--font-size-sm); }

/* Keeps the name input/text and the "Manual" badge on one line instead of
   the badge wrapping below the full-width input. */
.cell-name { display: flex; align-items: center; gap: var(--space-1); min-width: 0; }
.cell-name .row-text-input,
.cell-name .cell-primary { flex: 1; min-width: 11rem; }
.transactions-table .badge { flex-shrink: 0; }

/* Editable amount: sign + "$" then a compact, right-aligned number box in
   the same mono figures as the read-only amounts. */
.amount-edit { display: inline-flex; align-items: center; justify-content: flex-end; gap: 2px; }
.amount-edit .amount-input {
  width: 7.5rem;
  min-width: 0;
  min-height: 32px;
  height: 32px;
  border-radius: 7px;
  font-size: 14px;
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: inherit;
  color: inherit;
  appearance: textfield;
  -moz-appearance: textfield;
}
.amount-edit .amount-input::-webkit-outer-spin-button,
.amount-edit .amount-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* --- Report table (monthly category x month grid) --- */

.report-table th,
.report-table td {
  padding: 3px var(--space-2);
  font-size: 13px;
  border: 1px solid var(--color-border);
  white-space: nowrap;
}

.report-table th {
  height: 40px;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-text);
  font-family: var(--font-mono);
  font-weight: 500;
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--color-text-faint);
}

.report-table .num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

.report-table td:first-child { font-weight: 600; }

.report-table tbody tr:nth-child(even) { background: var(--color-bg); }
.report-table tbody tr:hover { background: var(--color-row-hover); }

/* Specificity needs to match/beat tr:nth-child(even) above (same 2 classes
   + 2 type selectors) — otherwise a summary row landing on an even position
   would silently lose its tint back to the plain zebra-stripe color. */
.report-table tbody tr.report-summary-row { background: var(--color-border-soft); }
/* On the cells, not the row — in a collapsed-border table the cells' own
   1px Rule borders win over a row border of the same width. */
.report-table tbody tr.report-summary-row-last td,
.report-table tbody tr.report-overview-row-last td { border-bottom-color: var(--color-text); }

/* Budget / Income / Savings rows above the expense rows. */
.report-table tbody tr.report-overview-row { background: var(--color-surface); }
.report-table td.report-negative { color: var(--color-danger-text); }

.report-table tfoot td {
  background: var(--color-bg);
  border-top: 1px solid var(--color-text);
  font-weight: 600;
}

.report-table td a { color: inherit; text-decoration: none; }
.report-table td a:hover { text-decoration: underline; }

/* Budget (col 2) and Average (col 3) each get their own warm neutral tint,
   on top of th/td/tfoot alike, so they read as distinct from the month
   columns. Neutral, not blue/green: green means income in this palette. */
.report-table th:nth-child(2), .report-table td:nth-child(2) { background-color: var(--color-row-hover); }
.report-table th:nth-child(3), .report-table td:nth-child(3) { background-color: var(--color-border-soft); }

/* Average (or the current month so far) came in over budget for that
   category — a clay border on the cell. */
.report-table td.over-budget { border: 2px solid var(--color-danger); }

/* A completed month whose spend went over the category budget — a plum fill. */
.report-table td.month-over-budget {
  background-color: oklch(0.93 0.035 320);
  color: oklch(0.40 0.09 320);
  font-weight: 600;
}

/* --- Report cell hover preview --- */

.report-cell { position: relative; display: inline-block; }

.cell-tooltip {
  /* Flush against the cell (no gap) — a gap here would be a dead zone the
     mouse has to cross to reach the tooltip, un-hovering .report-cell
     (and hiding the tooltip) before it gets there. The arrow below fakes
     the visual separation instead. */
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 40;
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-top: 3px solid var(--color-text);
  border-radius: var(--radius-md);
  box-shadow: 0 10px 24px rgba(30, 28, 24, 0.16);
  padding: var(--space-3);
  min-width: 220px;
  max-height: 440px;
  overflow-y: auto;
  font-size: var(--font-size-sm);
  white-space: normal;
  text-align: left;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--transition-fast), transform var(--transition-fast), visibility var(--transition-fast);
  pointer-events: none;
}

.cell-tooltip::before,
.cell-tooltip::after {
  content: "";
  position: absolute;
  bottom: 100%;
  right: var(--space-3);
  border: 6px solid transparent;
  border-bottom-color: var(--color-text);
  margin-bottom: 0;
}

.cell-tooltip::after { display: none; }

.report-cell:hover .cell-tooltip {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  pointer-events: auto;
}

.summary-table { width: 100%; border-collapse: collapse; }
.summary-table td { padding: var(--space-1) var(--space-2); white-space: nowrap; border-bottom: 1px solid var(--color-border-soft); font-size: 13px; }
.summary-table tr:last-child td { border-bottom: none; }
.summary-table .num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 500; }

.summary-more { margin: var(--space-2) 0 0; text-align: right; }

.summary-title {
  font-weight: 600;
  font-size: var(--font-size-sm);
  margin-bottom: var(--space-2);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}

/* --- Lists --- */

.list-plain { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }

/* --- Accounts page --- */

.account-row { padding: var(--space-2) 0 var(--space-2) var(--space-4); display: flex; justify-content: space-between; }
.account-type { color: var(--color-text-muted); font-size: var(--font-size-sm); }
.dashboard-actions { display: flex; gap: var(--space-3); margin-bottom: var(--space-5); }
.item-group-header { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.sync-status { color: var(--color-text-muted); font-size: var(--font-size-sm); margin-left: auto; }

/* --- Stat cards (dashboard) --- */

.stat-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-6);
  margin-bottom: var(--space-6);
}

.stat-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  color: var(--color-text);
  text-decoration: none;
  transition: border-color var(--transition-fast);
  /* Lets .stat-value size itself to this card's width (cqi units). */
  container-type: inline-size;
}

.dashboard-charts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-6);
  margin-bottom: var(--space-6);
}

.dashboard-chart-card { margin-bottom: 0; }

.dashboard-chart-card h3 {
  font-size: 17px;
  color: var(--color-text);
  margin: 0 0 var(--space-3);
}

.dashboard-chart-card canvas { max-height: 280px; }

/* --- Donut card (spending-by-category breakdown) --- */

.donut-card { margin-bottom: var(--space-6); }

.donut-header { margin-bottom: var(--space-4); }

.donut-header-titles { display: flex; align-items: center; gap: var(--space-3); }

.donut-eyebrow {
  color: var(--color-text-faint);
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: 11px;
  line-height: 16px;
  font-weight: 500;
  letter-spacing: 0.08em;
  margin-bottom: var(--space-1);
}

.donut-title { font-family: var(--font-sans); font-size: 20px; line-height: 28px; font-weight: 600; }

.donut-body {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: flex-start;
  gap: var(--space-6);
}

.donut-chart-wrap {
  position: relative;
  width: 280px;
  max-width: 100%;
  aspect-ratio: 1 / 1;
  margin: 0 auto;
}

.donut-chart-wrap canvas { max-height: none; }

.donut-center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  pointer-events: none;
}

.donut-center-value { font-family: var(--font-display); font-size: 30px; font-weight: 400; }
.donut-center-label { font-size: var(--font-size-sm); color: var(--color-text-muted); }

.donut-legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 var(--space-3);
}

@media (max-width: 900px) {
  .donut-legend { grid-template-columns: 1fr; }
}

.donut-legend li {
  display: flex;
  align-items: flex-start;
  gap: 0.3rem;
  padding: 0.2rem var(--space-1);
  border-radius: var(--radius-sm);
  cursor: default;
  transition: background var(--transition-fast);
}

.donut-legend li:hover,
.donut-legend li.donut-legend-active { background: var(--color-row-hover); }

.donut-dot {
  flex-shrink: 0;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  margin-top: 0.3em;
}

.donut-legend-text { min-width: 0; }
.donut-legend-name { font-weight: 500; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.donut-legend-amount { color: var(--color-text-muted); font-family: var(--font-mono); font-size: 0.7rem; white-space: nowrap; }

.dashboard-main-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  gap: var(--space-6);
}

.dashboard-main-col-left {
  display: flex;
  flex-direction: column;
  /* Grid items default to min-width:auto, so a wide nowrap table inside
     would otherwise push this column past its fair 1fr share instead of
     respecting the 50/50 split — this makes it actually honor that. */
  min-width: 0;
}

.dashboard-main-col-right {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
}

.recent-transactions-card { margin-bottom: 0; flex: 1; }

.outcome-card { margin-bottom: 0; flex: 1; display: flex; flex-direction: column; }

/* Fixed height, not flex:1 — a flex item's flex-basis (0 under flex:1)
   ignores its height/max-height, so it was silently being sized to
   whatever leftover space the transactions column left it, rather than
   what it actually needs to space its own bars out. A plain height keeps
   this card's real content size in play, so if it ends up taller than the
   transactions column, that column (already flex:1 in its own wrapper)
   grows to match instead. */
.outcome-chart-wrap { height: 480px; }

.sankey-chart-wrap { height: 500px; }
.sankey-svg { display: block; width: 100%; height: 100%; }
.sankey-svg text { fill: var(--color-text-muted); font-family: var(--font-sans); font-weight: 600; }
.sankey-svg .sankey-link:hover { stroke-opacity: 0.6; }

.recent-transactions-header { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-2); }

.view-all-link { font-size: 13px; font-weight: 600; white-space: nowrap; }

.recent-transactions-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.recent-transactions-table td {
  padding: 0.4rem var(--space-2);
  border-bottom: 1px solid var(--color-border-soft);
  vertical-align: middle;
  white-space: nowrap;
}

.recent-transactions-table tr:last-child td { border-bottom: 0; }
.recent-transactions-table tbody tr:hover { background: var(--color-row-hover); }

.dash-txn-date {
  color: var(--color-text-muted);
  font-family: var(--font-mono);
  font-size: 12px;
  width: 1%;
}

.dash-txn-name { font-weight: 600; }

.dash-txn-name {
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dash-txn-description {
  max-width: 90px;
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
}

.dash-txn-description-input {
  width: 100%;
  max-width: 90px;
  overflow: hidden;
  text-overflow: ellipsis;
  border: none;
  border-radius: 0;
  border-bottom: 1px dashed var(--color-border-strong);
  background: transparent;
  padding: 0;
  font-size: 13px;
  color: var(--color-text-muted);
  cursor: text;
}

input.dash-txn-description-input { min-height: 0; height: auto; border-radius: 0; }

.dash-txn-description-input:hover,
.dash-txn-description-input:focus { background: var(--color-surface-2); border-bottom-style: solid; box-shadow: none; }

.dash-txn-category,
.dash-txn-expense-type { width: 1%; }

/* Tally category tag: Ink text on a neutral pill with an 8px dot in the
   category's color. The row templates set --c inline (category_color). */
.category-pill,
.category-pill-select {
  display: inline-flex;
  align-items: center;
  height: 28px;
  min-height: 28px;
  padding: 0 10px 0 24px;
  border: 1px solid var(--color-border);
  border-radius: 14px;
  background: var(--color-surface) radial-gradient(circle, var(--c, var(--color-text-faint)) 0 3.5px, transparent 4px) no-repeat 8px center / 8px 8px;
  color: var(--color-text);
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
}

.category-pill-select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  font-family: inherit;
}

/* The dashboard's half-width recent-transactions card has no room for
   full-size tags next to the amount, so they run one size down there. */
.recent-transactions-table .category-pill,
.recent-transactions-table .category-pill-select {
  height: 24px;
  min-height: 24px;
  padding: 0 8px 0 19px;
  font-size: 12px;
  background-position: 6px center;
}

.category-pill-select:hover { background-color: var(--color-row-hover); }
.category-pill-select option { color: var(--color-text); }

.dash-txn-amount {
  width: 1%;
  text-align: right;
  font-weight: 400;
}

.dash-txn-actions { width: 1%; padding-left: var(--space-1); }

.dash-txn-delete {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text-faint);
  font-size: 0.8rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.dash-txn-delete:hover { border-color: var(--color-border-strong); background: var(--color-border-soft); }

.stat-card:hover { border-color: var(--color-border-strong); text-decoration: none; color: var(--color-text); }
.stat-card.over-budget { border-color: var(--color-danger); }

/* KPI tile: mono label, Newsreader figure, small Ink 2 caption. */
.stat-label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-faint);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-3);
  color: var(--color-text-faint);
  font-size: 14px;
  text-align: center;
}

.empty-state p { margin: 0; }
/* 40px per the style guide, scaled down when the card is narrow (two per
   row on a phone): Newsreader figures run ~5.6em wide for "$123,456.78",
   so 17% of the card's width keeps amounts up to that inside the card.
   overflow-wrap is the last resort for anything longer. */
.stat-value {
  font-family: var(--font-display);
  font-size: clamp(18px, 17cqi, 40px);
  line-height: 1;
  font-weight: 400;
  overflow-wrap: anywhere;
}
.stat-value.stat-positive { color: var(--color-accent-hover); }
.stat-value.stat-negative { color: var(--color-danger-text); }
.stat-budget { font-size: 13px; font-weight: 400; color: var(--color-text-muted); }
.stat-budget-over { color: var(--color-danger-text); font-weight: 600; }

/* --- Badges --- */

/* Tally status badges: on track (green), over (clay), neutral (fully used). */
.badge {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 9px;
  border-radius: var(--radius-xs);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  white-space: nowrap;
}

.badge-success { background: var(--color-success-soft); color: var(--color-accent-soft-text); }
.badge-danger { background: var(--color-danger-soft); color: var(--color-danger-soft-text); }
.badge-neutral { background: var(--color-border-soft); color: var(--color-text-muted); }

/* --- Responsive --- */

@media (max-width: 640px) {
  /* .topnav-links normally acts as the flex:1 spacer that pushes
     .topnav-right to the edge — now that it wraps to its own row below
     instead of sharing this one, justify-content has to do that job for
     the logo/hamburger row instead. */
  /* The base gap: var(--space-6) (32px) is meant for spacing between
     desktop's row of nav items — once the icon row wraps onto its own
     line below, that same gap compounds with .topnav-links' own
     margin-top/padding-top/border spacing, doubling up the gap visually. */
  .topnav-inner { padding: var(--space-3) var(--space-4); flex-wrap: wrap; justify-content: space-between; gap: 0; }

  /* Smaller than desktop's version, and sits between the logo and hamburger
     in row 1 automatically — .topnav-inner's justify-content: space-between
     plus this being a plain sibling (no explicit order, unlike .topnav-links'
     order: 3 below) already places it there without any extra positioning. */
  .beta-badge { height: 22px; font-size: 11px; padding: 0 7px; }

  /* Account/personal links stay behind the hamburger (.topnav-mobile-menu
     below); the main nav goes icon-only in its own row instead, rather
     than also being buried — see .topnav-link-label below. */
  .topnav-account-dropdown { display: none; }

  .topnav-links {
    order: 3;
    width: 100%;
    justify-content: space-around;
    gap: 0;
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    margin-top: var(--space-2);
  }

  .topnav-link-label,
  .topnav-links .topnav-caret { display: none; }

  .nav-toggle { display: inline-flex; }

  /* .topnav-dropdown's own position:relative would otherwise anchor the
     panel to this small button-sized wrapper instead of the full header —
     static here lets it bubble up to .topnav (position: sticky, itself
     already a positioning context) so top/left/right below span the full
     header width instead. */
  /* flex-start instead of .topnav-right's default vertical-center — the
     logo image is taller than the button (it has the "personal finance"
     subtitle under the wordmark), so centering on the row put the icon
     noticeably below the wordmark's letters instead of level with them. */
  .topnav-mobile-menu-wrapper { position: static; align-self: flex-start; margin-top: -16px; }

  .topnav-mobile-menu {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    min-width: 0;
    border-radius: 0;
    max-height: calc(100vh - 100%);
    overflow-y: auto;
  }

  .topnav-mobile-menu-person {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3) var(--space-3);
    font-weight: 500;
  }

  .topnav-mobile-menu-links { display: flex; flex-direction: column; gap: var(--space-1); }

  .app-main { padding: var(--space-6) var(--space-4); }

  form.inline-form {
    flex-direction: column;
    align-items: stretch;
  }

  form.inline-form select,
  form.inline-form input,
  form.inline-form button {
    width: 100%;
  }

  /* The 220px cap (added to stop the accounts filter's long option text
     from overflowing the card on desktop) leaves every filter select
     stranded well short of the card's full width here instead — each one
     already gets its own row via flex-wrap, so there's no overflow risk
     to guard against at this width. */
  .filter-bar-filters select { max-width: none; width: 100%; }

  .item-group-header { flex-direction: column; align-items: stretch; }
  .sync-status { margin-left: 0; }
  .donut-body { grid-template-columns: 1fr; }
  .donut-legend { grid-template-columns: 1fr; }
  .dashboard-charts { grid-template-columns: 1fr; }
  .dashboard-main-row { grid-template-columns: 1fr; }
  .auth-form-row { grid-template-columns: 1fr; }

  /* Month and year side by side on one row, View on its own full-width row
     below — flex-basis on the selects leaves no room left for the button
     to share their row, so it wraps down without needing its own wrapper
     element around just the two selects. */
  /* form.inline-form (element+class) outranks a plain .period-switcher
     (class-only) selector, so form.inline-form's own flex-direction:column
     a few lines up was winning and keeping this stacked no matter what
     got set here — matching its specificity is what actually overrides it. */
  form.inline-form.period-switcher { width: 100%; flex-direction: row; flex-wrap: wrap; align-items: stretch; }
  .period-switcher .period-select { flex: 1 1 calc(20% - var(--space-1)); }
  .period-switcher .btn { flex: 1 1 100%; }

  /* Shrunk to just its colored dot here — at full pill width a row's
     category + expense type alone can exceed a phone's whole screen width,
     forcing horizontal scroll just to see the amount/delete button. Tapping
     it still opens the full option list. */
  .category-pill-select,
  .recent-transactions-table .category-pill-select {
    width: 28px;
    max-width: 28px;
    padding: 0;
    overflow: hidden;
    color: transparent;
    background-position: center;
  }
}

/* --- Auth pages (login/signup/etc — same site chrome as everywhere else,
   just a narrow centered card in the content area) --- */

.auth-card {
  width: 100%;
  max-width: 440px;
  margin: var(--space-7) auto 0;
}

.auth-brand { display: flex; justify-content: center; margin-bottom: var(--space-5); }
.auth-logo { height: 44px; width: auto; }

.auth-heading {
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 36px;
  line-height: 42px;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-2);
}

.auth-subtitle {
  text-align: center;
  color: var(--color-text-muted);
  margin: 0 0 var(--space-6);
}

.auth-form { max-width: none; gap: var(--space-4); margin-bottom: var(--space-5); }

.auth-form input { font-size: 15px; }

.auth-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

.field-hint { color: var(--color-text-faint); font-size: 12px; font-weight: 500; }

.field-label-row { display: flex; justify-content: space-between; align-items: baseline; }

.auth-inline-link { font-size: var(--font-size-sm); }

.auth-submit {
  width: 100%;
  min-height: 44px;
  font-size: 15px;
  font-weight: 600;
}

.auth-footer-text { text-align: center; color: var(--color-text-muted); }
.auth-footer-text a { font-weight: 600; }

/* --- Splash / home page --- */

.splash { display: flex; flex-direction: column; }

.splash-section { padding: var(--space-7) var(--space-6); }
.splash-section-inner { max-width: var(--nav-max-width); margin: 0 auto; width: 100%; }
.splash-section-muted { background: var(--color-surface); border-top: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border); }

.splash-eyebrow {
  color: var(--color-accent-text);
  font-family: var(--font-mono);
  text-transform: uppercase;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.08em;
  margin-bottom: var(--space-2);
}

.splash-section-header { max-width: 640px; margin: 0 auto var(--space-6); text-align: center; }
.splash-section-header h2 { font-family: var(--font-display); font-weight: 400; font-size: 2.25rem; line-height: 1.15; letter-spacing: -0.01em; margin: 0 0 var(--space-2); }
.splash-section-header p { color: var(--color-text-muted); margin: 0; }

.splash-hero {
  padding: var(--space-7) var(--space-6);
  /* Near-opaque wash over the left ~2/3 (where the headline/CTAs sit) so
     text stays legible against the photo underneath, easing to a much
     lighter tint on the right so the photo actually reads as a photo —
     the mockup card sitting there already has its own opaque background,
     so it doesn't need the wash's help. */
  background-image:
    linear-gradient(90deg, var(--color-bg) 0%, rgba(245, 242, 235, 0.88) 45%, rgba(245, 242, 235, 0.35) 75%),
    url("/static/vitaly-gariev-Yy8qu396OP8-unsplash.jpg");
  background-size: cover;
  background-position: center;
}

.splash-hero-inner {
  max-width: var(--nav-max-width);
  margin: 0 auto;
  width: 100%;
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: var(--space-6);
  align-items: center;
}

.splash-hero h1 {
  font-size: clamp(2.5rem, 5vw, 3.5rem);
  line-height: 1.07;
  letter-spacing: -0.02em;
  margin: 0 0 var(--space-4);
}

.splash-hero-lede { font-size: 17px; line-height: 1.6; color: var(--color-text-muted); margin: 0 0 var(--space-5); }

.splash-hero-ctas { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-4); }
.splash-hero-ctas .btn { min-height: 48px; padding: 0 var(--space-6); font-size: 15px; }

.splash-hero-proof { display: flex; flex-wrap: wrap; gap: var(--space-4); color: var(--color-text-muted); font-size: var(--font-size-sm); }
.splash-hero-proof span { display: inline-flex; align-items: center; gap: var(--space-2); }

.splash-mockup {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 12px;
  padding: var(--space-5);
  box-shadow: 0 1px 0 var(--color-border), 0 24px 48px -24px rgba(30, 28, 24, 0.18);
}

.splash-mockup-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: var(--space-4); }
.splash-mockup-header h3 { margin: 0; font-family: var(--font-display); font-weight: 400; font-size: 24px; }

.splash-mockup .stat-cards { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.splash-mockup .stat-card { border-radius: var(--radius-md); }

.splash-features-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-4);
}

.splash-feature-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}

.splash-feature-icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-md);
  background: var(--color-accent-soft);
  margin-bottom: var(--space-3);
}

.splash-feature-card h3 { font-size: 17px; margin: 0 0 var(--space-2); }
.splash-feature-card p { color: var(--color-text-muted); font-size: var(--font-size-sm); margin: 0; }

.splash-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); counter-reset: splash-step; }

.splash-step-card { text-align: center; }

.splash-step-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--color-accent);
  color: #fff;
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 400;
  margin-bottom: var(--space-3);
}

.splash-step-card h3 { font-size: 17px; margin: 0 0 var(--space-2); }
.splash-step-card p { color: var(--color-text-muted); font-size: var(--font-size-sm); margin: 0; }

.splash-security-inner {
  max-width: var(--nav-max-width);
  margin: 0 auto;
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-6);
  align-items: center;
}

.splash-security-badges { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.splash-security-badges li { display: flex; align-items: flex-start; gap: var(--space-3); }
.splash-security-badges strong { display: block; }
.splash-security-badges span.security-desc { color: var(--color-text-muted); font-size: var(--font-size-sm); }

.splash-faq { max-width: 720px; margin: 0 auto; display: flex; flex-direction: column; gap: var(--space-3); }

.splash-faq-item {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
}

.splash-faq-item summary {
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}

.splash-faq-item summary::-webkit-details-marker { display: none; }

.splash-faq-item summary::after {
  content: "+";
  float: right;
  color: var(--color-text-faint);
  font-weight: 500;
}

.splash-faq-item[open] summary::after { content: "\2212"; }

.splash-faq-item p { color: var(--color-text-muted); margin: var(--space-3) 0 0; }

/* Ink band, like Tally's dark surfaces; the primary action stays green. */
.splash-cta {
  background: var(--color-text);
  color: var(--color-surface);
  text-align: center;
  padding: var(--space-7) var(--space-6);
}

.splash-cta h2 { font-family: var(--font-display); font-weight: 400; font-size: 2.25rem; line-height: 1.15; margin: 0 0 var(--space-2); }
.splash-cta p { margin: 0 0 var(--space-5); color: #bdb6a6; }
.splash-cta .splash-hero-ctas { justify-content: center; }
.splash-cta .btn-secondary { background: transparent; border-color: rgba(251, 250, 246, 0.5); color: var(--color-surface); }
.splash-cta .btn-secondary:hover { background: #2a2823; border-color: var(--color-surface); }

@media (max-width: 900px) {
  .splash-hero-inner, .splash-security-inner { grid-template-columns: 1fr; }
  /* Once the hero stacks to one column, the text block spans the full
     width instead of just the left ~2/3 the desktop wash was tuned for —
     go fully opaque so the photo (now sitting below the text, not beside
     it) can't undercut legibility anywhere text wraps to. */
  .splash-hero {
    background-image: linear-gradient(var(--color-bg), var(--color-bg)), url("/static/vitaly-gariev-Yy8qu396OP8-unsplash.jpg");
  }
  .splash-features-grid { grid-template-columns: repeat(2, 1fr); }
  .splash-steps { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .splash-features-grid { grid-template-columns: 1fr; }
  .splash-mockup .stat-cards { grid-template-columns: 1fr; }
}
