Skip to content

Cards

All cards: 24px radius, 24px inset, --surface on --canvas, 1px --border, no resting shadow.


14. BalanceCard

The hero. One trusted number. This is the component a user opens the product to see.

Layer 1: radius 24 · inset 24 · min-width 280 · height auto Layer 2:

┌─ 24 ────────────────────────────────┐
│  [eyebrow]  ·  [account mark]        │  ← row, space-between
│   8                                  │
│  [figure]                            │
│   8                                  │
│  [delta]  ·  [as-of]                 │
│  16                                  │
│  ├─ full-bleed sparkline ──────────┤ │  ← optional, bleeds to 3 edges
└──────────────────────────────────────┘

Layer 3: eyebrow (1 line, truncate) · figure (never truncates) · delta (1 line) · media (aspect-[4/1], full-bleed) · actions (max 2) Layer 4:

Slot Token Weight Color
eyebrow label 13/16 500 --text-secondary
figure figure-hero 40/48 500 --text-primary
delta caption 12/16 400 semantic

3 sizes, 2 weights ✓

Available vs. current. A bank balance has two values and they differ. Show available as the figure; current as a secondary line when they diverge. Conflating them is the most consequential copy error in consumer banking UI.

Motion: none at rest. Value flash when live. Sparkline draws once. Interactive variant gets press scale(0.97) and a 1px hover lift.

Responsive: figure steps 40 → 28 below a 280px container. Sparkline drops below 240px.

Edge cases: negative balance (overdraft — parens and a --negative figure, plus an explicit "Overdrawn" pill) · redacted · stale (dim to 0.7 + StaleIndicator) · very long account name.


15. KpiCard

Label · figure · delta · optional sparkline. The dashboard atom.

  • Baselines align across a KpiRow. Use grid with auto-rows-fr and a shared figure row, or two cards with different label lengths will have their figures at different heights — the most visible alignment failure on any dashboard.
  • Display family forbidden here. Figures align across the row.
  • polarity required, no default. Forcing the decision is the point.
  • The comparison basis is always shown: vs. Aug, never a bare +5.3%.

Loading: skeleton with the figure block at the exact figure width, or the card jumps when data lands.


16. AccountCard

Bank account: institution mark, masked number, type, available and current balances, sync status. Tapping opens the transaction list filtered to it.

Handles disconnected and reauth-required states prominently — a stale bank connection silently showing an old balance is a real financial hazard. Stale accounts dim and surface a "Reconnect" action.


17. PaymentMethodCard

The physical object. Two of the four sanctioned delight moments — the flip and the tilt.

Geometry, from ISO/IEC 7810 ID-1:

aspect-ratio: 1.586          (85.60 × 53.98 mm)
border-radius: 3.7% / 5.9%     (3.18mm — 3.7% of width, 5.9% of height)

Real proportions matter — a card at 16:9 with a 24px radius reads as a rectangle, not as a card.

Face: flat, single tint from the issuer color, network mark bottom-right, masked PAN in tnum with ss02 (so a 0 isn't an O), holder name in label uppercase, expiry MM/YY.

Motion:

  • Flip to reveal CVV — rotateY(0→180deg), spring.playful, real 3D with preserve-3d + backface-visibility: hidden. Not a crossfade. Spec.
  • Pointer tilt — ±6° from pointer position via spring.track, plus a specular sheen at opacity 0→0.12. Desktop only, gated behind @media (hover: hover) and (pointer: fine). Springs home on leave.
  • Reduced motion: instant swap, no tilt.

The tilt is decorative and it's licensed only because the card is decorative. The same effect on a KpiCard is a review failure.

Security: CVV and full PAN are never in the DOM until revealed, never in analytics, never in a screenshot-able state without an explicit user action.


18. RunwayCard

Months of runway, current cash, monthly burn, projected zero date. A burn line with a projection segment rendered dashed, because a projection is not a fact.

polarity="inverted" on burn. Runway under 6 months triggers --warning; under 3, --negative — and the threshold is configurable, because it's a business judgment, not a universal truth.

19. InvoiceCard

Number, customer, amount, due date, aging state (current / 1-30 / 31-60 / 61-90 / 90+). Overdue is --negative with the day count, never color alone. Partial payments show paid vs. outstanding.

20. SubscriptionCard

Vendor mark, amount, cadence, next charge, annualized cost. Annualized is the useful number — $49/mo is $588/yr, and showing it is what makes a spend review actionable.

21. AnomalyCard

A flagged deviation, with the comparison that triggered it and one clear action (approve / flag / create rule). Never a bare alert — an anomaly without its baseline is noise.

22. GoalCard

Target vs. actual with a progress rule (a rule line, not a rounded progress bar — consistent with the statement grammar).

23. StatCard

The minimal unit: label + value. 16px inset, no delta, no media. For dense grids where a KpiCard is too much.

The 10 components specified here.

Built against this document

The surfaces that implement what this argues — running, computing, or shaped by it.

Told when this spec changes

The docs are the contract the components are built against. When one changes, the component changes with it — and the copy in your repo does not. One email when that happens.

One address, no list rental, unsubscribe in one click.

Works in your QuickBooks Online or Xero file

Get your books closed every month

Lopifi is building AI bookkeeping that keeps your books closed on US GAAP as transactions happen, with a CPA review every quarter, for $200 a month. We’re not open yet.

$200/month when we open. No card now.