:root {
  font-family: system-ui, sans-serif;
  color-scheme: light dark;
  /* Ember Ledger (design system artifact): warm cream ground, deep brown
     ink, one terracotta action colour. */
  --surface: #fbf6ef;      /* surface */
  --card: #ffffff;         /* surface-raised */
  --sunken: #f3eadd;       /* surface-sunken: inputs, tracks */
  --line: #e6d9c8;         /* border */
  --text: #2b2118;         /* ink */
  --text-2: #6e5e50;       /* ink-muted */
  --text-3: #8c7b6b;       /* hints and axes, a step below ink-muted (not in the system) */
  --series-plan: #4e8a87;  /* categorical slot 1: cat-bills, the one cool hue */
  --series-whatif: #b54a24; /* categorical slot 2: primary terracotta */
  --status-good: #3f6b2e;  /* income */
  --status-critical: #b3261e; /* over-budget, reserved */
  --warning: #8a5a0c;      /* warning */
  --unplanned: #6f4fa0;    /* spending with no budget: outside the plan (not in the system) */
  --accent: #b54a24;       /* primary */
  --on-accent: #ffffff;    /* on-primary */
  --gap: .75rem;
}
@media (prefers-color-scheme: dark) {
  :root {
    --surface: #1c1814;
    --card: #28221d;
    --sunken: #14110e;
    --line: #3b332b;
    --text: #f3ece3;
    --text-2: #b8a99a;
    --text-3: #8c7b6b;
    --series-plan: #7db8b4;
    --series-whatif: #e8875f;
    --status-good: #9cc47f;
    --status-critical: #ff8a80;
    --warning: #f2c46b;
    --unplanned: #bea2e8;
    --accent: #e8875f;
    --on-accent: #2b1408;
  }
}

/* ---- app shell: the page itself never scrolls; panes scroll inside ---- */
html, body { height: 100%; }
body { margin: 0; display: flex; flex-direction: column; overflow: hidden; background: var(--surface); color: var(--text); accent-color: var(--accent); }
header { flex: none; display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: max(.6rem, env(safe-area-inset-top)) max(1rem, env(safe-area-inset-right)) .6rem max(1rem, env(safe-area-inset-left)); border-bottom: 1px solid var(--line); background: var(--card); }
header nav { margin: 0 auto; }
nav a svg { display: none; }
/* the header's +: log an expense from any page */
header a.quick-add { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border-radius: 50%; background: var(--accent); color: var(--on-accent); font-size: 1.4rem; font-weight: 600; line-height: 1; }
header a.quick-add:hover { filter: brightness(1.08); }
header a { color: inherit; text-decoration: none; }
nav { display: flex; gap: 1rem; }
nav a { color: var(--text-2); padding: .25rem 0; }
nav a.active { color: var(--text); font-weight: 600; }
main { flex: 1; min-height: 0; display: flex; flex-direction: column; width: 100%; max-width: 96rem; margin: 0 auto; padding: var(--gap) 1rem 1rem; box-sizing: border-box; }
.app { flex: 1; min-height: 0; display: grid; gap: var(--gap); }
/* a pane is a column that gives its spare height to .scroll */
.pane { min-height: 0; display: flex; flex-direction: column; }
.pane > .scroll { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.pane > h2, .pane > .hint, .pane > form, .pane > .fields, .pane > h3, .pane > .card-head { flex: none; }
/* list header: title + "+ Add", which opens that list's add dialog */
.card-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin: 0 0 .5rem; }
.card-head h2 { margin: 0; }
.add-btn { border: 1px solid var(--accent); background: none; color: var(--accent); border-radius: .4rem; padding: .3rem .8rem; font-weight: 600; }
.add-btn:hover { background: var(--accent); color: var(--on-accent); }
dialog select { width: 100%; }

h1 { font-size: 1.5rem; margin: 0; }
h2 { font-size: 1.1rem; margin: 0 0 .5rem; }
h3 { font-size: .95rem; margin: .75rem 0 .4rem; color: var(--text-2); }
/* 1rem text in fields keeps iOS from zooming into them on focus */
input, select, button { font: inherit; font-size: 1rem; }
button { cursor: pointer; padding: .4rem .8rem; background: var(--sunken); color: var(--text); border: 1px solid var(--text-3); border-radius: .4rem; }
a.button { display: inline-block; padding: .4rem .8rem; background: var(--sunken); color: var(--text); border: 1px solid var(--text-3); border-radius: .4rem; text-decoration: none; }
a.button:hover { border-color: var(--accent); color: var(--accent); }
button:disabled { cursor: default; opacity: .5; }
button.icon { padding: 0 .4rem; border: 0; background: none; color: var(--text-3); font-size: 1.1rem; }
button.icon:hover { color: var(--status-critical); }
input, select { padding: .4rem; min-width: 0; max-width: 100%; box-sizing: border-box; }
input:not([type=range], [type=checkbox], [type=file], [type=hidden]), select, textarea { background: var(--sunken); color: var(--text); border: 1px solid var(--text-3); border-radius: .4rem; }
form { display: flex; gap: .5rem; flex-wrap: wrap; margin: .6rem 0 0; }
form > input { flex: 1; }
label { display: flex; flex-direction: column; gap: .25rem; font-size: .85rem; color: var(--text-2); }
label input { color: var(--text); }
.card { background: var(--card); border: 1px solid var(--line); border-radius: .5rem; padding: .85rem; box-sizing: border-box; }
.fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); gap: .6rem; }
.hint { color: var(--text-3); font-size: .85rem; margin: 0 0 .5rem; }
.hint.warning { color: var(--warning); }
.when { color: var(--text-3); font-size: .85rem; }
.status { font-size: .9rem; margin: .4rem 0 0; }
.status.good { color: var(--status-good); }
.status.critical { color: var(--status-critical); }

/* ---- plan page: chart + afford | needs ---- */
#plan { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
#plan .pane-plan { display: flex; flex-direction: column; min-height: 0; gap: var(--gap); overflow-y: auto; overscroll-behavior: contain; }
#plan .pane-plan > * { flex: none; }
#plan .plan-side { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; }
#plan .plan-side .soon { flex: 0 1 auto; max-height: 45%; }
#plan .plan-side .needs { flex: 1 1 0; }
/* segmented switch: Chart | Needs on phones, Spent | Received always */
.seg { display: none; gap: .25rem; padding: .2rem; border-radius: .5rem; background: var(--line); }
.seg a, .seg button { flex: 1; border: 0; background: none; padding: .35rem .9rem; border-radius: .35rem; color: var(--text-2); text-decoration: none; text-align: center; font-size: .9rem; }
.seg .active { background: var(--card); color: var(--text); font-weight: 600; }
.seg.sub { display: flex; margin-left: auto; }
.month-nav .seg a { font-size: .9rem; color: var(--text-2); }
.month-nav .seg a.active { color: var(--text); }

