Structure in ink; colour only where there is data or a decision.
The one-page contract for Baseline 0.4: colour, type, spacing, elements, figures and layouts on a single sheet. Public Sans is the fork's core family; every other law is the parent's, kept. Four colours, two families, square edges, one accent.
01
Colour
four roles · no fifth · accent ≤ 4%
Roles
Ground#F3F2F2
Ink#201E1D
Accent#EC3013
Counter#2F4B9B
Neutral ramp · warm
100 → 900 · rules, fills, tints
Accent ramp · 500 is accent
100 · 300 · 500 · 700 · 900 · OKLCH-derived, retheme by one hex
Counter signal · cool
cool against warm — direction reads before the legend
Chart tints · ordered
neutral 200→800, peak is accent 900 — never a sixth hue
Diverging · sign keeps reading
accent falls ← → signal rises · fixed on luminance
Ink steps · text
Body — ink
Secondary — neutral 800
Tertiary — neutral 700
Mark — accent 700
Signal — signal 700
Accent budget · ≤ 4%
one mark in twenty-five · count filled controls first
02
Typography
Public Sans · JetBrains Mono · no italic
Plate · 44
Finding
H4 · 34
Section head
H5 · 24
Block title
Lead · 21
Lead prose sits above the body.
Body · 19
Body carries the argument in Public Sans.
Caption · 14
Caption carries the sample: what, where, when, n.
Annotation · mono
M 6.4 · 412 km · 32.08°N
A—12 · FIG 2 · REV C
Label grade · 11 / caps
The finding · method · scope
1,420
tabular
Hierarchy · the descent
One finding
Section — a claim
Body carries the argument.
Label · method
The rules of rank
One H1 per sheet — the finding. Every other level descends from it: section, block, body, caption, label.
A thick-thin rule pair (2px + 1px) opens the masthead; a 2px rule with the sheet number closes the surface.
One vertical hairline per page — body from apparatus. More than three dividers means space is doing too little.
Method sits beside the finding, never above it. One left edge per zone, drawn or not.
03
Spacing & grid
one ladder · 12 columns · square
The ladder · seven measures
8
16
24
32
48
64
96
8 label · 16 group · 24 between · 32 block = gutter
48 figure→caption · 64 page margin · 96 section→section
12 is off the ladder — a new decision, not a nudge
12 columns · gutter 32 · margin 64
1232 content · narrows 12 → 8 → 4 · margins 64 → 40 → 24
Sanctioned splits
7 + 5
8 + 4
4·4·4
12
6+6
equal halves claim equal rank
9+3
3 columns can't hold a 14px note
3+6+3
centred by construction
04
Elements
live components · square · one accent
Buttons
Segmented
Switch
Checkbox · radio
Chips
Selected
Filter
Field
Label
Value
Stat
Events
2,622
+8%
Table
Region
Events
Indonesia
1,420
Japan
1,180
Tag · delta
Rev C
▲+2.6
▼−4.2
Stepper
−
07
+
Pagination
1
2
3
Breadcrumb
Baseline/Sheets/A—12
Toast · status row
SAVE-04
Sheet issued.
Empty state
No matches
05
Figures
two edges · range-frame · one accent
Column · sorted
Range-frame line
Dot plot
06
Layouts
six sanctioned · three surfaces
The six sanctioned sheet layouts
L1 Finding · 7+5
L2 Comparison · 8+4
L3 Index · 4·4·4
L4 Table · 12
L5 Opener · 12 inv
L6 Panel · live
The three surfaces
Sheet · L1 finding
7+5 · apparatus column
Panel · L6 live
selection holds the scale
Plate · drawing
crop marks · title block
07
Patterns & rules
nine fills · two weights · never behind text
dot open
dot dense
hairline grid
dashed
registration
hatch · forecast
crosshatch
no data
rule stack
Rule weights
2px · section boundary
1px · division within
Annotation rule
the one accent rule · everything else ink
08
Brand, icons & dark ground
Register · Lucide 1.5px · .on-inverse
The mark · Register
Baseline
crop corners + one accent dot · lockup on centres
Icons · Lucide 1.5px
one set · 24 on 24 · currentColor · always labelled
Baseline
.on-inverse
Index
71.4
−4.2 fall
+2.6 rise
One class flips the whole set — the semantic names correct per scope, so the mark brightens and the numerals stay legible on dark. No per-component prop.
Voice · claims, not topics
“We drew it four ways. Three were lying.”
Five months in twelve lose money
Monthly profit overview
flat · specific · the number and its provenance in one breath
09
Components & structure
82 components · 14 groups
Shown · display & overlay families
Tabs
Counts
Index
Legend
Major
Minor
Disclosure
Method
Counted, not modelled.
Tooltip
1,420 events
Progress
controls · inputs · figures · furniture drawn live in §04 · §05 · §07 · below
Shown · figure families
Waterfall
Ring
Scatter
Waffle
Slope
Area
DivergingColumns
BarRows
Histogram
BoxPlot
StackedBar
Bullet
Gauge
Funnel
TreeMap
Matrix
CorrelationMatrix
StripPlot
RadialBar
BumpChart
FanChart
Calendar
Schedule
Sankey
ChordDiagram
Choropleth
SmallMultiples
Shown · controls, inputs, diagrams, plate, navigation, text
IconButton · Tag
Rev C
RangeSlider
NodeGraph
DotField
PlateFrame
RegisterRail
A—12
A—13
Numeral
71.4
82 across 14 groups — Controls 7 · Inputs 5 · Display 6 · Furniture 10 · Figures 32 · Annotation 3 · Diagrams 4 · Plate 2 · Overlay 3 · Navigation 3 · Layout 3 · Text·Icons·Feedback 4
Furniture · shown
SectionHead
03
The finding
SheetStamp
Sheet
A—12
Callout
StepIndex
010203
MarkerList
01
Four colours, no fifth
02
Two families, one job each
RegistrationMark
also live above · Masthead · SheetFooter · Rule · Delta
Elevation · one mechanism
Drawer, not shadow. Butts a viewport edge behind a 2px ink rule, opaque ground, no scrim — the page stays interactive. Menu, Combobox and Toast follow; nothing floats.
Motion & state
Hover changes colour only; press adds an ink ring. Nothing scales, lifts or bounces. Nothing animates past 120ms, linear.
Controls · geometry
46px standard, 40px compact. Square edges, flush-left labels, 2px focus ring offset 2px. Native elements throughout.
10
Build contract
load order · seven traps
Page head · in order
1 · styles.css — tokens
2 · react · react-dom · babel
3 · lucide.min.js — before the bundle
4 · _ds_bundle.js — last
templates/<slug>/ds-base.js does all of this. Always define a / a:hover from the palette.
Seven traps · caught before render
icons-silent
Load Lucide before the bundle, or every icon is a silent 0×0.
inverse-ground
Inside .on-inverse the dark ground is --color-bg, not --color-text.
control-fill
--control-fill is accent-700; count filled controls first in the 4% budget.
pattern-text
Never a pattern behind text; use the component's ground prop or a chip.
axo-shrink
Axonometric can't squeeze — give it its width or wrap to one column.
svg-style
A standalone .svg loses its <style>; inline the markup to keep the type.