Design SpecimenRandom Fact apps

The app guidelines, rendered from the published tokens

Every control, corner, type style and colour below is drawn with the values @randomfact/tokens 0.4.0 ships (palette.json, theme.css, fonts.css) at the sizes DESIGN.md fixes, in the real webfonts. Contrast ratios are computed live from the hexes. Switch Light, Dark or Both above; the page chrome itself uses §6's header values.

Accepted 2026-09-23

§1

Two chromes

Shell (Can, Convo): sidebar + a 56px page-header bar, mobile-first. Workbench (Inv, Taz): a 56px top bar with wordmark, tabs, workspace trigger, icon actions and ⋮. Both ship from @randomfact/ui; nothing else is allowed.

light

Shell · AppShell

Platform

New ticket

PLAT-58 App design system

Both chromes in @randomfact/ui, one control scale, the extended palette.

PLAT-53 Overview capture on release

Regenerate the screenshots as part of pnpm release.

Page title in the bar is the Section heading style (Exo 600 16px). Sidebar toggle and search are 36-square IconButtons; New ticket is the default Button.

Workbench · WorkbenchShell

TazRandom Fact
OverviewLedgerReports
Acme Ltd
Ledger

September 2026

Scroll inside this frame: the header is sticky, its surface is the page at .84 (light) / .80 (dark) under a 4px blur, with the hairline in --rf-line.

Uncategorised

14 transactions waiting for a category.

Rules

3 rules ran this month.

Exports

Last export 12 Sep 2026.

Team

2 members.

Header row min-h 56, 36px controls, 16px glyphs, 2px progress overlay that never grows the bar. The wordmark is chrome-owned (Exo 700 16.5 + 10px subline), approximated here.

dark

Shell · AppShell

Platform

New ticket

PLAT-58 App design system

Both chromes in @randomfact/ui, one control scale, the extended palette.

PLAT-53 Overview capture on release

Regenerate the screenshots as part of pnpm release.

Page title in the bar is the Section heading style (Exo 600 16px). Sidebar toggle and search are 36-square IconButtons; New ticket is the default Button.

Workbench · WorkbenchShell

TazRandom Fact
OverviewLedgerReports
Acme Ltd
Ledger

September 2026

Scroll inside this frame: the header is sticky, its surface is the page at .84 (light) / .80 (dark) under a 4px blur, with the hairline in --rf-line.

Uncategorised

14 transactions waiting for a category.

Rules

3 rules ran this month.

Exports

Last export 12 Sep 2026.

Team

2 members.

Header row min-h 56, 36px controls, 16px glyphs, 2px progress overlay that never grows the bar. The wordmark is chrome-owned (Exo 700 16.5 + 10px subline), approximated here.

§2

One control height: 36px

Every control that sits in a row is 36px, control text 14px, every glyph 16px. Button has no sm/lg; icon-only is a 36-square IconButton. The one exception is RowAction, 28px, inside a table row or list item only. Chips and badges are one size too: 20px, 12/500, rounded-sm, and never align with a control.

light
36
SaveCancelAssignGhostDeleteSearch transactions…Northwind TradersGroceriesOverviewLedgerAcme Ltd
28
RowAction, 28 square, 16px glyph. Never in a control row beside a 36.
PayeeCategoryAmount
Northwind TradersGroceries−1,204.95
Contoso EnergyUtilities−88.20
SalaryIncome4,250.00
Total2,956.85

Rows: Montserrat 400 14px, numbers tabular-nums right-aligned, total row 600. Chips are the §7 pair at one 20px size, rounded-sm. Input text is 16px below md (iOS zoom), 14px from md; shown at 14 here.

dark
36
SaveCancelAssignGhostDeleteSearch transactions…Northwind TradersGroceriesOverviewLedgerAcme Ltd
28
RowAction, 28 square, 16px glyph. Never in a control row beside a 36.
PayeeCategoryAmount
Northwind TradersGroceries−1,204.95
Contoso EnergyUtilities−88.20
SalaryIncome4,250.00
Total2,956.85

Rows: Montserrat 400 14px, numbers tabular-nums right-aligned, total row 600. Chips are the §7 pair at one 20px size, rounded-sm. Input text is 16px below md (iOS zoom), 14px from md; shown at 14 here.

§3

One radius

