Design systems

Forkful

Design tokens and primitives for the calorie tracker: OKLCH colour, type, 4pt spacing, shape, states.

Colours

Every value is authored in OKLCH so lightness stays perceptually even across the ramp. Colour carries meaning here: coral is brand and carbs, berry is protein, teal is fat. The neutrals are warm (hue 25 to 30) so nothing reads clinical next to food photography.

Brand and macros

Coral, brand and carbs--coraloklch(0.655 0.185 28)
Coral deep, pressed--coral-deepoklch(0.58 0.185 27) · 5.6:1
Coral tint--coral-tintoklch(0.955 0.035 32)
Berry, protein--berryoklch(0.565 0.205 354)
Teal, fat--tealoklch(0.70 0.105 195)
Teal deep, text on tint--teal-deepoklch(0.52 0.085 197)

Surface

App canvas--bgoklch(0.975 0.006 30)
Cards and sheets--surfaceoklch(1 0 0)
Inset wells, inputs--surface-2oklch(0.972 0.005 30)

Text

Primary--inkoklch(0.22 0.018 25) · 14.5:1
Secondary--ink-2oklch(0.41 0.016 25) · 7.6:1
Tertiary--mutedoklch(0.515 0.014 25) · 4.7:1

Structural

Hairline border--lineoklch(0.912 0.006 30)
Faint divider--line-2oklch(0.948 0.005 30)

Status

On track--goodoklch(0.62 0.13 162)
Approaching goal--warnoklch(0.78 0.145 70)
Over goal--overoklch(0.60 0.205 25)
Over, tint--over-tintoklch(0.955 0.035 28)

Colour tokens, semantic roles

CSS variableRoleOKLCH
--coralbrand.primary · macro.carbsoklch(0.655 0.185 28)
--coral-deepbrand.pressed · text-on-tintoklch(0.58 0.185 27)
--coral-tintbrand.wash · selected chipoklch(0.955 0.035 32)
--berrymacro.proteinoklch(0.565 0.205 354)
--berry-deepmacro.protein.textoklch(0.50 0.205 354)
--tealmacro.fatoklch(0.70 0.105 195)
--teal-deepmacro.fat.textoklch(0.52 0.085 197)
--bgsurface.canvasoklch(0.975 0.006 30)
--surfacesurface.card · sheetoklch(1 0 0)
--surface-2surface.inset · inputoklch(0.972 0.005 30)
--inktext.primary · 14.5:1oklch(0.22 0.018 25)
--ink-2text.secondary · 7.6:1oklch(0.41 0.016 25)
--mutedtext.tertiary · 4.7:1oklch(0.515 0.014 25)
--linestructural.borderoklch(0.912 0.006 30)
--line-2structural.divideroklch(0.948 0.005 30)
--goodstatus.on-trackoklch(0.62 0.13 162)
--warnstatus.approachingoklch(0.78 0.145 70)
--overstatus.exceededoklch(0.60 0.205 25)

Typography

Albert Sans carries every sentence in the product. Archivo at 125% width and tabular figures carries every number: the calorie ring, macro grams, chart readouts. Splitting the two means a number can grow to 48px without the reading text having to follow it.

Display, ringArchivo · 700 · 125% width · lh 1
1,840
MetricArchivo · 700 · 125% width · lh 1.05
126 g
H1Albert Sans · 700 · −0.02em · lh 1.15
Grilled salmon bowl
H2Albert Sans · 700 · −0.015em · lh 1.2
Today's meals
TitleAlbert Sans · 600 · 0 · lh 1.3
Breakfast
BodyAlbert Sans · 400 · 0 · lh 1.45
The quick brown fox jumps over the lazy dog.
SmallAlbert Sans · 400 · 0 · lh 1.4
The quick brown fox jumps over the lazy dog.
XS / UnitAlbert Sans · 600 · 0 · lh 1.3
kcal left

Font families

CSS variableStackWeightsRole
--font-ui'Albert Sans', system-ui, sans-serif400 · 500 · 600 · 700All reading text and controls
--font-num'Archivo', system-ui, sans-serif600 · 700 at wdth 125Calories, macros, chart readouts

Type scale

CSS variableSizeFamilyWeightLine height
--t-display40pxArchivo7001.0
--t-metric28pxArchivo7001.05
--t-h124pxAlbert Sans7001.15
--t-h219pxAlbert Sans7001.2
--t-title16pxAlbert Sans6001.3
--t-body15pxAlbert Sans4001.45
--t-sm13pxAlbert Sans4001.4
--t-xs11pxAlbert Sans6001.3

Spacing and shape

A strict 4pt grid, named by multiple rather than by t-shirt size, so --s6 reads as 24px without a lookup. Radius climbs with the size of the surface: 8px on inline controls, 28px on sheets, full round on pills and the tab bar.

Spacing scale

--s14px
--s28px
--s312px
--s416px
--s520px
--s624px
--s832px
--s1248px
--s1664px

Radius

--r1 · 8px
--r2 · 12px
--r3 · 16px
--r4 · 20px
--r5 · 28px
--r-full

Spacing tokens

CSS variableValueGrid stepUsage
--s14px1Icon gaps, segmented padding
--s28px2Chip gaps, label to value
--s312px3Inline control gaps
--s416px4Default card padding
--s520px5Screen gutter, chart card padding
--s624px6Between blocks in a sheet
--s832px8Section rhythm
--s1248px12Empty state padding
--s1664px16Scroll clearance above the tab bar

Radius and elevation

CSS variableValueApplies to
--r18pxFocus ring rounding, small tiles
--r212pxIcon buttons inside inputs
--r316pxPrimary button, search field, list rows
--r420pxCards, chart card
--r528pxBottom sheets
--r-full9999pxPills, segmented control, FAB, avatars
--shadow-sm0 1px 2px rgba(30,12,8,.05)Resting inline surfaces
--shadow-card0 1px 3px + 0 6px 16px −10pxCards
--shadow-pop0 8px 28px −8px + 0 2px 8pxSheets, lifted recipe cards
--shadow-fab0 8px 18px −6px rgba(30,14,10,.26)Floating action button

States

Touch targets confirm by shrinking, not by changing colour, so a finger covering the control still gets feedback. Selection is carried by tint plus a 1.5px border plus a darker label, never by tint alone. The focus ring is 2.5px coral at 2px offset on every focusable element.

Primary button

Default
Hover
Active
Focus
Success
Disabled

Chip, selectable

Default
100 g
Selected
100 g
Active
100 g
Disabled
100 g

Search field

Default
Focus
Filled
Over goal

State treatments

StatePropertyTreatment
defaultbackground / border--coral / --line at 1.5px
hoverbackground--coral-deep · 200ms ease-out-quart
active, buttontransformscale(0.97) · 120ms ease-out-quint
active, icon targettransformscale(0.85) to scale(0.92)
focus-visibleoutline2.5px solid --coral · offset 2px · radius 6px
selectedbackground / border / color--coral-tint / --coral / --coral-deep
successbackground / label--good · label swaps to "Added"
over goalbackground / color--over-tint / --over
disabledopacity / pointer-events0.4 · none
Previous
CuraCare

Material Design 3 tonal palette: teal primary, amber secondary, violet tertiary.

Back to start
FluxOps

Scalable component library built for cross-platform consistency.