/* ==========================================================================
   Cuentabox — "Fluent Ledger" design system
   Windows 11 / Fluent 2 rendered for a bookkeeping tool: neutral layered
   surfaces, hairline strokes, 4px controls on 8px cards, and ONE accent —
   petrol teal — carrying every action.
   Self-contained: system fonts, no external requests, no build step.

   Two rules the whole system rests on:
     1. Neutral first. Fluent is neutral-first, and a single accent only reads
        as an accent against neutral ground.
     2. One colour, one meaning. Teal means "you can act here". Green means
        money in. Red means money out. Amber means the AI is unsure. Nothing
        wears two hats, which is why the accent stopped being green.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  color-scheme: light;

  /* Surfaces & ink — Fluent light: layered neutrals, never warm */
  --bg:          #F3F3F3;   /* mica-like base the cards sit on */
  --bg-tint:     #EAEAEA;
  --surface:     #FFFFFF;   /* card / layer */
  --surface-2:   #F9F9F9;   /* subtle inset within a card */
  --line:        #E5E5E5;   /* hairline divider */
  --line-strong: #D2D2D2;   /* control border */
  --line-bottom: #C7C7C7;   /* Fluent's darker bottom stroke on controls */
  --text:        #1B1B1B;
  --text-muted:  #5D5D5D;

  /* Brand chrome — near-black neutral, not a second colour */
  --brand:       #1F1F1F;
  --brand-2:     #2B2B2B;
  --on-brand:    #FFFFFF;
  --on-brand-dim:#C7C7C7;

  /* Accent — petrol teal. It carries every ACTION: buttons, focus, the selected
     section, links. It is deliberately NOT green any more: green now means one
     thing only, money coming in, so the two jobs stop competing. Contrast
     checked - 5.95:1 both for white on the accent and the accent on white. */
  /* The brand blue, sampled off the Cuentabox logo (navy #0C2E72 -> blue
     #007DFB -> cyan #00B0D5) and deepened one step: white on the logo's own
     blue is 3.9:1, which is fine for a headline and not for a button label.
     This clears 4.6:1. */
  --accent:      #0A6FE8;
  --accent-hi:   #0B63CE;   /* hover */
  --accent-press:#094FA8;   /* pressed */
  --on-accent:   #FFFFFF;
  --accent-text: #0B5FC4;   /* accent as text on light ground */
  --accent-soft: #E6F0FE;

  /* Money & status. Green is now reserved for money-in and nothing else. */
  --pos:         #0C7A56;
  --neg:         #C42B1C;
  --warn:        #9D5D00;
  --warn-soft:   #FFF4CE;
  --warn-line:   #EFD08A;
  --danger:      #C42B1C;
  --danger-soft: #FDE7E9;

  /* Category chip tints */
  --chip-bg:     #EFEFEF;
  --chip-text:   #3A3A3A;

  /* Chart series. NOT the same as --pos/--neg: green-vs-red is invisible to a
     red-green colourblind reader, and these bars sit side by side where that
     matters. Green-vs-amber was picked by running the palette validator -
     deuteranopia separation goes from 1.7 (unusable) to 8.5+ here. The +/- red
     stays for text, where the sign and position already carry the meaning. */
  --series-in:   #12805C;
  --series-out:  #B07C0A;
  --grid:        #E8E8E8;

  /* Radii — Win11: 4px controls, 8px cards, nothing pill-shaped by default */
  --r-sm: 4px;
  --r-md: 8px;
  --r-lg: 10px;
  --r-xl: 12px;
  --r-full: 999px;

  /* Spacing scale */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 20px; --s6: 24px; --s7: 32px; --s8: 44px;

  /* Elevation — Fluent is restrained: a stroke does most of the work */
  --sh-1: 0 1px 2px rgba(0, 0, 0, .05);
  --sh-2: 0 1px 3px rgba(0, 0, 0, .06), 0 4px 10px rgba(0, 0, 0, .045);
  --sh-3: 0 8px 20px rgba(0, 0, 0, .14);
  --sh-accent: 0 2px 6px rgba(0, 0, 0, .22);

  /* Motion — Fluent's decelerate curve; short, never showy */
  --dur-fast: 100ms;
  --dur:      180ms;
  --dur-slow: 280ms;
  --ease: cubic-bezier(0, 0, 0, 1);

  /* Type — Segoe UI Variable is Windows 11's face and costs no download.
     Everything else falls back to the platform's own UI face, which keeps a
     low-end Android phone free of any webfont request. */
  --font: "Segoe UI Variable Text", "Segoe UI Variable", "Segoe UI",
          system-ui, -apple-system, Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Segoe UI Variable Display", "Segoe UI Variable", "Segoe UI",
          system-ui, -apple-system, Roboto, "Helvetica Neue", Arial, sans-serif;
  /* Numbers stay in the UI face with tabular figures - Fluent never switches
     to mono, and columns still line up. */
  --num: var(--font);

  --tabbar-h: 64px;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;

    --bg:          #202020;
    --bg-tint:     #272727;
    --surface:     #2B2B2B;
    --surface-2:   #323232;
    --line:        #3A3A3A;
    --line-strong: #484848;
    --line-bottom: #1E1E1E;
    --text:        #F5F5F5;
    --text-muted:  #C0C0C0;

    --brand:       #1A1A1A;
    --brand-2:     #262626;
    --on-brand:    #F5F5F5;
    --on-brand-dim:#B0B0B0;

    /* Lifts on the dark ground - a control has to be lighter than the page it
       sits on. --on-accent goes dark with it; keep those two in step or the
       label turns white-on-light-blue and disappears. 5.2:1. */
    --accent:      #3D97FF;
    --accent-hi:   #5EA9FF;
    --accent-press:#2C7FE0;
    --on-accent:   #06284F;
    --accent-soft: #12314F;
    --accent-text: #6FB6FF;

    --pos:         #5FDCAC;
    --neg:         #FF99A4;
    --warn:        #FCE100;
    --warn-soft:   #332B00;
    --warn-line:   #5C4F00;
    --danger:      #FF99A4;
    --danger-soft: #442726;

    --chip-bg:     #333333;
    --chip-text:   #DCDCDC;

    /* Re-stepped for the dark surface and re-validated there, not flipped. */
    --series-in:   #35A87E;
    --series-out:  #C08A1A;
    --grid:        #383838;

    --sh-1: 0 1px 2px rgba(0, 0, 0, .4);
    --sh-2: 0 1px 3px rgba(0, 0, 0, .5), 0 4px 10px rgba(0, 0, 0, .35);
    --sh-3: 0 8px 20px rgba(0, 0, 0, .6);
    --sh-accent: 0 2px 6px rgba(63, 184, 199, .22);
  }
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

/* Fluent's type ramp: Semibold (600) tops out the hierarchy - the old 800s
   were shouting. Size and spacing carry the hierarchy instead of weight. */
