A quiet system for spending, written down.
SPND is a personal finance product built on restraint. The system values hierarchy over decoration, tabular numerals over illustration, and thin dividers over drop shadows. This codifies every token, component, and pattern that appeared in v0.1 — and extends them with the states, semantic roles, and variations the product needs to grow.
Five rules that hold the system together
If a decision ever feels uncertain, fall back to these.
Color, shadow, and motion are spent carefully. Reach for a hairline before a card, a card before a shadow.
Every amount is tabular and right-aligned. Currency symbols are de-emphasized.
Tiny uppercase labels (10px / 0.15em) replace headings in dense contexts.
A divider-separated list carries the same meaning with a quarter of the visual weight.
Primary is slate; accent is reserved for positive progress and the single most important thing on a screen. If two things are accent-colored, one is wrong.
Cool neutrals carry the interface; one muted accent earns attention.
A 12-step cool slate ramp plus a single sage accent. Semantic colors share the same chroma and lightness so nothing shouts.
Inter for everything human, JetBrains Mono for everything counted.
Inter carries the interface. Monospace is reserved for technical metadata — hex codes, token names, transaction IDs — so real numbers (amounts) can keep Inter's tabular lining figures.
A 4-pixel base with 12 ramps.
Rows sit at sp-4. Section separation uses sp-7. Screen padding is sp-5 horizontal. Don't invent new values.
Sharp at small sizes, soft at large.
Icon wells and avatars are pill-shaped. Buttons and cards are lg (12px). Inputs md. Match the parent.
Five levels. Most things live at 0 or 1.
Elevation communicates floating, not importance. Sticky headers use 0 + hairline. Popovers use 4. In between is usually solvable with a border.
Material Symbols — outlined, 400 weight, 20 optical size.
One family, one style. Filled variants reserved for selected/active states only.
Single-select chips in a horizontally-scrolling row.
Bordered field or borderless in-row edit.
The workhorse of the whole system.
Every transaction, every settings item, every budget line is this row. Left: icon + title + secondary. Right: trailing value + meta.
Four pixels tall. Color communicates proximity to your limit.
Label + trailing hairline rule.
The most-used pattern in the system. Replaces h3 headers inside dense lists with near-zero vertical cost.
One scope per row, stacked vertically.
When more than one filter axis is needed, stack rows rather than packing everything into a single scroller.
Currency small and light, amount huge and tabular.
160px. Four segments max. Center shows a percent.
Icon · one-line title · 28-char description · one action.
Write like a line item. Count like an accountant.
- Tone
- Neutral, descriptive, never cheerful about money. "Under budget" is enough — skip "Great job!"
- Case
- Sentence case everywhere. Eyebrows are the only uppercase.
- Currency
- Symbol before amount, no space:
$142.30. Two decimals, always. - Negatives
- Minus sign
−(U+2212), not parentheses or red. - Dates
- Relative first (Today, Yesterday), then
Oct 24. - Merchants
- Use the merchant's own capitalization. Fade out instead of truncating mid-word.
A few specific traps, called out.
Every token on one wall.
Neutral ramp
12 stepsAccent & semantic
mutedType scale
Inter + MonoSurface tokens
copy-paste| Token | Light | Dark | Use |
|---|---|---|---|
| --bg | #FFFFFF | #0B0F17 | page |
| --surface | #F8FAFC | #111826 | wells |
| --outline | #E2E8F0 | #1F2A40 | borders |
| --fg | #1E293B | #E6EAF2 | text |
| --primary | #334155 | #E6EAF2 | CTAs |
| --accent | #65816B | #93AE99 | progress |
Radii
match parentElevation
0 or 1Motion
3 durations| --dur-fast | 120ms | hover |
| --dur-base | 180ms | transition |
| --dur-slow | 320ms | progress |
| ease-out | (.2,.8,.2,1) | entrances |
| ease-std | (.4,0,.2,1) | default |
List rows
workhorseDonut
patternLive system.
Change a token on the left — the system recomputes everywhere.