/* ---- accounts and budget: a summary over two list cards ---- */
#accounts, #budget { grid-template-rows: minmax(0, 1fr); }
.board { min-height: 0; display: grid; gap: var(--gap); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
.board > .summary { grid-column: 1 / -1; padding: 0 .25rem; }
.board > .summary .hint { flex-basis: 100%; margin: 0; }
.list form.add { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
.list form.add .wide { grid-column: 1 / -1; }
.list form.add > * { width: 100%; min-width: 0; }
#accounts .list form.add button { grid-column: auto; }
#budget .list form.add button { grid-column: 1 / -1; }
/* settings: cards across the full width; the expense input card puts its
   choices beside the live preview */
#settings { grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr)); grid-auto-flow: row dense; align-content: start; align-items: start; overflow-y: auto; }
#settings > .pane { min-height: auto; } /* each card as tall as its content: the picker preview must not spill into the next */
#settings .expense-input .fields { grid-template-columns: minmax(0, 1fr); align-content: start; }
.input-setup { display: grid; gap: .75rem 1.25rem; grid-template-columns: minmax(0, 1fr); }
.input-setup .preview { min-width: 0; border-top: 1px solid var(--line); padding-top: .5rem; }
.input-setup .preview .hint { margin: 0 0 .25rem; }
.account .sign-out { margin-left: auto; }
@media (min-width: 64rem) {
  #settings .expense-input { grid-column: span 2; }
  .input-setup { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); }
  .input-setup .preview { border-top: 0; padding-top: 0; border-left: 1px solid var(--line); padding-left: 1.25rem; }
}

/* accounts: edits wait for Save; a changed row and the save bar say so */
.budget .was { display: none; font-size: .75rem; color: var(--text-3); }
.budget .term { display: block; font-size: .75rem; color: var(--text-2); }
.budget.changed .was { display: block; }
.budget.changed input { border-color: var(--series-whatif); box-shadow: 0 0 0 1px var(--series-whatif); }
.budget.changed .name::before { content: "● "; color: var(--series-whatif); }
.accounts .budget .name { display: block; }
[hidden] { display: none !important; }
.budget .name.link { border: 0; background: none; padding: 0; text-align: left; color: var(--text); font-size: 1rem; cursor: pointer; }
.budget .name.link:hover { color: var(--accent); text-decoration: underline; }

/* ---- drag pickers for an expense amount (picker.js) ---- */
.picker { margin: .25rem 0; outline: none; user-select: none; -webkit-user-select: none; }
.picker-readout { font-size: 1.6rem; font-weight: 700; text-align: center; font-variant-numeric: tabular-nums; }
.pk-hint { font-size: .8rem; color: var(--text-3); text-align: center; margin: .35rem 0 0; }
.pk-track { position: relative; height: 2.75rem; border-radius: 1.4rem; background: var(--line); touch-action: none; cursor: pointer; margin: .6rem 0 .3rem; }
.pk-fill { position: absolute; inset: 0 auto 0 0; border-radius: 1.4rem; background: var(--accent); opacity: .35; }
.pk-thumb { position: absolute; top: 50%; width: 2.3rem; height: 2.3rem; transform: translate(-50%, -50%); border-radius: 50%; background: var(--card); border: 3px solid var(--accent); box-sizing: border-box; }
.pk-ticks { position: relative; height: 1rem; font-size: .7rem; color: var(--text-3); }
.pk-ticks span { position: absolute; transform: translateX(-50%); white-space: nowrap; }
.pk-ticks span:first-child { transform: none; }
.pk-ticks span:last-child { transform: translateX(-100%); }
.pk-dial-wrap { position: relative; width: min(14rem, 100%); margin: 0 auto; }
.pk-dial { width: 100%; display: block; touch-action: none; cursor: grab; }
.pk-arc-bg { fill: none; stroke: var(--line); stroke-width: 16; stroke-linecap: round; }
.pk-arc { fill: none; stroke: var(--accent); stroke-width: 16; stroke-linecap: round; }
.pk-knob { fill: var(--card); stroke: var(--accent); stroke-width: 4; }
.pk-dial-wrap .picker-readout { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 1.3rem; pointer-events: none; }
.pk-pad { touch-action: none; border: 1px dashed var(--text-3); border-radius: .6rem; padding: .8rem .5rem; text-align: center; cursor: ns-resize; }
.pk-scrub { position: relative; height: 15rem; padding: 0; border-radius: 0; display: grid; place-items: center; cursor: move; overflow: hidden; user-select: none; }
.picker-scrub .picker-readout { margin-bottom: .5rem; }
.pk-scrub-dot { position: absolute; display: none; pointer-events: none; width: 1.6rem; height: 1.6rem; border-radius: 50%; border: 2px solid var(--accent); background: color-mix(in srgb, var(--accent) 25%, transparent); transform: translate(-50%, -50%); }
.pk-scrub.held .pk-scrub-dot { display: block; }
.pk-scale { position: absolute; inset: 0; pointer-events: none; }
.pk-scale .cross { position: absolute; background: var(--text-3); opacity: .35; }
.pk-scale .cross.h { width: 100%; height: 1px; }
.pk-scale .cross.v { height: 100%; width: 1px; }
.pk-scale .line { position: absolute; background: var(--text-3); opacity: .5; }
.pk-scale .line.from-left, .pk-scale .line.from-right { width: 1px; height: 100%; }
.pk-scale .line.from-top, .pk-scale .line.from-bottom { height: 1px; width: 100%; }
.pk-scale b { position: absolute; font-weight: 400; font-size: .75rem; color: var(--text-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.pk-scale b.now { color: var(--accent); font-weight: 600; font-size: .85rem; }
.pk-scale b.from-left { transform: translate(6px, -50%); }
.pk-scale b.from-right { transform: translate(calc(-100% - 6px), -50%); }
.pk-scale b.from-top { transform: translate(-50%, 4px); }
.pk-scale b.from-bottom { transform: translate(-50%, calc(-100% - 4px)); }
.pk-scale b::after { content: ""; position: absolute; background: currentColor; }
.pk-scale b.from-left::after { left: -6px; top: 50%; width: 5px; height: 1px; }
.pk-scale b.from-right::after { right: -6px; top: 50%; width: 5px; height: 1px; }
.pk-scale b.from-top::after { top: -4px; left: 50%; height: 4px; width: 1px; }
.pk-scale b.from-bottom::after { bottom: -4px; left: 50%; height: 4px; width: 1px; }
.pk-pattern { position: relative; width: 17rem; max-width: 100%; aspect-ratio: 1; margin: .5rem auto 0; touch-action: none; user-select: none; -webkit-user-select: none; cursor: pointer; }
.picker-readout.want { animation: want .6s; color: var(--status-critical); }
@keyframes want { 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
.pk-ring { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.pk-seg path { fill: transparent; stroke: var(--text-3); stroke-width: .5; transition: fill .1s, stroke .1s; }
.pk-seg text { fill: var(--text); font-size: 7px; text-anchor: middle; dominant-baseline: central; font-variant-numeric: tabular-nums; }
.pk-seg.wide text { font-size: 5.2px; }
.pk-seg.over path { stroke: var(--accent); }
.pk-seg.on path { stroke: var(--accent); fill: color-mix(in srgb, var(--accent) 22%, transparent); }
.pk-seg.on text { fill: var(--accent); }
.pk-mid { fill: color-mix(in srgb, var(--text-3) 10%, transparent); stroke: var(--text-3); stroke-width: .5; }
.pk-pattern.menu .pk-mid { stroke: var(--accent); fill: color-mix(in srgb, var(--accent) 12%, transparent); }
.pk-pattern.menu .pk-ringset.digits { display: none; }
.pk-pattern .picker-readout { position: absolute; left: 50%; top: 50%; translate: -50% -70%; font-size: 1.35rem; white-space: nowrap; pointer-events: none; }
.pk-acct { position: absolute; left: 50%; top: 50%; translate: -50% 45%; max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .8rem; color: var(--text-2); pointer-events: none; }
.pk-seg.blank path { stroke-dasharray: 1 1.5; }
.pk-seg.add path { stroke: var(--accent); }
.pk-seg.add text { fill: var(--accent); font-weight: 600; }
.pk-seg.cur path { stroke: var(--accent); stroke-width: 1; }
.pk-seg.over.add path, .pk-seg.over.cancel path, .pk-ringset.menu .pk-seg.over path { fill: color-mix(in srgb, var(--accent) 22%, transparent); stroke: var(--accent); }
.pk-ringset.menu .pk-seg text { font-size: 5px; }
/* The ring's middle and bottom do the dialog's Cancel / Add while it is on screen. */
form.ring-actions:has(.picker-pattern:not([style*="none"])) .actions { display: none; }
.pk-trail { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.pk-trail polyline { fill: none; stroke: var(--accent); stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; opacity: .5; }
.pk-near { color: var(--text-3); font-size: .95rem; min-height: 1.4em; font-variant-numeric: tabular-nums; }
.pk-grid { position: relative; display: grid; grid-template-columns: repeat(5, 1fr); grid-template-rows: repeat(9, 1fr); gap: 2px; height: 15rem; touch-action: none; cursor: crosshair; margin-top: .4rem; }
.pk-grid span { display: flex; align-items: center; justify-content: center; font-size: .68rem; background: var(--line); border-radius: .2rem; color: var(--text-3); }
.pk-grid-h, .pk-grid-v { position: absolute; pointer-events: none; background: var(--accent); opacity: .55; }
.pk-grid-h { left: 0; right: 0; height: 1px; }
.pk-grid-v { top: 0; bottom: 0; width: 1px; }
.pk-grid-dot { position: absolute; width: 1.4rem; height: 1.4rem; margin: -.7rem 0 0 -.7rem; border-radius: 50%; background: var(--accent); border: 3px solid var(--card); box-sizing: border-box; pointer-events: none; box-shadow: 0 1px 6px #0006; }
.pk-ruler { position: relative; height: 4.2rem; overflow: hidden; touch-action: none; cursor: ew-resize; border-radius: .5rem; background: var(--line); margin-top: .4rem; }
.pk-ruler-strip { position: absolute; inset: 0 auto 0 0; will-change: transform; }
.pk-ruler-strip i { position: absolute; bottom: 0; width: 1px; height: .6rem; background: var(--text-3); }
.pk-ruler-strip i.major { height: 1.4rem; background: var(--text-2); }
.pk-ruler-strip b { position: absolute; top: .35rem; transform: translateX(-50%); font-size: .7rem; font-weight: 400; color: var(--text-2); white-space: nowrap; }
.pk-ruler-mark { position: absolute; left: 50%; top: 0; bottom: 0; width: 2px; margin-left: -1px; background: var(--accent); }
/* quick add: the + on a category row, tap, or hold and drag up (pan-y: a swipe from it scrolls; picker.js) */
.categories .category .quick { touch-action: pan-y; flex: none; width: 2.2rem; height: 2.2rem; min-height: 0; padding: 0; border: 1px solid var(--accent); border-radius: 50%; background: none; color: var(--accent); font-size: 1.2rem; line-height: 1; }
.categories .category .quick:active, .categories .category .quick.dragging { background: var(--accent); color: var(--on-accent); }
.categories .category.idle .name, .categories .category.idle .amount { color: var(--text-3); }
/* the expense page's categories as a grid of cards */
.categories.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: .5rem; }
.categories.cards li { position: relative; display: flex; flex-direction: column; align-items: stretch; gap: .1rem; padding: .5rem .6rem .55rem; border: 1px solid var(--line); border-radius: .6rem; background: var(--card); cursor: pointer; min-width: 0; }
.categories.cards li:active { border-color: var(--accent); }
.categories.cards li.hint { grid-column: 1 / -1; cursor: default; border-style: dashed; background: none; }
.categories.cards li.archived { cursor: default; border-style: dashed; }
.categories.cards li.archived .name, .categories.cards li.archived small { color: var(--text-3); }
.categories.cards .category .name { flex: none; font-weight: 600; padding-right: 1.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.categories.cards .category .quick { position: absolute; top: .35rem; right: .35rem; width: 1.75rem; height: 1.75rem; min-height: 0; font-size: 1rem; }
.categories.cards .category .amount { margin-left: 0; font-size: 1.05rem; margin-top: .1rem; }
.categories.cards .category small { font-size: .78rem; }
.categories.cards .category .bar { flex-basis: auto; margin-top: .3rem; }
.quick-bubble { position: fixed; z-index: 50; pointer-events: none; transform: translate(-50%, -140%); background: var(--card); color: var(--text); border: 1px solid var(--accent); border-radius: .5rem; padding: .35rem .65rem; font-weight: 600; white-space: nowrap; box-shadow: 0 4px 16px #0005; font-variant-numeric: tabular-nums; }
.quick-bubble small { display: block; font-weight: 400; color: var(--text-3); }
.pk-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); gap: .4rem; margin-top: .4rem; }
.pk-tile { touch-action: none; min-height: 3.2rem; border: 1px solid var(--line); background: var(--card); border-radius: .5rem; color: var(--text); font-size: .9rem; }
.pk-tile.on { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.pk-bubble { font-size: 1.1rem; min-height: 1.6em; }
#settings label .hint { margin: 0; font-size: .8rem; }

/* chart: a steady height from the viewport, whatever appears below it (a
   verdict, notices); plan.js sizes the viewBox to fill it, and the pane
   scrolls when there is more */
.chart-wrap { position: relative; flex: none; height: clamp(15rem, 46vh, 30rem); display: flex; flex-direction: column; align-items: center; background: var(--card); border: 1px solid var(--line); border-radius: .5rem; padding: .5rem; box-sizing: border-box; }
.chart-wrap svg { flex: 0 1 auto; min-height: 0; width: 100%; height: auto; max-height: 100%; display: block; touch-action: pan-y; }
.chart-wrap svg text { font-size: 11px; fill: var(--text-2); }
.grid line { stroke: var(--line); stroke-width: 1; }
.zero { stroke: var(--text-3); stroke-width: 1; }
.buffer { stroke: var(--text-3); stroke-width: 1; stroke-dasharray: 2 4; }
.buffer-label { font-size: 10px; }
.crosshair { stroke: var(--text-3); stroke-width: 1; pointer-events: none; }
path.plan { fill: none; stroke: var(--series-plan); stroke-width: 2; stroke-linejoin: round; }
path.whatif { fill: none; stroke: var(--series-whatif); stroke-width: 2; stroke-dasharray: 6 4; stroke-linejoin: round; }
.shortfall line { stroke: var(--status-critical); stroke-width: 1; stroke-dasharray: 3 3; }
.shortfall text { fill: var(--status-critical); font-size: 10px; }
.marker { cursor: grab; touch-action: none; }
.marker line { stroke: var(--series-plan); stroke-width: 1; stroke-dasharray: 2 2; }
.marker .dot { fill: var(--series-plan); stroke: var(--card); stroke-width: 2; }
.marker .hit { fill: transparent; stroke: none; } /* finger-sized target around the dot, never painted */
.marker text { fill: var(--text); font-size: 10px; pointer-events: none; }
/* as meant (and as internal/plan's placeLabels measures them): goal names
   and the buffer labels at 10px, over the chart text's 11px */
.chart-wrap svg .marker text, .chart-wrap svg .buffer-label, .chart-wrap svg .shortfall text { font-size: 10px; }
.marker.earning line { stroke: var(--status-good); }
.marker.earning .dot { fill: var(--status-good); }
.marker.off line { stroke: var(--text-3); }
.marker.off .dot { fill: var(--card); stroke: var(--text-3); }
.marker.off text { fill: var(--text-3); }
.marker.beyond text { font-style: italic; }
path.plan.worth { stroke-width: 2.5; }
path.band { fill: color-mix(in srgb, var(--series-plan) 15%, transparent); stroke: none; pointer-events: none; }
.now circle { fill: var(--card); stroke: var(--series-plan); stroke-width: 2; }
.now text { font-size: 10px; fill: var(--text-2); }
.payoff path { fill: var(--status-good); stroke: var(--card); stroke-width: 1.5; }
circle.repeat { fill: var(--series-plan); stroke: var(--card); stroke-width: 1.5; pointer-events: none; }
circle.repeat.earning { fill: var(--status-good); }
circle.repeat.off { fill: var(--card); stroke: var(--text-3); }
.chart-tip .lines { display: block; margin-top: .25rem; padding-top: .25rem; border-top: 1px solid var(--line); color: var(--text-2); }
.chart-tip { position: absolute; pointer-events: none; background: var(--card); border: 1px solid var(--line); border-radius: .3rem; padding: .3rem .5rem; font-size: .8rem; box-shadow: 0 2px 8px #0002; }
.legend { flex: none; align-self: stretch; display: flex; flex-wrap: wrap; gap: .25rem 1rem; font-size: .8rem; color: var(--text-2); padding: .4rem .25rem 0; }
.swatch { display: inline-block; width: 1.2rem; height: 0; border-top: 2px solid; vertical-align: middle; margin-right: .3rem; }
.swatch.plan { border-color: var(--series-plan); }
.swatch.whatif { border-color: var(--series-whatif); border-top-style: dashed; }
.swatch.buffer { border-color: var(--text-3); border-top-style: dotted; }
.swatch.band { height: .6rem; border: 0; background: color-mix(in srgb, var(--series-plan) 15%, transparent); }
.swatch.payoff { width: .55rem; height: .55rem; border: 0; background: var(--status-good); transform: rotate(45deg); margin: 0 .45rem 0 .2rem; }

/* summary strip under the chart */
.summary { flex: none; display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; padding: .25rem .25rem 0; align-items: baseline; }
.summary .status { flex-basis: 100%; margin: 0; }
.stat { display: flex; flex-direction: column; }
.stat .label { font-size: .8rem; color: var(--text-3); }
.stat strong { font-size: 1.1rem; }

/* ---- lists ---- */
ul { list-style: none; margin: 0; padding: 0; }
.goals li, .incomes li, .budgets li, .expenses li, .categories li, .months li { display: flex; align-items: center; gap: .75rem; padding: .4rem 0; border-bottom: 1px solid var(--line); }
.accounts .budget input { width: 9rem; }
.liabilities .budget input { color: var(--status-critical); }
.incomes .name { min-width: 0; }
.incomes .name small { display: block; color: var(--text-3); }
.goals .goal { padding: 0; }
.goal input[type=checkbox] { margin: 0; }
.goal .edit { flex: 1; display: flex; align-items: center; gap: .75rem; min-width: 0; padding: .5rem 0; border: 0; background: none; color: inherit; text-align: left; border-radius: .3rem; }
.goal .edit:hover { color: var(--accent); }
/* A name keeps its words whole: with no min-width: 0 it is never narrower
   than its longest word ("Asuransi", not "Asura / nsi"), but width caps
   that least width at 8rem (flex: 1 still sizes it), so one word longer
   than that breaks (break-word) instead of pushing the amount and the date
   out of the card. A long "every 6 months · next Dec 2026" wraps in its own
   column, and a list too narrow for the three side by side gives the name
   a line of its own, as on a phone. */
.goals { container-type: inline-size; }
.goal .name { flex: 1; width: 8rem; overflow-wrap: break-word; }
.goal .amount { margin-left: 0; }
.goal.earning .amount { color: var(--status-good); }
.goal .when { min-width: 4.5rem; max-width: 9rem; text-align: right; text-wrap: balance; }
@container (max-width: 22rem) {
  .goal .edit { flex-wrap: wrap; gap: 0 .75rem; }
  .goal .name { flex: 1 1 100%; }
  .goal .when { margin-left: auto; max-width: none; }
}
.goal.off .name, .goal.off .amount { color: var(--text-3); text-decoration: line-through; }
.amount { font-variant-numeric: tabular-nums; margin-left: auto; white-space: nowrap; }
.cashflow.income .amount { color: var(--status-good); }
.cashflows .total { color: var(--text-2); font-size: .9rem; border-bottom: 0; }
.expense .date { color: var(--text-3); font-size: .85rem; min-width: 6rem; }
.expense .name { min-width: 0; overflow-wrap: anywhere; }
.expense .name small { display: block; color: var(--text-3); }
.categories, .months { font-size: .9rem; }
/* budget: a field per category */
.budgets .budget { padding: .25rem 0; }
.budget .name { flex: 1; font-size: 1rem; color: var(--text); }
.budget input { width: 9rem; text-align: right; }
.budgets .total { color: var(--text-2); font-size: .9rem; border-bottom: 0; }
/* expenses summary: spent vs budget per category, with a bar */
.categories .category { flex-wrap: wrap; gap: .25rem .75rem; }
.categories .category .name { flex: 1; }
.categories .category small { color: var(--text-3); }
.categories .category.over .amount { color: var(--status-critical); }
.bar { flex-basis: 100%; height: 4px; border-radius: 2px; background: var(--line); overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--series-plan); }
.category.over .bar i { background: var(--status-critical); }
/* spending with no budget (views.Judge: unplanned), the same on Budget and Expenses */
.categories .category.unplanned .amount { color: var(--unplanned); }
.category.unplanned .bar i { background: var(--unplanned); }
.status.unplanned { color: var(--unplanned); }

/* ---- edit dialog ---- */
dialog { box-sizing: border-box; width: min(26rem, calc(100vw - 2rem)); padding: 1.25rem; border: 1px solid var(--line); border-radius: .5rem; background: var(--card); color: var(--text); box-shadow: 0 8px 32px #0004; }
dialog::backdrop { background: #0008; }
dialog form { display: flex; flex-direction: column; gap: .75rem; margin: 0; }
/* flex, not grid: Chrome sizes a grid row holding a type=month input far too tall.
   wrap only so the row's narrowest width is its widest field, not all of them
   side by side (two month inputs on a phone): with a 0 basis nothing ever wraps,
   but unwrapped the form was stretched past the dialog's padding, and the sticky
   actions with it. */
dialog .fields { display: flex; flex-wrap: wrap; gap: .75rem; }
dialog .fields label { flex: 1 1 0; min-width: 0; }
/* radios keep their own size beside their label (a full-width radio floats
   far from it, and is a huge circle on a phone) */
dialog input:not([type=checkbox], [type=radio]) { width: 100%; box-sizing: border-box; }
dialog input[type=radio] { flex: none; margin: 0; }
dialog .check { flex-direction: row; align-items: center; gap: .5rem; font-size: 1rem; color: var(--text); }
/* Save and Cancel stay in sight: in a dialog taller than the screen (it
   scrolls) they stick to its bottom edge, over the fields scrolling under. */
dialog { --dialog-pad: 1.25rem; --dialog-pad-bottom: var(--dialog-pad); }
dialog .actions { display: flex; gap: .5rem; justify-content: flex-end; margin-top: .25rem; position: sticky; bottom: calc(-1 * var(--dialog-pad-bottom)); z-index: 2; margin-left: calc(-1 * var(--dialog-pad)); margin-right: calc(-1 * var(--dialog-pad)); margin-bottom: calc(-1 * var(--dialog-pad-bottom)); padding: .6rem var(--dialog-pad) var(--dialog-pad-bottom); background: var(--card); }
dialog .actions .danger { margin-right: auto; }
button.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
/* destructive: Delete, Remove, Decline, Disconnect, Delete household */
button.danger { color: var(--status-critical); border-color: currentColor; }
button.danger:hover:not(:disabled) { background: color-mix(in srgb, var(--status-critical) 12%, transparent); }

/* ---- expenses page: form + totals | list ---- */
#expenses, #received { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); grid-template-rows: auto minmax(0, 1fr); }
#expenses .month-nav, #received .month-nav { grid-column: 1 / -1; }
/* one pane: the cards; the list is in the History dialog */
#expenses { grid-template-columns: minmax(0, 1fr); }
/* Import and History, on the totals' line */
.summary .tools { margin-left: auto; display: flex; gap: .4rem; align-self: center; }
.summary .tools button { border: 1px solid var(--line); background: none; color: var(--text); border-radius: .4rem; padding: .3rem .75rem; font-weight: 600; }
.summary .tools button:hover { border-color: var(--accent); color: var(--accent); }
.sort-bar[hidden] { display: none; }
.sort-bar { flex: none; margin: 0 0 .5rem; display: flex; justify-content: space-between; align-items: center; gap: .5rem; padding: .55rem .75rem; border: 1px solid var(--accent); border-radius: .5rem; background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--text); text-align: left; }
.sort-bar span { color: var(--accent); font-weight: 600; white-space: nowrap; }
dialog.import textarea { width: 100%; box-sizing: border-box; font: .85rem/1.4 ui-monospace, monospace; resize: vertical; }
dialog.import .hint { margin: 0; }
dialog.import .import-file { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin: 0; padding: .5rem .6rem; border: 1px solid var(--line); border-radius: .4rem; overflow-wrap: anywhere; }
dialog.sorter-dialog .sort-note { margin: -.4rem 0 0; }
dialog.import .import-row { display: flex; gap: .5rem; }
dialog.import .import-row select { flex: 1; min-width: 0; width: auto; }
dialog.import form { gap: .55rem; }
dialog.import .file-btn { flex: none; display: inline-flex; flex-direction: row; align-items: center; padding: 0 .8rem; border: 1px solid var(--line); border-radius: .4rem; color: var(--text); font-size: .9rem; cursor: pointer; }
dialog.import .file-btn:hover { border-color: var(--accent); color: var(--accent); }
/* the sorter: a ring of categories round the expense waiting */
dialog.sorter-dialog h2 small { font-size: .85rem; font-weight: 400; color: var(--text-3); margin-left: .4rem; }
.so-pad { position: relative; width: 19rem; max-width: 100%; aspect-ratio: 1; margin: 0 auto; touch-action: none; user-select: none; -webkit-user-select: none; }
.so-seg.skip text, .so-seg.delete text { font-weight: 600; }
.so-seg.delete path { stroke: var(--status-critical); }
.so-seg.delete text { fill: var(--status-critical); }
.pk-seg.so-seg.over path, .pk-seg.so-seg.on path { stroke: var(--accent); fill: color-mix(in srgb, var(--accent) 22%, transparent); }
.pk-seg.so-seg.delete.over path, .pk-seg.so-seg.delete.on path { stroke: var(--status-critical); fill: color-mix(in srgb, var(--status-critical) 22%, transparent); }
.so-card { position: absolute; left: 50%; top: 50%; translate: -50% -50%; width: 50%; display: flex; flex-direction: column; align-items: center; gap: .15rem; text-align: center; pointer-events: none; cursor: grab; }
.so-card.enter { animation: so-in .18s ease-out; }
@keyframes so-in { from { opacity: 0; scale: .85; } }
.so-amt { font-size: 1.15rem; white-space: nowrap; }
.so-dir { font-size: .7rem; color: var(--accent); text-transform: uppercase; letter-spacing: .04em; }
.so-pad.in .so-amt { color: var(--status-good); }
.so-seg.transfer text, .so-seg.back text, .so-seg.refund text { fill: var(--accent); font-weight: 600; }
.so-pad.transfer .pk-mid, .so-pad.refund .pk-mid { stroke: var(--accent); stroke-dasharray: 1.5 1; }
.so-note { font-size: .85rem; max-width: 100%; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow-wrap: anywhere; }
.so-meta { font-size: .72rem; color: var(--text-3); }
.so-pad.held .so-card { scale: .8; padding: .35rem .5rem; border-radius: .5rem; background: var(--card); box-shadow: 0 4px 16px #0006; }
.so-pad.held .pk-mid { stroke: var(--accent); }
.so-pad.empty .so-seg { opacity: .35; }
.so-pad.empty .so-amt { color: var(--status-good); }
.import-error { margin: 0; max-height: 8rem; overflow: auto; white-space: pre-wrap; font: .82rem/1.4 ui-monospace, monospace; color: var(--status-critical); }
/* what an import read: where it goes, the card flip, the lines left out */
.import-detail { display: flex; flex-direction: column; gap: .4rem; font-size: .85rem; }
.import-detail:empty { display: none; }
.import-detail p { margin: 0; }
.import-into { color: var(--text); font-weight: 600; }
.import-into.guess { color: var(--warning); }
.import-flip { flex-direction: row; align-items: flex-start; gap: .45rem; color: var(--text); font-size: .85rem; cursor: pointer; }
.import-flip input { flex: none; margin: .15rem 0 0; }
.import-detail details, .sort-skipped { font-size: .8rem; color: var(--text-2); }
.import-detail summary, .sort-skipped summary { cursor: pointer; }
.import-detail details ul, .sort-skipped ul { margin: .3rem 0 0; padding-left: 1.1rem; max-height: 7rem; overflow: auto; overflow-wrap: anywhere; }
.import-errors summary { color: var(--status-critical); }
dialog.sorter-dialog .sort-skipped { margin: -.3rem 0 .3rem; }
/* the count of imported rows waiting, on the Expenses tab */
.nav-count { display: inline-block; min-width: 1.1rem; margin-left: .3rem; padding: 0 .3rem; border-radius: .6rem; background: var(--accent); color: var(--on-accent); font-size: .7rem; font-weight: 600; line-height: 1.1rem; text-align: center; vertical-align: .1em; box-sizing: border-box; }
/* sorter: Accept all and Undo over the ring; the row tapped, the entry it
   may be, the correction sheet and the statement check under it */
.sort-tools { display: flex; flex-wrap: wrap; justify-content: center; gap: .4rem; min-height: 0; margin-bottom: .25rem; }
.sort-tools:not(:has(button:not([hidden]))) { display: none; }
.sort-accept { border-color: var(--accent); color: var(--accent); background: none; font-weight: 600; }
.sort-accept:hover { background: var(--accent); color: var(--on-accent); }
.so-pad:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 50%; }
.pk-seg.so-seg.suggest path { stroke: var(--accent); stroke-width: 1.2; stroke-dasharray: 2 1.2; }
.pk-seg.so-seg.suggest text { fill: var(--accent); font-weight: 700; }
.so-pad.tapped .so-card { scale: .95; padding: .35rem .5rem; border-radius: .5rem; background: var(--card); box-shadow: 0 0 0 2px var(--accent); }
.so-pad.tapped .so-note { -webkit-line-clamp: 6; }
.so-hint { margin: .35rem 0 0; text-align: center; font-size: .8rem; }
.so-hint:empty { display: none; }
.so-picked, .so-maybe { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: .4rem; margin-top: .45rem; }
.so-maybe { padding: .5rem .6rem; border: 1px solid var(--warning); border-radius: .5rem; background: color-mix(in srgb, var(--warning) 10%, transparent); }
.so-maybe p { flex: 1 1 100%; margin: 0; font-size: .85rem; text-align: center; }
.so-maybe-actions { display: flex; gap: .4rem; }
.sort-edit { display: flex; flex-direction: column; gap: .6rem; margin-top: .25rem; }
.seg.sort-dir { display: flex; }
.seg.sort-dir button[aria-pressed=true] { background: var(--card); color: var(--text); font-weight: 600; }
.sort-edit-actions, .sort-check-actions { display: flex; justify-content: flex-end; gap: .5rem; }
.sort-edit-error { margin: 0; }
.sort-check { margin-top: .6rem; padding: .6rem .7rem; border: 1px solid var(--line); border-radius: .5rem; background: var(--sunken); }
.sort-check p { margin: 0 0 .5rem; font-size: .85rem; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
dialog.history[open] { display: flex; flex-direction: column; gap: .5rem; width: min(36rem, calc(100vw - 2rem)); max-height: 85dvh; }
dialog.history h2 { margin: 0; flex: none; }
dialog.history .scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
dialog.history .actions { flex: none; }
.month-nav { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.month-nav a, .month-nav .disabled { font-size: 1.5rem; text-decoration: none; color: var(--text-2); }
.month-nav .disabled { color: var(--text-3); }
#expense-summary { padding: .5rem .25rem 0; }
#expense-summary .categories, #expense-summary .months, #received-summary .categories, #received-summary .months { flex-basis: 100%; }

/* ---- expenses and received: History, edit rows, charts ---- */
/* a card's list button: its expenses this month (History, filtered) */
.categories.cards .category .list-btn { position: absolute; right: .35rem; bottom: .85rem; width: 1.75rem; height: 1.75rem; min-height: 0; min-width: 0; padding: 0; display: grid; place-items: center; border: 0; border-radius: .35rem; background: none; color: var(--text-3); }
.categories.cards .category .list-btn:hover { color: var(--accent); background: var(--sunken); }
.categories.cards .category .list-btn svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.categories.cards .category small { padding-right: 1.9rem; }
.categories .category .quick.armed { background: var(--accent); color: var(--on-accent); box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 25%, transparent); }
/* History: filters over a list grouped by day */
.history-filters { flex: none; display: grid; grid-template-columns: 1fr 1fr; gap: .4rem; }
.history-filters .wide { grid-column: 1 / -1; }
.history-filters select, .history-filters input[type=search] { width: 100%; border-radius: 999px; padding-inline: .75rem; }
.history-filters .more-filters summary { cursor: pointer; color: var(--text-2); font-size: .85rem; padding: .2rem 0; }
.history-filters .more-filters .fields { margin-top: .4rem; }
.history-summary { margin: 0 0 .25rem; display: flex; flex-wrap: wrap; gap: .1rem .6rem; align-items: baseline; font-size: .9rem; }
.history-summary span { color: var(--text-3); font-size: .85rem; }
.history-list .expenses li.day { padding: .55rem .25rem .2rem; border-bottom: 0; font-size: .82rem; font-weight: 600; color: var(--text-2); }
.history-list .expenses li.day .amount { color: var(--text-2); }
.expenses .tap-row { padding: 0; }
.expenses .tap-row > button { align-items: center; padding: .5rem .25rem; }
.expenses .tap-row .time { color: var(--text-3); font-size: .8rem; font-variant-numeric: tabular-nums; }
.expenses .tap-row .date { color: var(--text-3); font-size: .85rem; min-width: 5.5rem; }
.expenses .tap-row .name small { display: block; color: var(--text-3); font-size: .8rem; }
.expense.refund .amount, .amount.in { color: var(--status-good); }
/* the add and edit dialogs: Refund */
.refund-check small { display: block; color: var(--text-3); font-size: .8rem; }
/* the add dialog: the date as a chip when it is not today */
.date-chip { margin: 0; display: flex; align-items: center; gap: .1rem; }
.date-chip .chip { padding: .25rem .7rem; border: 1px solid var(--accent); border-radius: 999px; background: color-mix(in srgb, var(--accent) 10%, transparent); color: var(--text); font-size: .85rem; min-height: 0; }
/* the received page: one tap when an income arrives */
.categories .income-row { flex-wrap: wrap; }
.got-it { flex: none; padding: .25rem .7rem; border: 1px solid var(--accent); border-radius: 999px; background: none; color: var(--accent); font-weight: 600; font-size: .85rem; }
.got-it:hover { background: var(--accent); color: var(--on-accent); }
.categories .income-row.other .name small { color: var(--text-3); }
.categories li.hint a { color: var(--accent); }
/* the income dialog: correction or a change from a date */
.choice-row { margin: 0; padding: 0; border: 0; display: flex; flex-direction: column; gap: .35rem; }
.choice-row legend { padding: 0; margin-bottom: .3rem; font-size: .85rem; color: var(--text-2); }
.choice-row .check { font-size: .95rem; }
/* charts (views/charts.templ): drawn twice, the one that fits is shown */
.charts { flex-basis: 100%; display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr)); gap: var(--gap); margin-top: .75rem; }
#received-summary .chart-card { flex-basis: 100%; margin-top: .75rem; }
.chart-card { margin: 0; padding: .6rem .6rem .5rem; background: var(--card); border: 1px solid var(--line); border-radius: .6rem; min-width: 0; }
.chart-card figcaption { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .25rem .75rem; margin-bottom: .25rem; }
.chart-card .chart-title { font-weight: 600; font-size: .95rem; }
.chart-card .legend { padding: 0; align-self: auto; }
.chart-card .legend .swatch { width: .8rem; }
.swatch.s0 { height: .6rem; border: 0; border-radius: 2px; background: var(--series-whatif); vertical-align: -1px; }
.swatch.s1 { height: .6rem; border: 0; border-radius: 2px; background: var(--series-plan); vertical-align: -1px; }
.swatch.spent { border-color: var(--series-whatif); }
.swatch.even, .swatch.level { border-color: var(--text-3); border-top-style: dashed; }
.swatch.mark { border-color: var(--text); border-top-width: 2px; }
.chart-card svg { display: block; width: 100%; height: auto; }
.chart-card svg text { font-size: 11px; fill: var(--text-2); }
.chart-card svg text.sub { font-size: 10px; fill: var(--text-3); }
.chart-card svg a.current text.x:not(.sub) { fill: var(--text); font-weight: 700; }
.chart-card rect.current { fill: var(--sunken); }
.chart-card .hit { fill: transparent; }
.chart-card a:hover .hit { fill: color-mix(in srgb, var(--accent) 6%, transparent); }
.chart-card a:focus-visible { outline: none; }
.chart-card a:focus-visible .hit { stroke: var(--accent); stroke-width: 1.5; }
.chart-card .col.s0 { fill: var(--series-whatif); }
.chart-card .col.s1 { fill: var(--series-plan); }
.chart-card .level, .chart-card .even { fill: none; stroke: var(--text-3); stroke-width: 1.5; stroke-dasharray: 5 4; }
.chart-card .mark { stroke: var(--text); stroke-width: 2; stroke-linecap: round; }
.chart-card .spent { fill: none; stroke: var(--series-whatif); stroke-width: 2; stroke-linejoin: round; }
.chart-card .end { fill: var(--series-whatif); stroke: var(--card); stroke-width: 2; }
.chart-card .today { stroke: var(--text-3); stroke-width: 1; stroke-dasharray: 2 3; }
.chart-card .pace .hit:hover { fill: color-mix(in srgb, var(--accent) 8%, transparent); }
.chart-note { margin: .25rem 0 0; color: var(--text-3); font-size: .8rem; }
.chart-narrow { display: none; }
@media (max-width: 48rem) {
  .chart-wide { display: none; }
  .chart-narrow { display: block; }
  .chart-card { padding: .5rem .35rem .45rem; }
}

/* ---- bottom tab bar (phones only) ---- */
.tabs { display: none; }

/* ---- phones: one pane at a time, tab bar at the bottom ---- */
@media (max-width: 48rem) {
  header nav { display: none; }
  header { padding: max(.5rem, env(safe-area-inset-top)) max(.75rem, env(safe-area-inset-right)) .5rem max(.75rem, env(safe-area-inset-left)); }
  header .quick-add { margin-left: auto; }
  main { padding: var(--gap) max(.75rem, env(safe-area-inset-right)) var(--gap) max(.75rem, env(safe-area-inset-left)); }
  .app { display: flex; flex-direction: column; }
  .pane { flex: 1; }
  #plan .pane-plan { gap: .5rem; }
  #plan .seg { display: flex; flex: none; }
  #plan .plan-side { display: contents; } /* its panes take turns with the chart */
  #plan .plan-side .soon { max-height: none; }
  .chart-wrap { height: clamp(14rem, 40dvh, 22rem); }
  .board { display: block; overflow-y: auto; overscroll-behavior: contain; }
  .board > * { margin-bottom: var(--gap); }
  #settings { display: block; overflow-y: auto; }
  #settings > .pane { margin-bottom: var(--gap); }
  .board .pane > .scroll { overflow: visible; }
  .month-nav h1 { font-size: 1.25rem; }
  .tabs { flex: none; display: flex; border-top: 1px solid var(--line); background: var(--card); padding: .25rem .25rem calc(.25rem + env(safe-area-inset-bottom)); }
  .tabs a, .tabs button { flex: 1; border: 0; background: none; padding: .35rem .1rem; color: var(--text-3); text-decoration: none; text-align: center; font-size: .75rem; border-radius: .4rem; }
  .tabs a svg { display: block; width: 1.4rem; height: 1.4rem; margin: 0 auto .15rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
  .tabs .active { color: var(--accent); font-weight: 600; }
  .card { padding: .75rem; }
  .chart-wrap { padding: .35rem .15rem; }
  form.add { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
  form.add .wide, form.add button { grid-column: 1 / -1; }
  form.add input, form.add select { width: 100%; }
  .goal .edit { flex-wrap: wrap; gap: 0 .75rem; }
  .goal .name { flex: 1 1 100%; }
  .goal .amount { margin-left: 0; }
  .goal .when { margin-left: auto; max-width: none; }
  .expense .date { min-width: 4.5rem; font-size: .8rem; }
  .summary { gap: .35rem 1.25rem; }
  #expenses { display: flex; flex-direction: column; }
  /* Received is one page that scrolls: the month, its chart, then the receipts. */
  #received { display: block; overflow-y: auto; overscroll-behavior: contain; }
  #received > * { margin-bottom: var(--gap); }
  #received .pane > .scroll { overflow: visible; }
  /* A sheet at the bottom of the screen, within reach of the thumb. */
  dialog { width: 100vw; max-width: 100vw; margin: auto 0 0; border-width: 1px 0 0; border-radius: .9rem .9rem 0 0; --dialog-pad-bottom: calc(1.25rem + env(safe-area-inset-bottom, 0px)); padding-bottom: var(--dialog-pad-bottom); max-height: 92dvh; }
  dialog .actions { flex-wrap: wrap; }
  dialog .actions button { flex: 1; }
  dialog .actions .danger { flex-basis: 100%; margin-right: 0; }
  dialog.history[open] { width: 100vw; max-height: 92dvh; }
}
/* wider than a phone: every pane is visible, whatever the tab signal says */
@media (min-width: 48.01rem) {
  .pane { display: flex !important; }
}

/* touch: finger-sized fields and buttons */
@media (pointer: coarse) {
  input:not([type=checkbox], [type=radio], [type=range]), select, button:not(.icon) { min-height: 2.75rem; }
  input[type=range] { height: 2.75rem; }
  input[type=checkbox], input[type=radio] { width: 1.3rem; height: 1.3rem; margin: 0; }
  button.icon { min-width: 2.75rem; }
  .marker { cursor: default; }
}

/* Sign-in and registration. These pages scroll (body.auth-page), unlike the
   app's pages, whose panes scroll: on a short or landscape phone the form
   and the consent page's Allow must stay reachable. */
.auth-page main { overflow-y: auto; overscroll-behavior: contain; }
.auth { display: flex; flex-direction: column; gap: .8rem; width: 100%; max-width: 24rem; margin: 3rem auto; }
@media (max-height: 40rem) { .auth { margin: 1rem auto; } }
.auth h1 { margin: 0; }
.auth .status:empty, .account .status:empty { display: none; }
.account .account-actions { margin-top: .5rem; padding-top: 0; border-top: 0; }
.auth button { padding: .55rem .8rem; }
.account-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .8rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.banner { margin-right: auto; padding: .1rem .5rem; border-radius: .3rem; background: var(--warning); color: var(--surface); font-size: .8rem; font-weight: 600; }

/* Expense dialog: Details switch */
label.switch { flex-direction: row; align-items: center; gap: .55rem; font-size: .9rem; color: var(--text); cursor: pointer; }
label.switch small { color: var(--text-3); font-size: .8rem; }
label.switch input { appearance: none; flex: none; width: 2.4rem; height: 1.4rem; margin: 0; border-radius: 1rem; background: var(--line); position: relative; cursor: pointer; transition: background .15s; }
label.switch input::after { content: ""; position: absolute; top: .15rem; left: .15rem; width: 1.1rem; height: 1.1rem; border-radius: 50%; background: #fff; transition: transform .15s; }
label.switch input:checked { background: var(--accent); }
label.switch input:checked::after { transform: translateX(1rem); }
label.switch input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.for-category { margin: 0; font-size: .9rem; color: var(--text-2); }

/* Fan picker: the grid in polar coordinates, pivot at the bottom-right */
.pk-fan { width: 100%; max-width: 20rem; margin: .4rem 0 0 auto; aspect-ratio: 1; touch-action: none; cursor: crosshair; }
.pk-fan svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pk-fan .band { fill: var(--line); }
.pk-fan .band.odd { fill: color-mix(in srgb, var(--line) 60%, var(--card)); }
.pk-fan .ray { stroke: var(--card); stroke-width: .5; }
.pk-fan text { fill: var(--text-3); font-size: 3.6px; text-anchor: middle; pointer-events: none; user-select: none; }
.pk-fan .cell { font-size: 3.1px; dominant-baseline: central; fill: var(--text-2); paint-order: stroke; stroke: var(--line); stroke-width: 1.2px; stroke-linejoin: round; }
.pk-fan .cell.odd { stroke: color-mix(in srgb, var(--line) 60%, var(--card)); }
.pk-fan .guide { fill: none; stroke: var(--accent); stroke-width: .45; opacity: .6; pointer-events: none; }
.pk-fan .dot { fill: var(--accent); stroke: var(--card); stroke-width: 1; pointer-events: none; filter: drop-shadow(0 .4px 1.5px #0006); }
dialog h2[tabindex="-1"] { outline: none; }

/* settings: registrations waiting for the admin */
.pending-users { list-style: none; margin: 0; padding: 0; }
.pending-users li { display: flex; align-items: center; gap: .5rem; padding: .4rem 0; border-bottom: 1px solid var(--line); }
.pending-users .name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.pending-users small { display: block; font-size: .75rem; color: var(--text-2); }

/* header: which book the pages show (personal or a household) */
.book-switch { font-size: .9rem; padding: .2rem .4rem; max-width: 12rem; }
@media (max-width: 48rem) { .book-switch { margin-left: auto; max-width: 55vw; } }

/* plan: which books the plan adds together */
.plan-scope { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .75rem; margin-bottom: .5rem; font-size: .9rem; }
.plan-scope .label { color: var(--text-2); }
.plan-scope .chip { display: inline-flex; align-items: center; gap: .3rem; padding: .15rem .6rem; border: 1px solid var(--line); border-radius: 999px; background: var(--card); cursor: pointer; }
.plan-scope .chip input { margin: 0; }
.plan-scope .horizon-switch { display: inline-flex; align-items: center; gap: .5rem; }
.plan-scope .horizon-switch .seg { display: flex; margin-left: 0; }
.plan-scope .horizon-switch .seg button { padding: .25rem .6rem; font-size: .85rem; white-space: nowrap; }
.plan-scope .horizon-switch button:disabled { cursor: not-allowed; opacity: .75; }
.goal .name .book, .entry .by { display: block; font-size: .75rem; color: var(--text-2); }

/* accounts: contributions in or out of this book */
.contributions strong.in { color: var(--status-good); }
.summary .account-actions { margin-top: .5rem; }

/* ---- accounts page: balances with their history, net worth over the
   year, where the money is, recent moves. The board scrolls as a whole
   (cards at their own height) instead of each list scrolling. ---- */
#accounts .board { overflow-y: auto; overscroll-behavior: contain; grid-template-rows: none; grid-auto-rows: auto; align-content: start; }
#accounts .board .pane > .scroll { overflow: visible; }
#accounts .board > .pane { min-height: auto; } /* as tall as its content: the rows must not squeeze cards into each other */
#accounts .board > .networth, #accounts .board > .closed-accounts { grid-column: 1 / -1; }
.book-scope { align-self: center; }
.card-head .change { font-size: .85rem; color: var(--text-2); font-variant-numeric: tabular-nums; }
/* net worth: bars up for what is held, down for what is owed, a line for net worth */
.balance-charts svg { display: block; width: 100%; max-width: 60rem; height: auto; margin: 0 auto; } /* wider would only make it taller */
.balance-chart text { font-size: 11px; fill: var(--text-2); }
.balance-chart.narrow { display: none; }
.balance-chart .hit { fill: transparent; }
.balance-chart .month:hover .hit { fill: color-mix(in srgb, var(--text-3) 10%, transparent); }
.balance-chart rect.held { fill: var(--series-plan); }
.balance-chart rect.owed { fill: var(--series-whatif); }
.balance-chart path.net { fill: none; stroke: var(--text); stroke-width: 2; stroke-linejoin: round; pointer-events: none; }
.balance-chart path.net.estimated { stroke-dasharray: 5 4; opacity: .7; }
.balance-chart .month.estimated rect.held, .balance-chart .month.estimated rect.owed { opacity: .45; }
.balance-chart .net-end { fill: var(--text); stroke: var(--card); stroke-width: 2; pointer-events: none; }
.balance-chart .net-label { fill: var(--text); font-weight: 600; paint-order: stroke; stroke: var(--card); stroke-width: 3px; stroke-linejoin: round; pointer-events: none; }
.networth .legend { padding-left: 0; }
.swatch.held, .swatch.owed { width: .7rem; height: .7rem; border: 0; border-radius: 2px; vertical-align: -1px; }
.swatch.held { background: var(--series-plan); }
.swatch.owed { background: var(--series-whatif); }
.swatch.net { border-color: var(--text); }
.as-table { margin: .5rem 0; font-size: .85rem; }
.as-table summary { cursor: pointer; color: var(--text-2); }
.as-table table { width: 100%; border-collapse: collapse; margin-top: .4rem; font-variant-numeric: tabular-nums; }
.as-table th, .as-table td { padding: .25rem .4rem; text-align: right; border-bottom: 1px solid var(--line); }
.as-table th:first-child, .as-table td:first-child { text-align: left; }
.as-table th { color: var(--text-3); font-weight: 600; }
/* an account's row: name, its year as a sparkline, the amount; Pay on a liability */
.account-row { gap: .25rem; }
.account-row > button, .account-row > .row-body { flex: 1; min-width: 0; align-items: center; }
.account-row > .row-body { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .75rem; padding: .55rem .25rem; }
.account-row .name { min-width: 0; overflow-wrap: anywhere; }
.account-row .name .book { display: block; font-size: .75rem; color: var(--text-2); }
.row-actions { flex: none; }
.row-actions .pay { padding: .25rem .7rem; border: 1px solid var(--accent); background: none; color: var(--accent); font-weight: 600; font-size: .9rem; }
.row-actions .pay:hover { background: var(--accent); color: var(--on-accent); }
.row-actions .paid { display: inline-block; padding: .25rem 0; color: var(--status-good); font-weight: 600; font-size: .9rem; white-space: nowrap; }
svg.spark { flex: none; overflow: visible; }
svg.spark path { fill: none; stroke: var(--series-plan); stroke-width: 1.5; stroke-linejoin: round; }
svg.spark circle { fill: var(--series-plan); }
svg.spark.owed path { stroke: var(--series-whatif); }
svg.spark.owed circle { fill: var(--series-whatif); }
/* where it is: one bar per account, as long as its part of the largest */
.breakdown h3 { margin: .5rem 0 .25rem; }
.shares li { display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .75rem; padding: .35rem 0; border-bottom: 1px solid var(--line); }
.shares .name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.shares .name small { display: block; font-size: .75rem; color: var(--text-2); }
.shares .amount small { color: var(--text-3); font-size: .8rem; margin-left: .25rem; }
.shares .bar { margin-top: .1rem; }
.shares.owed .bar i { background: var(--series-whatif); }
/* recent moves */
.moves-list .move { gap: .5rem; }
.moves-list .name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.moves-list .name small, .members-paid .name small { display: block; font-size: .78rem; color: var(--text-3); }
.members-paid .name { flex: 1; min-width: 0; }
.moves-list .undo { font-size: 1.2rem; }
.moves-list .undo:hover { color: var(--accent); }
.contribution .sub { color: var(--text-3); }
.contribution.payable { gap: .25rem; }
.contribution.payable > button { flex: 1; min-width: 0; }
.contribution-label { margin: 0; font-weight: 600; }
.stop-contribution { align-self: flex-start; }
/* closed accounts */
.closed-accounts summary { cursor: pointer; font-weight: 600; color: var(--text-2); }
.closed-accounts ul { margin-top: .4rem; }
.closed-accounts .name { flex: 1; min-width: 0; }
.closed-accounts .name small { display: block; font-size: .78rem; color: var(--text-3); }
.closed-accounts li { flex-wrap: wrap; }
.closed-accounts .closed-actions { display: flex; gap: .9rem; }
/* the edit dialog: its history, and Close for an account with history */
.amount-dialog .history-link { align-self: center; }
.amount-dialog .close-account { margin-right: auto; border-color: var(--line); color: var(--text-2); background: none; }
.amount-dialog .close-account:hover { border-color: var(--status-critical); color: var(--status-critical); }
/* an account's history sheet */
.activity-dialog { width: min(34rem, calc(100vw - 2rem)); }
.activity-dialog h2 { margin-bottom: .1rem; }
.activity-balance { margin: 0 0 .5rem; color: var(--text-2); }
.activity-balance strong { color: var(--text); font-size: 1.2rem; }
.activity-balance small { color: var(--text-3); }
.activity-dialog svg.spark { width: 100%; height: auto; margin-bottom: .5rem; }
.activity { max-height: 55vh; overflow-y: auto; overscroll-behavior: contain; }
.activity li { display: flex; align-items: baseline; gap: .6rem; padding: .4rem 0; border-bottom: 1px solid var(--line); }
.activity .date { flex: none; min-width: 4.5rem; color: var(--text-3); font-size: .82rem; }
.activity .what { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.activity .what small { display: block; font-size: .78rem; color: var(--text-3); }
.activity .amount { text-align: right; }
.activity .amount.in { color: var(--status-good); }
.activity .amount small { display: block; font-size: .75rem; color: var(--text-3); }
@media (max-width: 48rem) {
  #accounts .board { display: block; }
  .balance-chart.wide { display: none; }
  .balance-chart.narrow { display: block; }
  .amount-dialog .close-account { flex-basis: 100%; margin-right: 0; }
  .activity-dialog { width: 100vw; }
}

/* settings: households */
.households .household { border-top: 1px solid var(--line); padding: .75rem 0; }
.households h3 { margin: 0 0 .25rem; font-size: 1rem; }
.households .members { list-style: none; margin: .25rem 0; padding: 0; }
.households .members li { display: flex; align-items: center; gap: .5rem; padding: .3rem 0; }
.households .members .name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.households .members small { color: var(--text-2); font-size: .75rem; margin-left: .25rem; }
.households .household-head { display: flex; align-items: baseline; gap: .5rem; }
.households .household-plan { display: flex; align-items: baseline; gap: .5rem; margin: .25rem 0; font-size: .9rem; }
.households .household-plan > span { flex: 1; min-width: 0; }
.households .household-plan small { display: block; color: var(--text-2); font-size: .75rem; }
.head-actions { display: flex; gap: .5rem; align-items: center; }
button.link { border: 0; background: none; padding: 0; color: var(--accent); font-size: .85rem; cursor: pointer; }
button.link:hover { text-decoration: underline; }
dialog .status:empty { display: none; }
.households .invite { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .75rem; }
.households .invite p { margin: 0; flex: 1 1 16rem; }
.households .invite small { color: var(--text-2); }
.households .invite-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; }
.households .code { font-family: ui-monospace, monospace; letter-spacing: .08em; }
.households .requests { border-top: 1px solid var(--line); padding-top: .5rem; }

/* header: the notification bell and its list */
.bell { position: relative; display: inline-flex; align-items: center; justify-content: center; padding: .3rem; border: 0; background: none; color: var(--text-2); cursor: pointer; align-self: center; }
.bell:hover { color: var(--text); }
.bell .badge { position: absolute; top: -.1rem; right: -.25rem; min-width: 1.1rem; padding: 0 .25rem; border-radius: 999px; background: var(--accent); color: var(--on-accent, #fff); font-size: .7rem; font-weight: 600; line-height: 1.1rem; text-align: center; }
.notice-list { list-style: none; margin: 0; padding: 0; max-height: 60vh; overflow-y: auto; }
.notice-list li { display: flex; flex-direction: column; gap: .1rem; padding: .5rem .25rem; border-bottom: 1px solid var(--line); }
.notice-list li.unread { font-weight: 600; }
.notice-list li.unread::before { content: "●"; color: var(--accent); font-size: .6rem; margin-bottom: -.2rem; }
.notice-list a { color: inherit; }
.notice-list small { font-weight: 400; font-size: .75rem; color: var(--text-2); }

/* tap rows (budget categories, accounts): what it is and its amount; a tap opens its dialog */
.budgets .tap-row { padding: 0; }
.tap-row > button { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .75rem; width: 100%; padding: .55rem .25rem; border: 0; border-radius: .35rem; background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; }
.tap-row > button:hover { background: color-mix(in srgb, var(--accent) 7%, transparent); }
.tap-row .name { flex: 1; font-size: 1rem; }
.tap-row .amount small, .tap-row .sub { color: var(--text-3); font-size: .8rem; }
.tap-row .sub { flex-basis: 100%; }
.tap-row.over .bar i { background: var(--status-critical); }
.tap-row.over .sub:not(.history) { color: var(--status-critical); }
.tap-row.unplanned .sub:not(.history) { color: var(--unplanned); }
.tap-row.ahead .sub:not(.history) { color: var(--warning); }
.tap-row .name .kind { margin-left: .4rem; font-size: .7rem; color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
.tap-row .sub.history { margin-top: -.15rem; }

/* budget rows: a bullet bar. The fill is what was spent, over a band as wide
   as the budget; a neutral tick marks where spending at the month's pace
   would be today, a dotted one a typical month. Over is critical, unplanned
   its own colour, and only a flexible category runs "ahead" (warning). */
.bullet { position: relative; flex-basis: 100%; height: .55rem; margin: .25rem 0 .1rem; border-radius: .3rem; background: var(--sunken); }
.bullet .band { position: absolute; inset: 0 auto 0 0; border-radius: .3rem; background: var(--line); }
.bullet .fill { position: absolute; left: 0; top: .14rem; bottom: .14rem; max-width: 100%; border-radius: .15rem; background: var(--series-plan); }
.bullet .tick { position: absolute; top: -.2rem; bottom: -.2rem; width: 0; border-left: 2px solid var(--text-2); transform: translateX(-1px); }
.bullet .tick.typical { border-left-style: dotted; border-left-color: var(--text-3); }
.tap-row.over .bullet .fill, .budgets .total.over .bullet .fill { background: var(--status-critical); }
.tap-row.unplanned .bullet .fill { background: var(--unplanned); }
.tap-row.ahead .bullet .fill { background: var(--warning); }
.budgets .total { flex-wrap: wrap; gap: .2rem .75rem; padding: .55rem .25rem; }
.budgets .total .name { flex: 1; }
.budgets .total .sub { flex-basis: 100%; color: var(--text-3); font-size: .8rem; }
/* fixed costs and flexible spending added up, above the total */
.budgets .subtotal { flex-wrap: wrap; gap: .2rem .75rem; padding: .45rem .25rem; color: var(--text-2); font-size: .9rem; }
.budgets .subtotal .name { flex: 1; }
.budgets .subtotal .sub { flex-basis: 100%; color: var(--text-3); font-size: .8rem; }
.budgets .subtotal.over .bullet .fill { background: var(--status-critical); }
.budgets .subtotal.over .sub { color: var(--status-critical); }
.budgets .subtotal.ahead .bullet .fill { background: var(--warning); }
.budgets .subtotal.ahead .sub { color: var(--warning); }
.budgets .subtotal.unplanned .bullet .fill { background: var(--unplanned); }
.budgets li.archived { display: block; border-bottom: 0; padding-top: .75rem; }
.budgets .archived summary { cursor: pointer; color: var(--text-2); font-size: .9rem; padding: .25rem; }
.budgets .archived .name { flex: 1; min-width: 0; }
.budgets .archived .name small { display: block; color: var(--text-3); font-size: .8rem; }

/* category dialog: kind and place in the list */
.kind-choice { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; border: 0; padding: 0; margin: 0; min-width: 0; }
.kind-choice legend { float: left; width: 100%; padding: 0; margin: 0 0 .1rem; font-size: .85rem; color: var(--text-2); }
.seg-option { flex-direction: row; align-items: center; gap: .4rem; padding: .3rem .75rem; border: 1px solid var(--line); border-radius: 999px; color: var(--text); font-size: .9rem; cursor: pointer; }
.seg-option:has(input:checked) { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.seg-option input { margin: 0; min-height: 0; }
.seg-option span { white-space: nowrap; }
.kind-choice .hint { flex-basis: 100%; margin: 0; }
.order { display: flex; align-items: center; gap: .4rem; }
.order .hint { margin: 0 auto 0 0; }
.order button { padding: .25rem .65rem; font-size: .9rem; }
button.danger-fill { background: var(--status-critical); border-color: var(--status-critical); color: var(--surface); }
.fill-list .name small.months { display: block; color: var(--text-3); font-size: .78rem; white-space: normal; }
.fill-list .name small.months span { white-space: nowrap; } /* "Oct 4,5 jt" stays on one line */
.liabilities .tap-row .amount { color: var(--status-critical); }
.amount-dialog .name-field { font-size: 1.1rem; font-weight: 600; }
.amount-dialog .readout { font-size: 1.6rem; font-weight: 700; text-align: center; }
.amount-dialog .readout + .hint { margin: -.5rem 0 0; text-align: center; }
.amount-dialog .picker-readout { display: none; } /* the readout above shows the amount, and "No budget" */
.amount-dialog .term { display: flex; flex-direction: column; gap: .75rem; }
.amount-dialog .term .hint { margin: 0; }
.suggest { display: flex; flex-wrap: wrap; gap: .4rem; }
.suggest .chip { padding: .3rem .6rem; border: 1px solid var(--line); border-radius: 999px; background: none; color: var(--text-2); font-size: .85rem; cursor: pointer; }
.suggest .chip strong { color: var(--text); font-weight: 600; }
.suggest .chip:hover { border-color: var(--accent); }
.fill-list { list-style: none; margin: 0; padding: 0; max-height: 50vh; overflow-y: auto; }
.fill-list li { border-bottom: 1px solid var(--line); }
.fill-list .check { display: flex; flex-direction: row; align-items: center; gap: .6rem; padding: .45rem 0; font-size: .95rem; color: var(--text); }
.fill-list .name { flex: 1; }
.fill-list small { color: var(--text-2); white-space: nowrap; }
.card-head { flex-wrap: wrap; }
.head-actions button { white-space: nowrap; }

/* settings: AI assistants (MCP) and the OAuth consent page */
.ai-assistants h3 { margin: 1rem 0 .3rem; font-size: .95rem; }
.copy-field { display: flex; gap: .5rem; }
.copy-field input { flex: 1; min-width: 0; font-family: ui-monospace, monospace; font-size: .85rem; }
.connect-howto { margin-top: .6rem; }
.connect-howto ol { margin: .5rem 0 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .4rem; }
.connect-howto code { overflow-wrap: anywhere; }
.consent-list { margin: 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .3rem; }
.consent-actions { display: flex; justify-content: flex-end; gap: .5rem; }
.consent-choice { border: 1px solid var(--line); border-radius: .5rem; padding: .5rem .75rem; margin: 0 0 .75rem; display: flex; flex-direction: column; gap: .4rem; }
.consent-choice legend { font-size: .85rem; color: var(--text-2); padding: 0 .25rem; }
.consent-choice .choice { flex-direction: row; align-items: center; gap: .5rem; font-size: .95rem; color: var(--text); }
.consent-access { font-weight: 600; }
.connected-apps .app-actions { display: flex; flex-wrap: wrap; gap: .4rem; justify-content: flex-end; }
.connected-apps .access { font-weight: 600; }

/* ---- amount fields (views.AmountField): what was typed, as rupiah ---- */
.amount-readout { font-size: .8rem; color: var(--text-2); font-variant-numeric: tabular-nums; }
.amount-readout:empty { display: none; }
.amount-readout.bad { color: var(--status-critical); }

/* ---- toasts (views.Toast): over the bottom of the page, above the tab bar
   on phones. #toasts is a manual popover (top layer, over an open dialog);
   only the toasts themselves take clicks. ---- */
.toasts { position: fixed; inset: auto 0 1.25rem; margin: 0 auto; padding: 0; border: 0; background: none; color: inherit; overflow: visible; width: min(28rem, calc(100vw - 2rem)); display: flex; flex-direction: column; gap: .5rem; pointer-events: none; z-index: 50; }
.toasts[popover]:not(:popover-open) { display: none; }
.toast { pointer-events: auto; display: flex; align-items: center; gap: .25rem; padding: .45rem .35rem .45rem .9rem; border-radius: .5rem; background: var(--text); color: var(--surface); box-shadow: 0 6px 24px #0005; font-size: .95rem; animation: toast-in .18s ease-out; }
.toast.bad { background: var(--status-critical); }
.toast .toast-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast button { flex: none; padding: .3rem .55rem; border: 0; background: none; color: inherit; }
.toast .toast-undo { font-weight: 700; text-decoration: underline; }
.toast .toast-close { font-size: 1.15rem; line-height: 1; opacity: .8; }
.toast button:hover { opacity: 1; background: color-mix(in srgb, var(--surface) 15%, transparent); }
.toast.gone { opacity: 0; transform: translateY(.5rem); transition: opacity .2s, transform .2s; pointer-events: none; } /* a fading toast lets clicks through */
@keyframes toast-in { from { opacity: 0; transform: translateY(.5rem); } }
@media (max-width: 48rem) { .toasts { bottom: calc(4.75rem + env(safe-area-inset-bottom, 0px)); } } /* clear of the tab bar (icons over labels) */
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } .toast.gone { transition: none; } }

/* ---- plan page: tools, notices, verdict, coming up, goal notes ---- */
.status.warning { color: var(--warning); }
.status.whatif { color: var(--series-whatif); }
.stat .when, .stat .sub { font-size: .78rem; color: var(--text-3); }
.plan-scope .hint { flex-basis: 100%; margin: 0; }
.plan-tools { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; }
.view-switch button { white-space: nowrap; }
.whatif-field { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; font-size: .9rem; color: var(--text-2); }
.whatif-field > label { font-size: .9rem; }
.whatif-field .amount-field { flex-direction: row; }
.whatif-field .amount-field input { width: 8rem; }
.whatif-field select { width: auto; }
.plan-notices { display: flex; flex-direction: column; gap: .4rem; }
.plan-notices:empty { display: none; }
.notice { margin: 0; padding: .45rem .65rem; border-left: 3px solid var(--warning); border-radius: .35rem; background: color-mix(in srgb, var(--warning) 9%, transparent); font-size: .875rem; color: var(--text); }
.notice.critical { border-left-color: var(--status-critical); background: color-mix(in srgb, var(--status-critical) 9%, transparent); }
.notice a, .notice .link { margin-left: .35rem; color: var(--accent); font-size: inherit; }
.setup { padding: .75rem .85rem; border: 1px solid var(--line); border-radius: .5rem; background: var(--card); }
.setup h2 { font-size: 1rem; }
.setup ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; font-size: .9rem; }
.setup li.done { color: var(--text-3); }
.setup .tick { display: inline-block; width: 1.2rem; color: var(--text-3); }
.setup li.done .tick { color: var(--status-good); }
.setup small { color: var(--text-3); }
.setup a { margin-left: .4rem; color: var(--accent); white-space: nowrap; }
.ask h2 { margin-bottom: .6rem; }
.ask .month-pick > span { display: flex; align-items: center; gap: .5rem; }
.ask .month-pick input[type=range] { flex: 1 1 auto; min-width: 0; }
.ask .month-pick input[type=month] { flex: none; width: 9.5rem; }
.ask .check { flex-direction: row; align-items: center; gap: .5rem; margin: .6rem 0; font-size: .9rem; color: var(--text); }
.ask .check input { margin: 0; }
.afford-result .advice { margin: .4rem 0 0; padding-left: 1.1rem; list-style: disc; display: flex; flex-direction: column; gap: .25rem; font-size: .9rem; }
.afford-result .advice .link { margin-left: .3rem; font-size: inherit; }
.add-to-plan { margin-top: .6rem; border: 1px solid var(--accent); background: none; color: var(--accent); font-weight: 600; }
.add-to-plan:hover { background: var(--accent); color: var(--on-accent); }
.upcoming-list li { display: grid; grid-template-columns: 5.5rem minmax(0, 1fr) auto; grid-template-areas: "date name amount" "date name after"; column-gap: .6rem; align-items: baseline; padding: .45rem 0; border-bottom: 1px solid var(--line); font-size: .9rem; }
.upcoming-list li.hint { display: block; border: 0; }
.upcoming-list .date { grid-area: date; color: var(--text-3); font-size: .8rem; }
.upcoming-list .name { grid-area: name; min-width: 0; overflow-wrap: anywhere; }
.upcoming-list .amount { grid-area: amount; text-align: right; }
.upcoming-list .after { grid-area: after; text-align: right; color: var(--text-3); font-size: .8rem; font-variant-numeric: tabular-nums; }
.upcoming-list .income .amount, .upcoming-list .earning .amount { color: var(--status-good); }
.upcoming-list .low .after { color: var(--status-critical); }
.upcoming .notice { margin-top: .5rem; }
.goals .goal { flex-wrap: wrap; column-gap: .75rem; row-gap: 0; }
.goal-note { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: .2rem .6rem; padding: 0 0 .45rem 2rem; font-size: .8rem; color: var(--text-3); }
.goal-note:empty { display: none; }
.goal-note .good { color: var(--status-good); }
.goal-note .warning { color: var(--warning); }
.goal-note .critical { color: var(--status-critical); }
.goal-note .link { font-size: inherit; }
.goal .when.overdue { color: var(--warning); }
.goal .when.beyond { font-style: italic; }
.goals li.past { display: block; border-bottom: 0; }
.goals li.past summary { cursor: pointer; padding: .5rem 0; color: var(--text-2); font-size: .9rem; }
dialog .check small { display: block; color: var(--text-3); font-size: .8rem; }
@media (max-width: 48rem) {
  .upcoming-list li { grid-template-columns: 4.6rem minmax(0, 1fr) auto; }
  .plan-tools { gap: .4rem; }
  .plan-tools .view-switch { margin-left: 0; }
  .ask .fields.afford { grid-template-columns: minmax(0, 1fr); }
  .whatif-field .amount-field input { width: 6.5rem; }
}