h1, h2, h3 { line-height: 1.25; letter-spacing: -.01em; margin: 0 0 var(--s3); }
h1 { font-family: var(--font-display); font-size: 26px; font-weight: 600; }
h2 { font-size: 18px; font-weight: 600; }
h3 { font-size: 15px; font-weight: 600; }
p  { margin: 0 0 var(--s3); }
p:last-child { margin-bottom: 0; }
small { font-size: 12.5px; color: var(--text-muted); }

a { color: var(--accent-text); text-decoration-thickness: 1px; text-underline-offset: 2px; }

::selection { background: var(--accent-soft); color: var(--text); }

/* Fluent's focus rectangle: a dark ring with a light gap, so it stays visible
   on any surface, accent or neutral, in either theme. */
:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--surface);
  border-radius: var(--r-sm);
}

main {
  max-width: 760px;
  margin: 0 auto;
  padding: var(--s4) var(--s4) calc(var(--tabbar-h) + var(--s8) + env(safe-area-inset-bottom));
}

/* --------------------------------------------------------------------------
   3. Icons
   -------------------------------------------------------------------------- */
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.icon {
  width: 24px;
  height: 24px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: middle;
}
.icon-sm { width: 18px; height: 18px; stroke-width: 1.9; }
.icon-lg { width: 32px; height: 32px; stroke-width: 1.5; }
.icon-xl { width: 46px; height: 46px; stroke-width: 1.3; }

/* --------------------------------------------------------------------------
   4. Top bar
   -------------------------------------------------------------------------- */
/* Windows 11 app chrome is the same tone as the page it sits above, separated
   by a hairline rather than a slab of colour. The old dark bar read as a
   website header; this reads as an application. */
header.nav {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--bg);
  color: var(--text);
  padding: env(safe-area-inset-top) var(--s4) 0;
  border-bottom: 1px solid var(--line);
  box-shadow: none;
}
.nav-inner {
  max-width: 760px;
  margin: 0 auto;
  min-height: 56px;
  display: flex;
  align-items: center;
  gap: var(--s3);
}
.nav-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: 0;
  color: var(--text);
  text-decoration: none;
  margin-right: auto;
}
.nav-mark {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: #fff;
}
.nav-mark .icon { width: 18px; height: 18px; stroke-width: 1.9; }

.nav-links { display: none; align-items: center; gap: var(--s1); }
/* NavigationView items: the selected one is marked by an accent bar, not by a
   filled pill. That indicator is how Windows 11 shows "you are here". */
.nav-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 40px;
  padding: 0 var(--s3);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  text-decoration: none;
  font-size: 14px;
  font-weight: 400;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.nav-link:hover { background: var(--bg-tint); color: var(--text); }
.nav-link.active { color: var(--text); background: var(--bg-tint); font-weight: 600; }
.nav-link.active::after {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: -1px;
  width: 18px;
  height: 3px;
  border-radius: 2px;
  background: var(--accent);
}
.nav-link .icon { width: 18px; height: 18px; }

/* Compact right-side action on mobile (e.g. Accounts) */
.nav-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 44px;
  min-height: 40px;
  padding: 0 var(--s3);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--line);
  text-decoration: none;
  font-size: 14px;
  font-weight: 400;
}
.nav-action:hover { color: var(--text); background: var(--surface); }

/* The person chip: avatar + who you are, opening Profile. On the rail it sits
   at the bottom the way Windows 11 parks the account entry; on a phone it is
   the top-right avatar every app puts there. */
.nav-me {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 40px;
  padding: 0 var(--s2);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  text-decoration: none;
  font-size: 14px;
}
.nav-me:hover { background: var(--bg-tint); color: var(--text); }
.avatar {
  width: 30px; height: 30px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
  background-size: cover;
  background-position: center;
}
.nav-me-label { display: none; }

/* --- "The AI is not sure" ------------------------------------------------ */
/* A doubtful field is marked by an amber underline AND named in the panel
   above it, never by colour alone. */
input.is-doubtful { border-bottom: 2px solid var(--warn); padding-bottom: 9px; }
.doubt-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); margin-top: var(--s2); }
.doubt-field { font-size: 13px; font-weight: 600; }
button.doubt-opt {
  min-height: 34px;
  padding: 4px var(--s3);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
button.doubt-opt.is-chosen { border-color: var(--accent); color: var(--accent-text); }

/* --- Charts -------------------------------------------------------------- */
.chart-legend { display: flex; flex-wrap: wrap; gap: var(--s4); margin-bottom: var(--s3); }
.chart-key { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-muted); }
.chart-swatch { width: 10px; height: 10px; border-radius: 2px; flex: none; }
.chart-svg { display: block; width: 100%; height: 200px; overflow: visible; }

.chart-table { margin-top: var(--s3); }
.chart-table summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--text-muted);
  padding: var(--s1) 0;
}
.chart-table table { width: 100%; border-collapse: collapse; margin-top: var(--s2); font-size: 13.5px; }
.chart-table th, .chart-table td { padding: 6px var(--s2); border-bottom: 1px solid var(--line); text-align: left; }
.chart-table td:not(:first-child), .chart-table th:not(:first-child) { text-align: right; font-variant-numeric: tabular-nums; }

/* Ranked horizontal bars. Length is read far more accurately than angle, which
   is why this is not a pie - and a Schedule C has nineteen categories. */
