Color tokens

Palette is shared with Project Broadsheet — paper / ink / vermillion / slate / gold — so projects feel related without being identical. Variable names stay app-local (--bg, --fg, --accent) so swapping themes touches one file. Every text-on-surface pairing below clears WCAG 2.2 AA (4.5:1 for body, 3:1 for large text and UI surfaces) in both light and dark themes.

--bgpage
--bg-elevatedcards, modals
--bg-alttable heads, alt rows
--fgbody text
--fg-mutedsecondary text
--fg-subtlesmall print, hints
--accentprimary actions, links
--okpositive available
--warnwarnings, due
--dangerdestructive, outflow

Typography

Four families: Playfair Display for masthead and modal titles, Lora for headlines, Source Serif 4 for body, DM Sans for in-app UI. Type scale is fluid where it counts (KPIs, hero) and a flat ramp everywhere else.

Display / 4xlMoney has a job.
Display / 3xlMoney has a job.
Headline / 2xlMoney has a job.
Headline / xlMoney has a job.
Headline / lgMoney has a job.
Body / mdEvery dollar is assigned before the month begins.
Body / baseEvery dollar is assigned before the month begins.
UI / smFilter, search, totals.
UI / xsField hints, eyebrow labels.
Mono$2,400.00 · acct_xyz_123

Spacing scale

Nine steps from 3xs (4px) to 3xl (96px). Grids and components compose from this scale — never raw pixels.

  • --space-3xs4px
  • --space-2xs8px
  • --space-xs12px
  • --space-sm16px
  • --space-md24px
  • --space-lg32px
  • --space-xl48px
  • --space-2xl72px
  • --space-3xl96px

Buttons

Default-size buttons are 44 × 44 CSS pixels minimum (WCAG 2.2 AAA target size). The compact variant btn--sm is 36 × 36 and reserved for dense table rows. Every variant has an explicit :focus-visible ring and a :disabled state.

Primary

Secondary

Ghost

Danger

Forms

Every input is paired with a visible <label>. field__hint is for non-essential help text; required and error messaging live above or beside the input, never as the only signal. Inputs are 44 px tall (matching the button target size) so the form line aligns with the action row.

Anything you'll recognize at a glance.

Cards

The default container for any group of related content inside the app shell. Cards have horizontal overflow on so tables inside them scroll laterally on phones instead of forcing the page wider.

Storage

Profile data is held in your browser's localStorage. Typical quota is 5–10 MB.

182.4 KB used of 5 MB (4%)

Tables

Numeric columns use .num (right-aligned, tabular-nums). Tables inside cards scroll horizontally on phones.

DatePayeeCategoryAmount
Apr 18Whole FoodsGroceries-$48.22
Apr 17PayrollIncome$2,400.00
Apr 15ComcastInternet-$79.99

Badges

For inline metadata — status, tags, counts. Pair color with a label so the meaning isn't color-only.

active duplicate card payment split (3)

Alerts & help blocks

For inline guidance and warnings. The .form-help block carries a left accent border so it reads as advisory, not error.

All imports run in your browser. The file you select never leaves this page.

Toasts

Bottom-right transient notifications. The container is aria-live="polite"; each toast carries role="status" so screen readers announce them without interrupting the user.

Profile 'Household' created.

Delete cancelled — typed name did not match.

Could not save changes. Check browser storage settings.

Modals

Every modal carries role="dialog" and aria-modal="true". Esc closes; click-outside dismisses. Destructive actions require typed-name confirmation (see the delete-profile flow).

Accessibility checklist

  • Target size. Default buttons, header icon buttons, and modal-close buttons are 44 × 44 CSS pixels (WCAG 2.2 AAA). Compact buttons in dense table rows are 36 × 36 (AA, 24 × 24 minimum). Dense controls (.cleared-toggle) render at 28 × 28 but extend their hit area to 44 × 44 via a transparent pseudo-element.
  • Focus visible. Every interactive element has a 2 px solid --accent outline plus a 4 px soft halo on buttons. Skip-link slides into view on focus.
  • Contrast. Body text ≥ 4.5:1, large text and UI surfaces ≥ 3:1 in both themes. --fg-subtle was retuned to clear 4.5:1 on the paper background for small print.
  • Color is never the only signal. Amounts pair color with a sign and a number; goal status pairs color with a label; reconciled state pairs background with the lock icon.
  • Semantic structure. One <h1> per page. Landmarks (header, nav, main, footer) wrap their regions. Tables use <th scope="col">.
  • Keyboard. Esc closes modals. Skip link goes to #main. Every action available by mouse is available by keyboard.
  • Reduced motion. prefers-reduced-motion collapses every animation and transition to 0.01ms.
  • Live regions. The toast stack is aria-live="polite" + aria-atomic="true"; individual toasts use role="status".
  • Forms. Every input has a paired <label for="...">. Required state is conveyed by the attribute and the label, not by color.