--radius: 0.625rem (10px) and the shadcn derivation published as aliases. Solid corner is the new value; the dashed corner is what rounded-* meant before (Tailwind's fixed 4/6/8/12), at 3× zoom. Can, Convo and Inv grow 2px at every step; Taz shrinks 2px.

light
sm · 6px
chips, badges, kbd
Design
3×
md · 8px
every control, menus, menu items
Save changes
3×
lg · 10px
popovers, dialogs, sheets
3×
xl · 14px
cards and panels

Q3 invoices

12 open, 3 overdue

3×

Write the alias, never bare rounded: bare rounded reads --radius itself (10px), larger than rounded-md.

dark
sm · 6px
chips, badges, kbd
Design
3×
md · 8px
every control, menus, menu items
Save changes
3×
lg · 10px
popovers, dialogs, sheets
3×
xl · 14px
cards and panels

Q3 invoices

12 open, 3 overdue

3×

Write the alias, never bare rounded: bare rounded reads --radius itself (10px), larger than rounded-md.

§4

App type styles

Exo speaks (titles, figures), Montserrat reads. Eight styles, no fractional sizes, 12px is the floor, no italic. fonts.css loads exactly Exo 600/700 and Montserrat 400/500/600.

light
Accounts
Page titleExo 700 · 24/32 · tracking-tight
1,204,395.20
FigureExo 700 · 24/32 · tabular-nums
Recent activity
Section headingExo 600 · 16/24 · tracking −0.01em
Q3 invoices
Card titleMontserrat 600 · 14/20
Save changes
Control labelMontserrat 500 · 14/20 · buttons, tabs, triggers
Paid to Northwind Traders on 14 September 2026, matched to rule “Groceries”.
BodyMontserrat 400 · 14/20 · inputs, menu items, cells
Workspace
OverlineMontserrat 600 · 12/16 · uppercase, tracking-wide, --text-2
Updated 2 minutes ago
Caption / metaMontserrat 400 · 12/16 · --text-2

The weights the apps load

Exo 600 — Section headingloaded
Exo 700 — Page title, Figureloaded
Montserrat 400 — Body, Captionloaded
Montserrat 500 — Control labelloaded
Montserrat 600 — Card title, Overlineloaded
Montserrat italic — not loadedsynthesised oblique

The apps load only these five. A weight they leave out renders as the nearest loaded one: an Exo element left at 400 renders 600, a Montserrat element at 700 renders 600. (This site loads the full variable fonts, so that fallback can't be shown live here.)

Numbers in rows and the wordmark

Groceries1,204.95
Utilities88.20
Transport312.00
Total1,605.15

Row numbers are Montserrat tabular-nums at the row's size; Exo numbers are the Figure style only. Wordmark (chrome-owned): InvRandom Fact

dark
Accounts
Page titleExo 700 · 24/32 · tracking-tight
1,204,395.20
FigureExo 700 · 24/32 · tabular-nums
Recent activity
Section headingExo 600 · 16/24 · tracking −0.01em
Q3 invoices
Card titleMontserrat 600 · 14/20
Save changes
Control labelMontserrat 500 · 14/20 · buttons, tabs, triggers
Paid to Northwind Traders on 14 September 2026, matched to rule “Groceries”.
BodyMontserrat 400 · 14/20 · inputs, menu items, cells
Workspace
OverlineMontserrat 600 · 12/16 · uppercase, tracking-wide, --text-2
Updated 2 minutes ago
Caption / metaMontserrat 400 · 12/16 · --text-2

The weights the apps load

Exo 600 — Section headingloaded
Exo 700 — Page title, Figureloaded
Montserrat 400 — Body, Captionloaded
Montserrat 500 — Control labelloaded
Montserrat 600 — Card title, Overlineloaded
Montserrat italic — not loadedsynthesised oblique

The apps load only these five. A weight they leave out renders as the nearest loaded one: an Exo element left at 400 renders 600, a Montserrat element at 700 renders 600. (This site loads the full variable fonts, so that fallback can't be shown live here.)

Numbers in rows and the wordmark

Groceries1,204.95
Utilities88.20
Transport312.00
Total1,605.15

Row numbers are Montserrat tabular-nums at the row's size; Exo numbers are the Figure style only. Wordmark (chrome-owned): InvRandom Fact

§5

Two text tiers

--text-1 and --text-2, no opacity modifiers, no third tier. Taz's --text3 and Inv's --rf-sea-ink-soft both collapse onto --text-2. Ratios are measured against the page and the card.

light
Paid to Northwind Traders--text-1 on page 13.95:1 AA
Matched by rule “Groceries”, 2 minutes ago--text-2 on page 4.59:1 AA
Disabled control text is the only faded textopacity-50, disabled only
Paid to Northwind Traders--text-1 on card 14.68:1 AA
Matched by rule “Groceries”, 2 minutes ago--text-2 on card 4.83:1 AA
No /70: an opacity modifier is a third tier by another name—

What was retired, on its own ground

Taz --text3 on the page#9aa1ac 2.47:1 fails
→ --text-2#6b7280 4.59:1 AA
Inv --rf-sea-ink-soft on the page#475569 7.20:1 AA
→ --text-2#6b7280 4.59:1 AA
dark
Paid to Northwind Traders--text-1 on page 19.17:1 AA
Matched by rule “Groceries”, 2 minutes ago--text-2 on page 8.19:1 AA
Disabled control text is the only faded textopacity-50, disabled only
Paid to Northwind Traders--text-1 on card 16.19:1 AA
Matched by rule “Groceries”, 2 minutes ago--text-2 on card 6.92:1 AA
No /70: an opacity modifier is a third tier by another name—

What was retired, on its own ground

Taz --text3 on the card#5b7185 3.50:1 fails
→ --text-2#94a3b8 6.92:1 AA
Inv --rf-sea-ink-soft on the page#94a3b8 8.19:1 AA
→ --text-2 (already the same value)#94a3b8 8.19:1 AA

§6

Workbench chrome values

Three tokens, not four: --rf-header-bg, --rf-line, --rf-sand. Tab ink is --text-2 inactive and --text-1 on hover and active; the hover fill is sand at 60%. Frame 1640px with a 16px gutter, shared by the bar and the page.

light
Reportsinactive · --text-2 4.59:1 AA
Reportshover · sand 60%, --text-1
Reportsactive · sand, --text-1 13.13:1 AA
Reportswhy not --text-2 on sand: 4.32:1 fails
--rf-header-bg
rgba(250, 249, 247, 0.84)
over the page: --bg at .84
--rf-line
rgba(7, 31, 57, 0.12)
navy hairline
--rf-sand
#e8f4fc
active-tab fill
--rf-sand 60%
color-mix(in srgb, #e8f4fc 60%, transparent)
tab hover fill
Ledger · September 2026Uncategorised · 14 transactionsRules · 3 ran this month
header surface over content, backdrop-blur-sm
dark
Reportsinactive · --text-2 8.19:1 AA
Reportshover · sand 60%, --text-1
Reportsactive · sand, --text-1 15.26:1 AA
Reportswhy not --text-2 on sand: 6.52:1 AA
--rf-header-bg
rgba(0, 0, 0, 0.8)
over the page: --bg at .8
--rf-line
rgba(192, 229, 249, 0.16)
sky hairline
--rf-sand
#0d1f30
= the dark --muted
--rf-sand 60%
color-mix(in srgb, #0d1f30 60%, transparent)
tab hover fill
Ledger · September 2026Uncategorised · 14 transactionsRules · 3 ran this month
header surface over content, backdrop-blur-sm

Palette

Anchors, surfaces and the flipping tokens

The six brand anchors are the same hex in both themes and pair within a layer. The surface system and the data tokens (success, danger, warning) take a value per theme. Brand-blue text (links, marketing headings, the focus ring) is blue in light and sky in dark; blue itself does not flip, and there is no lifted blue (lagoon is retired in tokens 0.4.0). Not restated in DESIGN.md; shown so the app layer can be judged over the ground it sits on.

light

Anchors, paired by layer

gold #f7b600
blue #3f7ca5
cream #fce9a8
sky #c0e5f9
bronze #915e00
navy #071f39

Surfaces and semantic colours

--bg (page)
#faf9f7
--surface (card)
#ffffff
--border
#e5e7eb
--muted
#f1f0ee
--secondary / --accent
#c0e5f9
--primary
#f7b600
on it: #071f39 9.21:1 AA
--destructive
#ef4444
white on it 3.76:1 fails
--ring
#3f7ca5

Blue-as-ink, and the data tokens

A link, and a marketing heading
--rf-blue #3f7ca5 · on card 4.53:1 AA · also --ring
+4.2%
--rf-success #1a7a4a · on card 5.35:1 AA
−1.8%
--rf-danger #c2410c · on card 5.18:1 AA
↑ Price increase
--rf-warning #9a6700 (0.3.1) · on card 4.87:1 AA · page 4.63:1 AA
Delete
--destructive #ef4444 · an action, same in both themes
dark

Anchors, paired by layer

gold #f7b600
blue #3f7ca5
cream #fce9a8
sky #c0e5f9
bronze #915e00
navy #071f39

Surfaces and semantic colours

--bg (page)
#000000
--surface (card)
#0a1929
--border
#334155
--muted
#0d1f30
--secondary / --accent
#14293f
--primary
#3f7ca5
on it: #f1f5f9 4.13:1 fails
--destructive
#ef4444
white on it 3.76:1 fails
--ring
#c0e5f9

Blue-as-ink, and the data tokens

A link, and a marketing heading
--rf-sky #c0e5f9 · on card 13.36:1 AA · also --ring
+4.2%
--rf-success #4ade80 · on card 10.18:1 AA
−1.8%
--rf-danger #fb923c · on card 7.84:1 AA
↑ Price increase
--rf-warning #fbbf24 (0.3.1) · on card 10.62:1 AA · page 12.58:1 AA
Delete
--destructive #ef4444 · an action, same in both themes

§7

Data colour

Twelve categorical hues in four families plus a neutral “Other”. A chart hue clears 3:1 on the page; a chip's ink clears 4.5:1 on its ground over the card. The chart order is the one that keeps adjacent series apart under colour-blindness. There is no red or pink hue.

light

Chart order, hue on the page

1. blue-2
#2971a7
on page 4.97:1 ✓
2. gold-1
#af7c00
on page 3.50:1 ✓
3. teal-3
#006d4b
on page 6.07:1 ✓
4. purple-1
#97549b
on page 4.92:1 ✓
5. teal-2
#33854a
on page 4.34:1 ✓
6. purple-3
#4d478c
on page 7.69:1 ✓
7. teal-1
#008e82
on page 3.84:1 ✓
8. purple-2
#6f57ab
on page 5.50:1 ✓
9. gold-2
#a65d00
on page 4.77:1 ✓
10. blue-3
#31559a
on page 6.89:1 ✓
11. gold-3
#9d4616
on page 6.01:1 ✓
12. blue-1
#1a8ead
on page 3.62:1 ✓
Other · neutral-1
#657383
on page 4.61:1 ✓

Chips, ink on ground over the card, by family

blue-16.90:1 AAblue-27.24:1 AAblue-37.43:1 AAteal-16.74:1 AAteal-27.03:1 AAteal-36.77:1 AAgold-17.36:1 AAgold-27.50:1 AAgold-37.57:1 AApurple-17.65:1 AApurple-27.59:1 AApurple-37.51:1 AAneutral-17.27:1 AA
dark

Chart order, hue on the page

1. blue-2
#4a8fc7
on page 6.04:1 ✓
2. gold-1
#bb881a
on page 6.65:1 ✓
3. teal-3
#0f825e
on page 4.37:1 ✓
4. purple-1
#b06cb4
on page 5.65:1 ✓
5. teal-2
#50a064
on page 6.55:1 ✓
6. purple-3
#635ea5
on page 3.67:1 ✓
7. teal-1
#179a8e
on page 6.05:1 ✓
8. purple-2
#8c74cc
on page 5.49:1 ✓
9. gold-2
#b96f1c
on page 5.35:1 ✓
10. blue-3
#4a70b7
on page 4.29:1 ✓
11. gold-3
#b85e31
on page 4.68:1 ✓
12. blue-1
#1a8ead
on page 5.52:1 ✓
Other · neutral-1
#798898
on page 5.79:1 ✓

Chips, ink on ground over the card, by family

blue-18.77:1 AAblue-28.78:1 AAblue-38.82:1 AAteal-18.71:1 AAteal-28.76:1 AAteal-38.72:1 AAgold-18.84:1 AAgold-28.78:1 AAgold-38.78:1 AApurple-18.85:1 AApurple-28.80:1 AApurple-38.78:1 AAneutral-18.84:1 AA

§8 – §9

The token rule, flipped, and one tokens route

No app declares an --rf-* property and no component file carries a raw hex outside an allow-listed chart module. A design value an app needs is a PLAT change to tokens plus the app's adoption; @randomfact/ui/testing enforces it.

Every app's stylesheet

@import "@randomfact/tokens/fonts.css";
@import "tailwindcss";
@import "@randomfact/tokens/theme.css";

Nothing else from the package. palette.css is the file theme.css imports, not an entry.

The gate fails on

  • an --rf-* or --color-rf-* declaration (bar the four --rf-md-* knobs)
  • an import of @randomfact/tokens/palette.css
  • a components/ui/ folder
  • a raw hex or Tailwind colour-ramp class in a non-test .ts/.tsx
  • a --radius: declaration

Allowed by name

  • setting a published knob: --rf-md-block-gap, --rf-md-heading-lead on a docs selector
  • a chart module listed in chartModules
  • an allow entry with a non-empty reason, which fails as stale once it matches nothing
Values read from @randomfact/tokens 0.4.0 and the platform's DESIGN.md on main (accepted 2026-09-23; the file is a reference of decisions only). Mock chrome (wordmark, nav labels, sample data) is illustrative; the sizes and colours are the published ones. The brand itself — the mark, colour and voice — is in the brand guidelines.