.catbars { display: grid; gap: var(--s3); }
.catbar {
  display: grid;
  grid-template-columns: minmax(120px, 1.4fr) minmax(60px, 2fr) auto auto;
  align-items: center;
  gap: var(--s3);
}
.catbar-name { font-size: 13.5px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.catbar-track { display: block; height: 10px; border-radius: 2px; background: var(--bg-tint); overflow: hidden; }
.catbar-fill { display: block; height: 100%; border-radius: 2px; background: var(--series-out); }
.catbar-val { font-size: 13.5px; font-variant-numeric: tabular-nums; font-weight: 600; text-align: right; }
.catbar-share { font-size: 12.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; min-width: 34px; text-align: right; }
@media (max-width: 560px) {
  .catbar { grid-template-columns: 1fr auto; row-gap: var(--s1); }
  .catbar-track { grid-column: 1 / -1; }
  .catbar-share { display: none; }
}

/* Indicator tiles: a small row of the figures that decide what to do next. */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--s3); }
.kpi {
  padding: var(--s3) var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
.kpi-label { display: block; font-size: 12.5px; color: var(--text-muted); }
.kpi-val { display: block; font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; margin-top: 2px; }
.kpi-val.pos { color: var(--pos); }
.kpi-val.neg { color: var(--neg); }
.kpi a { text-decoration: none; }

.profile-id { display: flex; align-items: center; gap: var(--s4); }
.avatar-lg { width: 64px; height: 64px; font-size: 22px; }
.profile-email { display: block; font-size: 16px; font-weight: 600; word-break: break-all; }

/* --- Desktop: NavigationView rail ---------------------------------------
   Wave puts its sections in a left sidebar and so does Windows 11. Same
   answer from both directions, so the rail is the desktop layout. */
@media (min-width: 1024px) {
  header.nav {
    position: fixed;
    inset: 0 auto 0 0;
    width: 220px;
    padding: var(--s4) var(--s3);
    border-bottom: 0;
    border-right: 1px solid var(--line);
    overflow-y: auto;
  }
  .nav-inner {
    max-width: none;
    min-height: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: var(--s5);
  }
  .nav-brand { margin: 0 0 0 var(--s2); font-size: 17px; }
  .nav-links { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
  .nav-link { min-height: 40px; justify-content: flex-start; gap: var(--s3); padding: 0 var(--s3); }
  /* On a vertical rail the selection indicator runs down the left edge. */
  .nav-link.active::after {
    left: 0;
    bottom: auto;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 18px;
  }
  .nav-me { margin-top: auto; padding: var(--s2); }
  .nav-me-label { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  main { margin-left: 220px; max-width: 1100px; padding: var(--s6) var(--s7) var(--s8); }
  .tabbar { display: none; }
}

/* Between phone and rail: horizontal links in the top bar. */
@media (min-width: 768px) and (max-width: 1023px) {
  .nav-links { display: flex; }
  main { padding-bottom: var(--s8); }
  .tabbar { display: none; }
}

/* --------------------------------------------------------------------------
   5. Bottom tab bar (mobile)
   -------------------------------------------------------------------------- */
.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 50;
  display: flex;
  align-items: flex-start;
  justify-content: space-around;
  gap: 2px;
  height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  padding: 6px var(--s2) env(safe-area-inset-bottom);
  background: var(--surface);
  border-top: 1px solid var(--line);
  box-shadow: 0 -1px 3px rgba(0, 0, 0, .06);
}
@media (prefers-color-scheme: dark) {
  .tabbar { box-shadow: 0 -1px 3px rgba(0, 0, 0, .4); }
}

.tab {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  min-height: 50px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 4px 2px;
  border-radius: var(--r-md);
  color: var(--text-muted);
  text-decoration: none;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .01em;
  transition: color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.tab .icon { width: 23px; height: 23px; }
.tab:active { opacity: .6; }
.tab.active { color: var(--accent-text); }
.tab.active::before {
  content: "";
  position: absolute;
  top: -6px;
  width: 26px; height: 3px;
  border-radius: var(--r-full);
  background: var(--accent);
  animation: tab-in var(--dur) var(--ease) both;
}

/* Center raised Snap action */
.tab-snap {
  flex: 0 0 auto;
  width: 64px;
  color: var(--text-muted);
}
.tab-snap .snap-orb {
  width: 54px; height: 54px;
  margin-top: -22px;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--sh-accent), 0 0 0 5px var(--surface);
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur) var(--ease);
}
.tab-snap .snap-orb .icon { width: 27px; height: 27px; stroke-width: 1.8; }
.tab-snap:active .snap-orb { background: var(--accent-press); }
.tab-snap span { margin-top: -2px; }
.tab-snap.active { color: var(--accent-text); }
.tab-snap.active::before { display: none; }

@media (min-width: 768px) {
  .tabbar { display: none; }
}

@keyframes tab-in { from { transform: scaleX(.2); opacity: 0; } to { transform: scaleX(1); opacity: 1; } }

/* --------------------------------------------------------------------------
   6. Cards & layout helpers
   -------------------------------------------------------------------------- */
/* Fluent card: 8px corners, a hairline stroke doing the separation, and only
   the faintest shadow. Elevation in Win11 is a whisper, not a lift. */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: var(--s5);
  margin-bottom: var(--s4);
  box-shadow: var(--sh-1);
  animation: rise var(--dur-slow) var(--ease) both;
}
.card > :last-child { margin-bottom: 0; }
.card-tight { padding: var(--s3); }
.card-flush { padding: var(--s2) var(--s3); }

/* Staggered entrance, capped at 5 items */
.card:nth-of-type(1) { animation-delay: 0ms; }
.card:nth-of-type(2) { animation-delay: 45ms; }
.card:nth-of-type(3) { animation-delay: 90ms; }
.card:nth-of-type(4) { animation-delay: 135ms; }
.card:nth-of-type(n+5) { animation-delay: 175ms; }

@keyframes rise {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

.card-head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-bottom: var(--s4);
}
.card-head h2, .card-head h1 { margin: 0; }
.card-head .icon { color: var(--accent-text); }
.card-head .spacer { margin-left: auto; }

.eyebrow {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--s1);
}

.row { display: flex; gap: var(--s3); flex-wrap: wrap; }
.row > * { flex: 1 1 140px; min-width: 0; }
.stack > * + * { margin-top: var(--s3); }
.muted { color: var(--text-muted); }
.center { text-align: center; }

hr.rule { border: 0; border-top: 1px solid var(--line); margin: var(--s4) 0; }

/* --------------------------------------------------------------------------
   7. Buttons
   -------------------------------------------------------------------------- */
/* Fluent controls: 4px corners, Semibold label, and a bottom stroke a shade
   darker than the sides. That asymmetric stroke is what gives a Windows 11
   button its slight physical lift without a drop shadow doing the work. */
button, .btn {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: 44px;
  padding: 10px var(--s5);
  border: 1px solid var(--accent-press);
  border-bottom-width: 2px;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--on-accent);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0;
  text-decoration: none;
  cursor: pointer;
  box-shadow: none;
  transition: background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              opacity var(--dur-fast) var(--ease);
}
button:hover, .btn:hover { background: var(--accent-hi); }
/* Fluent presses inward by flattening the bottom stroke, never by scaling. */
button:active, .btn:active {
  background: var(--accent-press);
  border-bottom-width: 1px;
  padding-top: 11px;
}
button:disabled, .btn[aria-disabled="true"] {
  opacity: .45;
  cursor: not-allowed;
  border-bottom-width: 1px;
  padding-top: 10px;
}

button.big, .btn.big { width: 100%; min-height: 48px; font-size: 15.5px; padding: 12px var(--s5); }
button.big:active, .btn.big:active { padding-top: 13px; }

button.secondary, .btn.secondary,
button.quiet, .btn.quiet {
  background: var(--surface);
  color: var(--text);
  border-color: var(--line-strong);
  border-bottom-color: var(--line-bottom);
}
button.secondary:hover, .btn.secondary:hover,
button.quiet:hover, .btn.quiet:hover { background: var(--surface-2); }
button.secondary:active, .btn.secondary:active,
button.quiet:active, .btn.quiet:active { background: var(--bg-tint); color: var(--text-muted); }

button.ghost, .btn.ghost {
  background: transparent;
  color: var(--accent-text);
  border-color: transparent;
}
button.ghost:hover, .btn.ghost:hover { background: var(--accent-soft); }
button.ghost:active, .btn.ghost:active { background: var(--accent-soft); opacity: .7; padding-top: 10px; }

button.danger, .btn.danger {
  background: var(--surface);
  color: var(--danger);
  border-color: var(--line-strong);
  border-bottom-color: var(--line-bottom);
}
button.danger:hover, .btn.danger:hover { background: var(--danger-soft); border-color: var(--danger); }
button.danger:active, .btn.danger:active { background: var(--danger-soft); opacity: .8; }

