Style guide

The living design system behind Project Budget — tokens, typography, page chrome, prose, components, and accessibility rules. Every component is rendered with the production CSS, so what you see here is what every page uses.

Every marketing and docs page on this site composes from this set. If a component isn't on this page, it shouldn't be on a marketing page. Add it here first.

How to use this page

Sections are addressable by anchor — the right-side TOC tracks scroll position. New components belong here before they belong anywhere else, so the system stays single-sourced.

Page chrome

Every marketing, docs, glossary, and blog page renders through the same shell:

  • Breadcrumb at the top — Home / Section / Title — with an explicit aria-label="Breadcrumb".
  • Page title (<h1>) and optional subtitle (front-matter subtitle:).
  • Prose body wrapped in .prose — see the typography section.
  • Sticky TOC on the right (≥1024px viewport) — built client-side from h2/h3 inside .doc-content__prose.

Typography

Four families: Playfair Display for hero/display, Lora for headlines, Source Serif 4 for body, DM Sans for in-app UI. The flat type ramp below is what every page draws from — no ad-hoc font sizes.

Lead paragraph

A lead is the first idea a reader meets. It sits in display-serif at --fs-xl with relaxed line-height so the opening line reads like the lede of an article.

Standard prose

Body copy uses Source Serif 4 at --fs-md / 1.65 line-height with a max-width: 70ch measure. Headings inside prose carry deliberate spacing: h2 gets a top rule + --space-2xl top margin, h3 sits closer at --space-xl. h4 renders as small-caps UI text.

Inline elements

Links underline by default — they get slightly thicker on hover. Inline code sits on the alt surface with a subtle border. Keyboard shortcuts render as Cmd+K. Strong and emphasis keep the body weight contract.

Blockquote

"Every dollar gets a job before the month begins."

— Envelope budgeting, paraphrased

Lists

  • Unordered lists use an accent-tinted marker.
  • List items take --space-2xs between them so they read as discrete points.
  • Nest sparingly. If you need three levels, restructure as headings.
  1. Numbered lists follow the same pattern.
  2. Use them when sequence matters.
  3. Otherwise prefer unordered.

Definition list

Ready to Assign
Money you've received but not yet given a job.
Assigned
The dollar amount you've committed to a category this month.
Carry-over
The available balance that rolls into next month's same category.

Tables

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

Code block

// Every dollar gets a job before the month begins.
function rta(profile, month) {
  return inflow(profile, month) - assigned(profile, month);
}

Callouts

Use callouts for inline guidance that breaks out of regular prose flow. Four variants — neutral (accent), --ok, --warn, --danger — picked by semantic intent, not aesthetics.

Default

Neutral callout. Use this for explanatory asides that aren't warnings or errors — context, tips, "good to know" notes.

Success / OK

Confirms a result or a healthy state — "Goal is fully funded for this month."

Warning

For non-blocking caution — "You're about to overwrite assignments for every category."

Destructive

For irreversible action warnings — "Deleting moves the profile to trash for 7 days. Permanent after that."

Info

For informational cross-references — "See the glossary entry on Ready to Assign for a longer definition."

Color tokens

Palette is paper / ink / vermillion / slate / gold — shared with Project Broadsheet so projects feel related without being identical. 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-altalt rows, table heads
--fgbody text
--fg-mutedsecondary text
--fg-subtlesmall print
--accentprimary actions, accent rails
--okpositive available
--warnwarnings, due
--dangerdestructive, outflow

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. 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.

Anything you'll recognize at a glance.

Cards

The default container for any group of related content. 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%)

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)

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.

Accessibility rules

  • Target size. Default buttons, header icon buttons, and modal-close buttons are 44 × 44 CSS pixels (WCAG 2.2 AAA). Compact variants in dense rows are 36 × 36 (AA, 24 × 24 minimum).
  • 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.
  • Color is never the only signal. Amounts pair color with a sign and a number; goal status pairs color with a label.
  • 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 to 0.01ms.
  • Live regions. The toast stack is aria-live="polite"; 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.
Loading…