/* Square icon-only button — still 44px tap target */
button.icon-btn, .btn.icon-btn {
  width: 44px;
  min-height: 44px;
  padding: 0;
  border-radius: var(--r-sm);
}
button.icon-btn:active, .btn.icon-btn:active { padding-top: 0; }

.btn-row { display: flex; gap: var(--s2); flex-wrap: wrap; }
.btn-row > .btn, .btn-row > button { flex: 1 1 auto; }

/* --------------------------------------------------------------------------
   8. Forms
   -------------------------------------------------------------------------- */
label {
  display: block;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text-muted);
  margin-bottom: var(--s1);
}

/* Fluent text fields: hairline box, a darker bottom stroke at rest, and on
   focus that bottom stroke thickens into the accent. The accent underline is
   the single most recognisable control in Windows 11, and it reads as focus
   without the halo a glow would add. */
input, select, textarea {
  width: 100%;
  min-height: 44px;
  padding: 10px var(--s3);
  font: inherit;
  font-size: 16px; /* prevents iOS zoom-on-focus */
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line-bottom);
  border-radius: var(--r-sm);
  margin: 0 0 var(--s4);
  transition: border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
input:hover, select:hover, textarea:hover { background: var(--surface-2); }
input:focus, select:focus, textarea:focus {
  background: var(--surface);
  border-color: var(--line-strong);
  border-bottom: 2px solid var(--accent);
  padding-bottom: 9px; /* hold the box height as the underline thickens */
  outline: none;
  box-shadow: none;
}
input::placeholder { color: var(--text-muted); opacity: .9; }

select {
  -webkit-appearance: none;
  appearance: none;
  padding-right: 38px;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 19px) 50%, calc(100% - 13px) 50%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

input[type="checkbox"], input[type="radio"] {
  width: 22px;
  height: 22px;
  min-height: 0;
  margin: 0;
  accent-color: var(--accent);
  flex: none;
}
input[type="file"] {
  padding: 10px var(--s3);
  background: var(--surface-2);
  border-style: dashed;
  cursor: pointer;
}
input[type="file"]::file-selector-button {
  -webkit-appearance: none;
  appearance: none;
  margin-right: var(--s3);
  padding: 8px var(--s4);
  min-height: 36px;
  border: 0;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--on-accent);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
input[type="date"] { min-width: 0; }

/* label + control pair */
.field { margin-bottom: var(--s4); }
.field > input, .field > select { margin-bottom: 0; }
.field-hint { font-size: 12.5px; color: var(--text-muted); margin: var(--s1) 0 0; }

/* Checkbox rows get a 44px tap target */
.check {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 44px;
  padding: var(--s2) var(--s3);
  border: 1.5px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  margin-bottom: 0;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.check:hover { border-color: var(--line-strong); }
.check:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }

/* Collapsible filter bar */
details.filters { border-radius: var(--r-lg); }
details.filters > summary {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: 44px;
  list-style: none;
  cursor: pointer;
  font-weight: 600;
  font-size: 15px;
  color: var(--text);
  border-radius: var(--r-sm);
}
details.filters > summary::-webkit-details-marker { display: none; }
details.filters > summary .chev {
  margin-left: auto;
  color: var(--text-muted);
  transition: transform var(--dur) var(--ease);
}
details.filters[open] > summary .chev { transform: rotate(180deg); }
details.filters > summary .icon:first-child { color: var(--accent-text); }
.filters-body { padding-top: var(--s4); animation: rise var(--dur) var(--ease) both; }

/* --------------------------------------------------------------------------
   9. Money & numbers
   -------------------------------------------------------------------------- */
.money, .amount, .num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  letter-spacing: -.01em;
}
.amount { text-align: right; }
.income, .pos { color: var(--pos); }
.expense, .neg { color: var(--neg); }

.money-hero {
  display: block;
  font-size: clamp(38px, 12vw, 52px);
  font-weight: 600;
  letter-spacing: -.035em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
  margin: var(--s1) 0 var(--s2);
}

/* --------------------------------------------------------------------------
   10. Chips, badges, banners
   -------------------------------------------------------------------------- */
.chip, .badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: var(--r-full);
  background: var(--chip-bg);
  color: var(--chip-text);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
}
.badge, .chip-warn {
  background: var(--warn-soft);
  color: var(--warn);
  border: 1px solid var(--warn-line);
}
.chip-accent { background: var(--accent-soft); color: var(--accent-text); }

/* Tappable chip (review queue) */
a.chip-link {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 52px;
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  background: var(--warn-soft);
  border: 1px solid var(--warn-line);
  color: var(--warn);
  text-decoration: none;
  font-weight: 600;
  font-size: 14.5px;
  transition: transform var(--dur-fast) var(--ease), filter var(--dur) var(--ease);
}
a.chip-link:active { transform: scale(.985); }
a.chip-link > span { flex: 1 1 auto; min-width: 0; }
a.chip-link .go { margin-left: auto; flex: none; }
a.chip-link .badge { background: rgba(0,0,0,.07); border-color: transparent; }
@media (prefers-color-scheme: dark) {
  a.chip-link .badge { background: rgba(255,255,255,.12); }
}

.banner {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-size: 14.5px;
  margin-bottom: var(--s3);
}
.banner .icon { flex: none; margin-top: 1px; }
.banner-warn { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.banner-ok   { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-text); }
.banner-bad  { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }

.error {
  color: var(--danger);
  font-size: 14px;
  font-weight: 600;
  margin: var(--s2) 0 0;
}
.error:empty { display: none; margin: 0; }

/* --------------------------------------------------------------------------
   11. Tables (statement style)
   -------------------------------------------------------------------------- */
table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
td, th {
  padding: 10px var(--s2);
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: middle;
}
th { font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted); }
tr:last-child td, tr:last-child th { border-bottom: 0; }
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--r-md); }
.scroll-x table { min-width: 100%; white-space: nowrap; }

/* Statement rows (P&L, month summary) */
.stmt { display: block; }
.stmt-row {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
}
.stmt-row:last-child { border-bottom: 0; }
.stmt-row .lbl { color: var(--text-muted); font-weight: 600; }
.stmt-row .val { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 600; }
/* The ruled total, straight out of accounting typography: one hairline above
   the figure, a double rule beneath it. Bookkeepers have closed columns this
   way on paper for a century, and no software in this category bothers. It
   costs two borders and it is the detail that tells a customer's accountant
   this was built by someone who knows the work. */
.stmt-total {
  margin-top: var(--s2);
  padding-top: var(--s3);
  padding-bottom: var(--s2);
  border-top: 1px solid var(--text);
  border-bottom: 3px double var(--text);
  font-size: 17px;
}
.stmt-total .lbl { color: var(--text); font-weight: 600; }
.stmt-total .val { font-size: 22px; font-weight: 600; letter-spacing: -.02em; }

/* Every figure in a column lines up: tabular figures are measurement, not a
   monospace costume. */
.stmt .val, .amount, .money-hero, .tx-amount, td { font-variant-numeric: tabular-nums; }

/* The Schedule C line number, carried beside a category wherever one appears.
   It is the product's actual differentiator - the chart of accounts IS the tax
   form - so it earns a persistent mark rather than living buried in a report. */
.sc-line {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 5px;
  margin-left: var(--s2);
  border: 1px solid var(--line-strong);
  border-radius: 3px;
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  vertical-align: middle;
}

/* --------------------------------------------------------------------------
   12. Transaction rows
   -------------------------------------------------------------------------- */
.txlist { display: block; }
.tx {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--s1) var(--s3);
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--line);
  animation: rise var(--dur) var(--ease) both;
}
.tx:last-child { border-bottom: 0; padding-bottom: 0; }
.tx:first-child { padding-top: 0; }
.tx-vendor {
  font-weight: 600;
  font-size: 15.5px;
  letter-spacing: -.01em;
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
}
.tx-vendor a { color: var(--text-muted); display: inline-flex; }
.tx-vendor a:hover { color: var(--accent-text); }
.tx-amount {
  grid-column: 2;
  grid-row: 1;
  text-align: right;
  font-weight: 600;
  font-size: 16px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.015em;
  white-space: nowrap;
}
.tx-date { font-size: 12.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tx-foot {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--s2);
  margin-top: var(--s1);
}
.tx-foot .cat-select { flex: 1 1 auto; min-width: 0; }

/* Category select styled as a soft chip */
select.cat-select {
  min-height: 44px;
  margin: 0;
  padding: 8px 32px 8px var(--s4);
  font-size: 13.5px;
  font-weight: 600;
  border-radius: var(--r-full);
  border: 1.5px solid var(--line);
  background-color: var(--chip-bg);
  color: var(--chip-text);
  background-position: calc(100% - 17px) 50%, calc(100% - 11px) 50%;
}
select.cat-select:hover { border-color: var(--line-strong); }
select.cat-select.is-unset { background-color: var(--warn-soft); color: var(--warn); border-color: var(--warn-line); }

.tx-del {
  width: 44px; min-height: 44px;
  padding: 0;
  border-radius: var(--r-full);
  background: transparent;
  border: 1.5px solid var(--line);
  color: var(--text-muted);
  box-shadow: none;
}
.tx-del:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }

/* Transfer rows: neutral icon button (undo is not destructive) + label fills
   the select's slot so the delete button stays right-aligned with the list. */
.tx-undo {
  width: 44px; min-height: 44px;
  padding: 0;
  border-radius: var(--r-full);
  background: transparent;
  border: 1.5px solid var(--line);
  color: var(--text-muted);
  box-shadow: none;
}
.tx-undo:hover { background: var(--bg-tint); border-color: var(--line-strong); color: var(--text); }
.tx-foot .tx-transfer-label { flex: 1 1 auto; min-width: 0; font-size: 13.5px; color: var(--text-muted); }

/* --------------------------------------------------------------------------
   13. Account cards
   -------------------------------------------------------------------------- */
.acct-grid { display: grid; gap: var(--s3); grid-template-columns: 1fr; }
@media (min-width: 560px) { .acct-grid { grid-template-columns: 1fr 1fr; } }

.acct {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  animation: rise var(--dur) var(--ease) both;
}
.acct-icon {
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--accent-soft);
  color: var(--accent-text);
  flex: none;
}
.acct > span:last-child { min-width: 0; flex: 1 1 auto; }
.acct-name { display: block; font-weight: 600; font-size: 15.5px; letter-spacing: -.01em; }
.acct-meta { display: block; font-size: 12.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   14. Home hero
   -------------------------------------------------------------------------- */
.hero-snap {
  display: flex;
  align-items: center;
  gap: var(--s4);
  width: 100%;
  padding: var(--s5);
  margin-bottom: var(--s4);
  /* The primary action reads as a raised layer, not as a darker hole. On dark
     the old near-black fill sat below the page tone and vanished; a surface
     with an accent stroke works in both themes. */
  border: 1px solid var(--accent);
  border-radius: var(--r-md);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  text-align: left;
  box-shadow: var(--sh-1);
  animation: rise var(--dur-slow) var(--ease) both;
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur) var(--ease);
}
.hero-snap:hover { background: var(--accent-soft); box-shadow: var(--sh-1); }
.hero-snap:active { background: var(--accent-soft); opacity: .85; }
.hero-orb {
  width: 60px; height: 60px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--accent);
  color: #fff;
  flex: none;
  box-shadow: var(--sh-accent);
}
.hero-orb .icon { width: 30px; height: 30px; stroke-width: 1.7; }
.hero-snap > span { min-width: 0; }
.hero-title { display: block; font-size: 19px; font-weight: 600; letter-spacing: -.02em; }
.hero-sub { display: block; font-size: 13.5px; color: var(--text-muted); margin-top: 2px; }
.hero-snap .go { margin-left: auto; color: var(--on-brand-dim); }

/* Quick links grid */
/* Quick actions, in the shape Wave uses on its dashboard: one wide row of
   tinted actions, icon beside label rather than stacked. Kept in Fluent's
   surface language - 4px corners, hairline stroke, flat tint - so it reads as
   a Windows control strip rather than a row of pastel web buttons. */
.quick { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2); }
.quick a {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: 48px;
  padding: var(--s3);
  border: 1px solid var(--line);
  border-bottom-color: var(--line-bottom);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.quick a .icon { color: var(--accent-text); width: 20px; height: 20px; }
.quick a:hover { background: var(--accent-soft); border-color: var(--accent); }
.quick a:active { background: var(--accent-soft); opacity: .8; }
@media (max-width: 520px) {
  .quick { grid-template-columns: 1fr 1fr; }
  .quick a { flex-direction: column; gap: 6px; min-height: 76px; text-align: center; font-size: 12.5px; }
}

/* --------------------------------------------------------------------------
   15. Snap: dropzone + stepper
   -------------------------------------------------------------------------- */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s3);
  width: 100%;
  min-height: 236px;
  padding: var(--s6) var(--s4);
  border: 2.5px dashed var(--line-strong);
  border-radius: var(--r-lg);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  text-align: center;
  box-shadow: none;
  font: inherit;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.dropzone:hover { background: var(--accent-soft); border-color: var(--accent); }
.dropzone:active { transform: scale(.99); background: var(--accent-soft); }
.dropzone.is-over { border-color: var(--accent); background: var(--accent-soft); border-style: solid; }
.dropzone:disabled { opacity: .6; }
.dropzone-orb {
  width: 76px; height: 76px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--accent);
  color: #fff;
  box-shadow: var(--sh-accent);
}
.dropzone-orb .icon { width: 36px; height: 36px; stroke-width: 1.6; }
.dropzone-title { font-size: 17px; font-weight: 600; letter-spacing: -.01em; }
.dropzone-sub { font-size: 13.5px; color: var(--text-muted); font-weight: 500; }

/* 3-step progress */
.steps {
  display: flex;
  align-items: flex-start;
  gap: var(--s1);
  margin: var(--s4) 0 0;
  padding: 0;
  list-style: none;
}
.step {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  position: relative;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
  text-align: center;
}
.step .dot {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  border: 2px solid var(--line-strong);
  background: var(--surface);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  z-index: 1;
  transition: all var(--dur) var(--ease);
}
.step .dot .icon { width: 15px; height: 15px; stroke-width: 2.4; }
.step::after {
  content: "";
  position: absolute;
  top: 12px;
  left: calc(50% + 18px);
  right: calc(-50% + 18px);
  height: 2px;
  background: var(--line-strong);
}
.step:last-child::after { display: none; }

.step.is-done { color: var(--accent-text); }
.step.is-done .dot { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.step.is-done::after { background: var(--accent); }

.step.is-current { color: var(--accent-text); }
.step.is-current .dot {
  border-color: var(--accent);
  color: var(--accent-text);
  animation: pulse 1.4s var(--ease) infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 var(--accent-soft); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.status-line {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: 22px;
  margin: var(--s4) 0 0;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
}
.status-line:empty { display: none; }

.preview-frame {
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--surface-2);
  margin-bottom: var(--s4);
}
.preview-frame:empty { display: none; }
#preview { display: block; width: 100%; max-width: 100%; }

/* --------------------------------------------------------------------------
   16. Import stepper + duplicate cards
   -------------------------------------------------------------------------- */
.dup-card {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  margin-bottom: var(--s2);
  border: 1.5px solid var(--warn-line);
  border-radius: var(--r-md);
  background: var(--warn-soft);
  cursor: pointer;
  font-weight: 500;
  color: var(--text);
  transition: border-color var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.dup-card:has(input:checked) { opacity: .62; border-style: dashed; }
.dup-card .dup-body { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; }
.dup-card .dup-desc { font-weight: 600; font-size: 14.5px; overflow-wrap: anywhere; }
.dup-card .dup-meta { font-size: 12.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.dup-card .dup-amt { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.dup-list { list-style: none; margin: var(--s3) 0 0; padding: 0; }

.facts { list-style: none; margin: 0; padding: 0; }
.facts li {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-size: 14.5px;
}
.facts li:last-child { border-bottom: 0; }
.facts .n {
  flex: none;
  min-width: 40px;
  font-weight: 600;
  font-size: 17px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.facts .n-accent { color: var(--accent-text); }

/* --------------------------------------------------------------------------
   17. Reports: category bars + package card
   -------------------------------------------------------------------------- */
.bars { display: block; }
.bar-item { padding: var(--s3) 0; border-bottom: 1px solid var(--line); animation: rise var(--dur) var(--ease) both; }
.bar-item:last-child { border-bottom: 0; padding-bottom: 0; }
.bar-item:first-child { padding-top: 0; }
.bar-head {
  display: flex;
  align-items: baseline;
  gap: var(--s3);
  margin-bottom: 7px;
  font-size: 14.5px;
}
.bar-head .bar-name { font-weight: 600; }
.bar-head .bar-val { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; }
.bar-track {
  height: 9px;
  border-radius: var(--r-full);
  background: var(--bg-tint);
  overflow: hidden;
}
.bar-fill {
  height: 100%;
  border-radius: var(--r-full);
  background: var(--accent);
  transform-origin: left center;
  animation: bar-grow var(--dur-slow) var(--ease) both;
}
@keyframes bar-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.pkg-card {
  background: var(--brand);
  border-color: transparent;
  color: var(--on-brand);
}
.pkg-card h2 { color: var(--on-brand); }
.pkg-card p { color: var(--on-brand-dim); font-size: 14.5px; }
.pkg-card .card-head .icon { color: #fff; }
.pkg-card .error { color: var(--warn); }
.pkg-card .btn { background: var(--accent); color: var(--on-accent); }
.pkg-card .btn:hover { background: var(--accent-hi); }
.pkg-icon {
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: rgba(255,255,255,.10);
  color: #fff;
  flex: none;
}

/* --------------------------------------------------------------------------
   18. Empty states & skeletons
   -------------------------------------------------------------------------- */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
  padding: var(--s7) var(--s4);
  text-align: center;
  color: var(--text-muted);
}
.empty-icon {
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--accent-text);
  margin-bottom: var(--s1);
}
.empty-title { font-size: 16px; font-weight: 600; color: var(--text); }
.empty-hint { font-size: 14px; max-width: 34ch; }
.empty a { font-weight: 600; }

.skel-list { display: block; }
.skel {
  height: 12px;
  border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--bg-tint) 25%, var(--surface-2) 37%, var(--bg-tint) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.3s linear infinite;
}
.skel-row {
  display: grid;
  grid-template-columns: 1fr 84px;
  gap: 10px var(--s3);
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--line);
}
.skel-row .skel:nth-child(1) { width: 62%; height: 14px; }
.skel-row .skel:nth-child(2) { width: 100%; }
.skel-row .skel:nth-child(3) { width: 42%; height: 10px; grid-column: 1 / -1; }
@keyframes shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

/* --------------------------------------------------------------------------
   19. Toasts
   -------------------------------------------------------------------------- */
.toast-wrap {
  position: fixed;
  left: 50%;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + var(--s3));
  transform: translateX(-50%);
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  align-items: center;
  width: max-content;
  max-width: min(92vw, 420px);
  pointer-events: none;
}
@media (min-width: 768px) { .toast-wrap { bottom: var(--s6); } }

.toast {
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: 12px var(--s5);
  border-radius: var(--r-full);
  background: var(--brand);
  color: var(--on-brand);
  font-size: 14.5px;
  font-weight: 600;
  box-shadow: var(--sh-3);
  animation: toast-in var(--dur) var(--ease) both;
}
.toast-ok { background: var(--accent); color: var(--on-accent); }
.toast-out { animation: toast-out 220ms var(--ease) both; }
@keyframes toast-in  { from { opacity: 0; transform: translateY(12px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateY(8px) scale(.97); } }

/* --------------------------------------------------------------------------
   20. Login
   -------------------------------------------------------------------------- */
.login-wrap {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s5);
  background:
    var(--bg);
}
.login-card { width: 100%; max-width: 400px; padding: var(--s6); margin: 0; }
.login-mark {
  width: 60px; height: 60px;
  display: grid; place-items: center;
  border-radius: var(--r-lg);
  background: var(--accent);
  color: #fff;
  box-shadow: var(--sh-accent);
  margin-bottom: var(--s4);
}
.login-mark .icon { width: 32px; height: 32px; }
.login-card h1 { font-size: 30px; margin-bottom: var(--s2); }

/* --------------------------------------------------------------------------
   21. Utilities
   -------------------------------------------------------------------------- */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.hidden { display: none !important; }

/* --------------------------------------------------------------------------
   22. Reduced motion — kill all animation
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .card, .tx, .acct, .bar-item, .hero-snap, .filters-body { animation: none !important; opacity: 1 !important; transform: none !important; }
  .bar-fill { animation: none !important; transform: none !important; }
  button:active, .btn:active, .tab:active, .quick a:active, .dropzone:active { transform: none !important; }
}

/* --------------------------------------------------------------------------
   Legal documents (terms.html, privacy.html)
   Long-form reading, not app chrome. Deliberately carries no inline <style>
   and no inline <script>: these two pages are already clean under a strict
   CSP, so they will not need touching when script-src drops 'unsafe-inline'.
   -------------------------------------------------------------------------- */
.legal {
  max-width: 46rem;              /* ~75 characters - a comfortable measure */
  margin: 0 auto;
  padding: var(--s6) var(--s5) var(--s8);
}
.legal-head { border-bottom: 1px solid var(--line); margin-bottom: var(--s6); padding-bottom: var(--s4); }
.legal-head h1 { margin: 0 0 var(--s2); }
.legal-updated { color: var(--text-muted); font-size: .875rem; margin: 0; }
.legal h2 {
  font-size: 1.0625rem;
  font-weight: 600;
  margin: var(--s6) 0 var(--s2);
  padding-top: var(--s2);
  border-top: 1px solid var(--line);
}
.legal h2:first-of-type { border-top: 0; padding-top: 0; }
.legal p, .legal li { line-height: 1.65; }
.legal ul { padding-left: 1.25rem; }
.legal li { margin-bottom: var(--s2); }
.legal a { color: var(--accent-text); }
.legal strong { font-weight: 600; }
/* Points a reader must not skim past - plain-language summaries of the parts
   that cost them money or data. */
.legal-callout {
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  padding: var(--s3) var(--s4);
  margin: var(--s4) 0;
  border-radius: 0 4px 4px 0;
}
.legal-callout p:last-child { margin-bottom: 0; }
.legal-nav { display: flex; gap: var(--s4); margin-top: var(--s7); padding-top: var(--s4); border-top: 1px solid var(--line); }
/* Small print under a form. Used on signup and subscribe. */
.small { font-size: .8125rem; }

/* --- Utilities ----------------------------------------------------------- */

/* `hidden` has to beat anything we set, and it did not.
   The browser's own rule is [hidden] { display: none }, which any later
   `display` declaration outranks - and `button, .btn { display: inline-flex }`
   above does exactly that. The result was a button marked hidden sitting in
   plain sight: "Remove photo" showed on the profile page for an account with no
   photo. This affects every hidden button in the app, not just that one. */
[hidden] { display: none !important; }

/* Present for the browser and screen readers, invisible on screen.
   Used for the username field that has to sit beside a password field so a
   password manager knows which account it is filling - see profile.html. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Inbox */
.hint { display: block; font-size: 12.5px; color: var(--text-muted); }
.drop { display: block; border: 2px dashed var(--line-strong); border-radius: var(--r-lg);
  padding: 28px; text-align: center; cursor: pointer; }
.drop:hover { background: var(--accent-soft); border-color: var(--accent); }
.drop .hint { margin-top: 6px; }
.inbox-row { border-bottom: 1px solid var(--line); padding: 10px 0; }
.inbox-row:last-child { border-bottom: 0; }
.inbox-head { display: flex; gap: 8px; align-items: center; }
.inbox-file { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.inbox-line { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 4px; color: var(--text-muted); font-size: 13.5px; }
.inbox-actions { display: flex; gap: 8px; margin-top: 6px; }
.inbox-edit { display: grid; gap: 6px; margin-top: 8px; }

/* Category suggestions on the Purchases page */
.sug-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--grid); flex-wrap: wrap; }
.sug-row:last-of-type { border-bottom: 0; }
.sug-merchant { font-weight: 600; text-transform: capitalize; }
.sug-row button { margin-left: auto; }
.sug-all { margin-top: 12px; }

/* Cash box on the Banking page */
.cash-line { display: flex; justify-content: space-between; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--grid); }
.cash-line:last-of-type { border-bottom: 0; }

/* Money coming in, on the Reports page. Green, because green already means one
   thing in this app and only one thing: money arriving. The expense bars beside
   these stay accent-blue, so the two directions never have to be read off a
   label alone. */
.bar-fill-in { background: var(--series-in); }
.sub-head { font-size: 14px; font-weight: 700; margin: var(--s5) 0 var(--s2); }
#incomeCustomers .stmt-row .lbl small { display: block; font-weight: 400; color: var(--text-muted); }

/* Invoices. The line editor is a description that takes the room, then a small
   quantity and price beside it - the shape of every paper invoice ever written. */
.inv-line { align-items: start; gap: var(--s2); }
.inv-line .field { margin-bottom: var(--s2); }
.inv-line .inv-qty { flex: 0 1 90px; }
.inv-line .inv-price { flex: 0 1 130px; }
.inv-line .tx-del { flex: 0 0 auto; margin-top: 0; }
.field-label { display: block; font-size: 13px; font-weight: 600; color: var(--text-muted); margin-bottom: var(--s2); }
/* Late is the one status that has to carry past a glance, so it gets the
   danger tint rather than the neutral chip every other state uses. */
.chip-late { background: var(--danger-soft); color: var(--danger); }

/* "remembered" on a Purchases row: this category came from a merchant you
   taught it earlier. Quiet on purpose - it will sit on most rows once the app
   has learned a few shops, and a loud badge repeated forty times reads as
   noise rather than as information. */
.badge-remembered { background: var(--accent-soft); color: var(--accent-text); }

/* Loans on the Banking page */
.loan-item + .loan-item { margin-top: var(--s5); padding-top: var(--s5); border-top: 1px solid var(--line); }
.loan-name { font-weight: 700; font-size: 16px; margin-bottom: var(--s2); }
.loan-item .muted { font-size: 13.5px; line-height: 1.55; margin: var(--s2) 0 0; }
.loan-item .banner { margin: var(--s3) 0 0; }

/* Profitable years on the Reports page */
.py-head { font-size: 17px; font-weight: 600; margin: 0 0 6px; letter-spacing: -.01em; }
#profitYears .muted { margin: 0 0 14px; font-size: 14px; line-height: 1.55; }
#profitYears .stmt-row .lbl small { display: block; font-weight: 400; color: var(--warn); }

/* Mileage. The second line of a rate row has to break: inline, "January to June
   2026" and "154.1 miles at 72.5¢ a mile" ran together into one unreadable
   string, which is the sort of thing only looking at it catches. */
#summary .stmt-row .lbl small { display: block; font-weight: 400; color: var(--text-muted); }
#rateNote .banner { margin: var(--s4) 0 0; }
#trips .tx-foot .tx-transfer-label { white-space: normal; }
/* Every control in this app is width:100% by default, which is right inside a
   form field and wrong in a card header - the year picker stretched across the
   whole card, and on a phone it would have squeezed the heading beside it. */
#yearPick { flex: 0 0 auto; width: auto; min-width: 104px; }

/* --------------------------------------------------------------------------
   22. Receipt viewer
   --------------------------------------------------------------------------
   The picture opened from a Purchases row. It is a modal <dialog> so Escape,
   the top layer and focus containment come from the browser instead of from
   us; the close button, the backdrop and the phone's back gesture are wired in
   receipt-viewer.js. Deliberately unanimated - this has to open instantly on
   the old Android handset the product promises to run on. */
body.viewer-open { overflow: hidden; }

.viewer {
  /* Positioned and painted here rather than left to the dialog's own defaults,
     so that every rung of the fallback in receipt-viewer.js - showModal, show,
     and a bare open attribute on a WebView that has never heard of <dialog> -
     lands on the same full-screen picture. z-index only matters on the rungs
     below the top layer: nav is 40, tabbar 50, toast 80. */
  position: fixed;
  inset: 0;
  z-index: 90;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  /* Every page sets viewport-fit=cover, so an installed app draws underneath
     the status bar and the notch. At a flat 16px the close button sat UNDER
     them on a phone: present, painted, and impossible to press. */
  padding:
    max(var(--s4), env(safe-area-inset-top))
    max(var(--s4), env(safe-area-inset-right))
    max(var(--s4), env(safe-area-inset-bottom))
    max(var(--s4), env(safe-area-inset-left));
  border: 0;
  background: rgba(0, 0, 0, .72);
  display: none;
}
.viewer[open] { display: flex; align-items: center; justify-content: center; }
.viewer::backdrop { background: rgba(0, 0, 0, .72); }

.viewer-panel {
  display: flex;
  flex-direction: column;
  width: min(100%, 900px);
  /* Enough presence that a receipt which failed to load still reads as a panel
     with something to say, rather than a stray bar across the screen. */
  min-height: min(260px, 100%);
  max-height: 100%;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--sh-3);
}

.viewer-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s2) var(--s2) var(--s4);
  border-bottom: 1px solid var(--line);
}
.viewer-title {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 600;
  font-size: 15.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.viewer-close {
  flex: none;
  min-width: 44px; min-height: 44px;
  padding: 0 var(--s3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  border-radius: var(--r-full);
  background: var(--surface-2);
  border: 1.5px solid var(--line-strong);
  color: var(--text);
  font-weight: 600;
  font-size: 14.5px;
  box-shadow: none;
}
.viewer-close:hover { background: var(--bg-tint); border-color: var(--line-strong); color: var(--text); }
/* The word is the point on a phone; on a very narrow screen the cross alone
   still has to be a 44px target, so the label is what goes, not the button. */
@media (max-width: 380px) { .viewer-close-label { display: none; } }

.viewer-media {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  padding: var(--s3);
  background: var(--surface-2);
}
/* Centred with an auto margin rather than align-items, and the difference is
   not cosmetic: centring a flex child TALLER than its scroll container pins it
   to the middle and puts the top out of reach. A long till receipt opened on
   item four, with the shop name and the date scrolled off above it and no way
   to scroll up. An auto margin collapses to zero the moment the picture
   overflows, so small receipts still centre and tall ones start at the top. */
.viewer-img { display: block; margin: auto; max-width: 100%; height: auto; border-radius: var(--r-md); }

/* A file the picture element could not read - usually a PDF. The object earns
   its height only once it reports that it loaded, so a browser that cannot
   render one inline leaves the message standing on its own instead of above a
   tall blank rectangle. */
.viewer-fallback { margin: auto; display: grid; gap: var(--s2); width: 100%; }
.viewer-pdf { width: 100%; height: 0; border: 0; }
.viewer-pdf.is-loaded { height: 62dvh; }
.viewer-note { margin: 0; color: var(--text-muted); }

/* The receipt icon on a Purchases row. It was an <a> to the bare image; it is
   now a button that opens the viewer, and has to keep looking like the quiet
   icon it always was while growing a target a thumb can actually hit. */
.tx-receipt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px; min-height: 30px;
  margin: -6px 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-full);
  background: transparent;
  box-shadow: none;
  color: var(--text-muted);
}
.tx-receipt:hover { background: var(--bg-tint); color: var(--accent-text); }

/* --------------------------------------------------------------------------
   23. The phone menu (three lines, beside the mark)
   --------------------------------------------------------------------------
   Below 768px the header nav is hidden and only the five-slot tab bar shows,
   while the app has nine pages - so four of them could not be reached from a
   phone at all. This button is that way in. Above 768px the nav rail already
   lists everything, so it goes away. Built in public/nav-menu.js. */
.nav-burger {
  flex: none;
  width: 44px; min-height: 44px;
  padding: 0;
  margin-right: calc(var(--s1) * -1);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text);
  box-shadow: none;
}
.nav-burger:hover { background: var(--bg-tint); }
@media (min-width: 768px) { .nav-burger { display: none; } }

body.navsheet-open { overflow: hidden; }

.navsheet {
  position: fixed;
  inset: 0;
  z-index: 95;               /* above the toast at 80 and the viewer's 90 */
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  /* viewport-fit=cover means an installed app paints under the status bar. */
  padding:
    max(var(--s3), env(safe-area-inset-top))
    max(var(--s3), env(safe-area-inset-right))
    max(var(--s3), env(safe-area-inset-bottom))
    max(var(--s3), env(safe-area-inset-left));
  border: 0;
  background: rgba(0, 0, 0, .6);
  display: none;
}
.navsheet[open] { display: flex; align-items: flex-start; justify-content: center; }
.navsheet::backdrop { background: rgba(0, 0, 0, .6); }

.navsheet-panel {
  display: flex;
  flex-direction: column;
  width: min(100%, 420px);
  max-height: 100%;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--sh-3);
}

.navsheet-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s2) var(--s2) var(--s2) var(--s4);
  border-bottom: 1px solid var(--line);
}
.navsheet-title { flex: 1 1 auto; font-weight: 600; font-size: 15.5px; color: var(--text-muted); }
.navsheet-close {
  flex: none;
  min-width: 44px; min-height: 44px;
  padding: 0 var(--s3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  border-radius: var(--r-full);
  background: var(--surface-2);
  border: 1.5px solid var(--line-strong);
  color: var(--text);
  font-weight: 600;
  font-size: 14.5px;
  box-shadow: none;
}
.navsheet-close:hover { background: var(--bg-tint); }

.navsheet-list { overflow: auto; -webkit-overflow-scrolling: touch; padding: var(--s2); }
.navsheet-link {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 52px;          /* a comfortable thumb target, not a dense list */
  padding: 0 var(--s3);
  border-radius: var(--r-md);
  color: var(--text);
  text-decoration: none;
  font-size: 16px;
  font-weight: 600;
}
.navsheet-link:hover { background: var(--bg-tint); }
.navsheet-link .icon { color: var(--text-muted); }
.navsheet-link.active { background: var(--accent-soft); color: var(--accent-text); }
.navsheet-link.active .icon { color: var(--accent-text); }
