Stella

STELLA / DESIGN SYSTEM / 0.1

Numbers you can
read across the room.

A dark rail against warm off-white paper. Newsreader for page titles and every metric, Inter at 14px for the labels, rows and controls you read a hundred times.

See the components
  • Editable source
  • Light and dark
  • 44px on a coarse pointer

63 primitives · 63 stories · 5 palettes · 64 screens

Mode and palette

Graphite · active palette

On-time delivery · Northern network · last 30 days to 14 Sep 2026

95.8%up 0.5 pts

against a 95.0% target, and 95.4% eight weeks ago

20 JulWeekly, % of drops on time · dashed is the target7 Sep
Open this in the command centre
light · graphiteLive tokens. No hexes.
background
brand
foreground
ring

01 / THE PRINCIPLES

Six rules the system does not bend.

Stella is built for screens whose subject is a number. These six decide what the rail does, which face carries a figure, and what a colour is allowed to mean.

01

Colour has three jobs.

The palette owns the neutral spine, the brand family and the focus ring. Accents label what a thing is. Status labels how it is going. None of the three ever borrows from another.

02

The corner does not scale.

4px on every control, from a 28px chip to a 44px button. 8px on every surface. Circles are for avatars and palette swatches, and nothing else.

03

Two faces, two jobs.

Newsreader at weight 400 carries page titles and every metric. Inter at 14px carries labels, rows, controls and captions — the text you read a hundred times.

04

The rail does not flip.

The rail is a chip with its own surface and its own ink, so #14120f holds in both modes. Light mode is a dark rail on warm paper; dark mode is the same rail, one step deeper than the page.

05

A number carries its unit.

49.5%, 305 users, 31 days — 305 alone is a riddle. A delta carries its sign, so ↑5% reads before the colour does, and every figure is tabular.

06

Grey the baseline, colour the subject.

One series is the answer; the rest are context, drawn in --chart-neutral. Four series is the ceiling, zero is on the axis, and the chart survives being printed in grey.

02 / COLOUR

Five palettes. One set of meanings.

A palette owns the neutral spine, the brand family and the focus ring — nothing else. Graphite is the default, and its primary action is near-black ink rather than a colour, so the only saturated things on the page are the numbers. Choose one to repaint the page.

A palette never changes the meaning.

Status is fixed across all five palettes, and every status carries a word as well as a colour. Colour is the second signal here, never the only one.

BrandRunningComplete4 rows need reviewProvider timed out

The three surfaces you build on.

--background

--card

--muted

21 palette slots · generated contrast · no component hexes

03 / TYPOGRAPHY

Two faces. Two jobs.

Newsreader takes page titles and every metric. Inter takes labels, rows, controls and captions. Both are variable, open-licensed and self-hosted, and both load in the app and in Storybook.

Newsreader Variable / 400 / -0.02em

A number you can
read across the room.

The display weight is 400, never bold — size and tracking carry the emphasis. The serif takes titles and figures and nothing else: a table header, a row and a form label are Inter.

Page title / text-h1 · 28 / 1.2 · serif 400

Provider match rates

Section title / text-h3 · 16 / 1.4 · sans 600

Rows that failed enrichment

Body / text-body · 14 / 1.55 · sans 400

4 of 120 rows failed — the provider returned no match.

Supporting / text-body-sm · 13 / 1.5 · sans 400

Last run 14 Sep 2026, 09:12 UTC.

04 / SHAPE

One corner for controls. One for surfaces.

Buttons, inputs, selects, tabs and chips all take 4px. Cards, popovers, sheets and dialogs take 8px. Two values, not a ladder that grows with the component — proportion is the signature, so a 32px button and a 44px button carry the same corner.

The corner does not scale.
Three heights, one 4px radius.

rounded-control / 32 · 36 · 44px

Roles, not random corners.
A field and a tab are controls. A card is a surface. That is the whole ladder.
4px / rounded-tab
8px / rounded-surface

No breakpoint changes the radius.

05 / ELEVATION

One hairline. One shadow. One ring.

A card is a border and no shadow. Only overlays lift, and every one of them uses the same --shadow-overlay. Focus is a separate 2px ring on --ring — press Tab to see it. Depth states a relationship; it never fills empty space.

On the page
One hairline is enough to give a group a place.
A panel inside a card

No floating tiles, no doubled frames, and no shadow standing in for a divider.

border-border / shadow: none

Above the page
The scrim makes the relationship clear. Escape returns you to the origin.

shadow-overlay / bg-scrim

Every floating surface uses --shadow-overlay rather than inventing a depth of its own.

Where the keyboard is
The focus ring is visible, deliberate, and painted once.

2px outline / 2px offset / --ring

Error changes the border. Keyboard focus adds an outline. Neither resizes the field.

06 / LAYOUT

One gutter per container.

Space states the relationship: 4 and 8px inside a group, 12 to 24px between related parts, 32px between decisions. A container owns one gutter — 16px, or 24px above md — so its heading, its content and its footer land on the same edge.

Shared tracks, no guesswork.

The grid is a tool, not a decoration. Turn it off and the alignment should still hold.

Source
Matched
Failed
4px
8px
12px
16px
24px
32px

At the narrow end the composition changes, not just the scale. Cards stack, filters fold into a sheet, and a wide table becomes a list of records. The page itself never scrolls sideways.

320px minimum / controls lift to 44px below 768px

07 / MOTION

A response, not a performance.

Motion in Stella confirms that something changed. It never moves the thing you are about to press, and it never animates a number into looking like a trend.

Ready on scroll. The four recipes take turns while this section is on screen.

ONE CURVE

One curve, every time

Ready on scroll
  1. 01

    Colour response

  2. 02

    Overlay fade

  3. 03

    State change

  4. 04

    Bounded loading

cubic-bezier(0.2, 0, 0, 1) / 160ms default / 300ms overlays

01Resting

Colour response

A press darkens the fill. The button keeps its 4px corner, its height and its place under the cursor.

160ms / --ease-standard / colour only

02Resting

Overlay fade

A layer above the page fades in slowly enough to follow. It never grows from a point.

300ms / --ease-standard / opacity only

03Resting

Live updates

Every 60 min

State change

The thumb and the track change together, so the switch reads as one event.

160ms / --ease-standard / one event

04Resting
Enriching 120 rows
x

Bounded loading

Ambient motion is kept for work that has not finished, and stops the moment it has.

1.4s loop / while pending only

WHERE MOTION STOPS

Three cases the system refuses

Rows enriched today

1,284

1,297

Data never tweens

A number replaces itself. Nothing counts up between two values, so nothing hints at a direction that is not there.

0ms / transition: none

Arrives above, not inside

Feedback never pushes

Notifications float above the layout and field messages reserve their line, so the page never jumps under the reader.

Overlay feedback / undo / no layout shift

motion on
reduced

same final frame

Reduced motion keeps meaning

Turning motion off removes the journey, never the destination. No meaning lives in a skipped frame.

prefers-reduced-motion: reduce

  1. Immediate

    Focus and live values tell the truth without delay.

  2. Still

    Targets never shift, scale or bounce away from the cursor.

  3. Restrained

    No ambient loop competes with reading or comparing.

  4. Inclusive

    Reduced motion keeps every final state and its meaning.

08 / THE COMPONENTS

Every primitive, doing real work.

Three rows of live primitives. Try the forms, open the overlays, change the filters. Every colour comes from the palette you chose; not one of them is a hex.

24 working specimensScroll to explore

01 / actions

The primary action
Primary, secondary and quiet actions.
A quieter action, and a reversible one

Name the report before publishing. A disabled action says what unblocks it.

02 / preferences

Preferences
Switches and checkboxes with labelled targets.

One summary a week instead of an alert for every run.

03 / navigation

Two views, one strip
Tabs keep related views in reach.

Last 24 hours

18 runs finished. 2 of them returned failed rows.

2 failed

04 / invite

A form that validates
One field, one error, one way forward.

Give a teammate read access to this workspace.

05 / people

Who owns the run
A person, with no extra chrome.
JR

Jamie Rivers

Data lead · Enrichment

Owns the provider integrations and reviews every run that returns failed rows.

On call

06 / dialog

One decision at a time
A focused layer with a clear way back.

One decision, one layer, and a clear way back to the page.

Dialog / Input / Button

07 / feedback

What went wrong
Success, failure, and a way back.

08 / files

A local file
A file picker with honest feedback.

Choose a CSV to enrich.

Local preview only. Nothing is uploaded or sent.

09 / notes

A note with a budget
A textarea that counts down to 180.

0 / 180 characters

Write a note to enable saving.

10 / search

Search that filters
Typing removes rows and nothing else moves.
Provider match rates8 columns
Failed enrichment rows12 columns
Weekly active users5 columns

11 / empty

Nothing here yet
An empty state with exactly one action.
No views yet
A view saves a filter, a sort and its columns.

12 / disclosure

Answers on demand
Three questions, no wall of text.

13 / range

A value and its progress
A slider that drives a real bar.
40 min

A shorter interval costs more provider calls. The default is 60 min.

20 min elapsed
x

14 / filters

Filters in a sheet
A sheet that returns a count, not a guess.

3 views shown

Provider match rates

Failed enrichment rows

Weekly active users

15 / loading

Loading holds its place
Skeletons match the content's geometry.

Real line boxes / reserved space

16 / badges

Status carries a word
Every colour is paired with a label.
DraftRunningComplete4 rows need reviewProvider timed out

Every state carries a word as well as a colour, and status keeps its meaning in all five palettes.

ReportsRuns

17 / avatars

The people on a run
An avatar group with initials as fallback.
  • Jamie RiversData lead
  • Alex LaneAnalyst
  • Robin WellsReviewer

3 collaborators / initials as fallback

18 / radio

One choice of three
A radio group with full-height rows.

Preview schedule: weekly summary. No notifications are sent.

19 / select

Sorting a list
A native select that really re-sorts.
  1. Failed enrichment rows12 columns
  2. Provider match rates8 columns
  3. Weekly active users5 columns

20 / toggle

A reversible toggle
Pressed state reads without colour alone.

Failed rows, last 7 days

Pin a view to the top of the rail. Press again to unpin it.

In its usual place in this preview.

21 / tooltip

A hint, not a dependency
Helpful for pointer and keyboard alike.

Hover or focus for a little context. The action works without reading it.

Preview notifications are on.

22 / popover

Details in place
An anchored popover, not a detour.
View details

More context without leaving the row you are reading.

23 / separator

One hairline per seam
Separators give related content its order.

Weekly active users

Distinct users who ran at least one query in the period.

5 columnsShared view

One hairline between the figure and its details.

24 / pagination

One page at a time
Pagination over real records.

Provider match rates

Reports

8 columns.

View 1 of 3

09 / DATA

You, against everyone else.

Five forms, one organisation, one seeded table. The subject is always the coloured mark and the comparison is always grey — a quantity with no opinion attached. Every figure carries its unit, every series carries its name, and nothing here needs colour to be read.

Appointments offered within seven days

72.8%

up ↑ 5.4 ptsover the twelve months to September 2026

8.5 points above the peer median, which finished the year at 64.3%.

  • Your network72.8%
  • Peer median64.3%

Per cent of appointments

Twelve months to September 2026. The axis starts at 55% because nothing here is a bar; the reading is the distance between the two lines, and it is labelled.

Median wait, by service

Two series per category: yours in colour, the peer median in grey.

Days

  • Your network
  • Peer median

Zero is on the axis, so a bar's length is its whole value, and the unit is named once beside the axis rather than on every tick. Skin is the one service where the network waits longer than its peers — the chart is allowed to say so.

Top 6 sites

Ranked by the share offered within seven days.

Six of 22 sites. Bars start at zero and the scale runs to 100%, so the ranking and the gaps are both readable. Every value is printed, so the axis would only repeat it.

How the network is spread

All 22 sites, counted into five-point bands.

Sites

Per cent offered within seven days, in five-point bands

Median site 73.7%. The middle half sits between 66.9% and 80.0%, and the whole range runs 52.8% to 88.6%. One average would have hidden all of that.

When the week is busy

One measure, ordered by magnitude — the one place a ramp is correct.

Appointments booked by weekday and hour of the day
Weekday080910111213141516
Mon08:00 — 18 appointments09:00 — 26 appointments10:00 — 31 appointments11:00 — 29 appointments12:00 — 22 appointments13:00 — 14 appointments14:00 — 21 appointments15:00 — 25 appointments16:00 — 17 appointments
Tue08:00 — 24 appointments09:00 — 33 appointments10:00 — 38 appointments11:00 — 35 appointments12:00 — 26 appointments13:00 — 16 appointments14:00 — 24 appointments15:00 — 28 appointments16:00 — 19 appointments
Wed08:00 — 21 appointments09:00 — 29 appointments10:00 — 34 appointments11:00 — 31 appointments12:00 — 24 appointments13:00 — 15 appointments14:00 — 22 appointments15:00 — 26 appointments16:00 — 18 appointments
Thu08:00 — 20 appointments09:00 — 28 appointments10:00 — 33 appointments11:00 — 30 appointments12:00 — 23 appointments13:00 — 15 appointments14:00 — 23 appointments15:00 — 27 appointments16:00 — 18 appointments
Fri08:00 — 16 appointments09:00 — 23 appointments10:00 — 27 appointments11:00 — 25 appointments12:00 — 19 appointments13:00 — 12 appointments14:00 — 17 appointments15:00 — 20 appointments16:00 — 13 appointments
1238 appointments in the hour

1,055 appointments across the week. Busiest hour: Tuesday at 10:00, with 38 booked. The lunch column is the pale stripe down the middle.

Grey the baseline, colour the subject.

The peer median is drawn in --chart-neutral in every form it appears — line, bar, legend. A comparison given a sixth hue would compete with the five that mean something.

It has to survive being printed in grey.

Position, label and order carry the reading; hue only reinforces it. Two series at most in any comparison, both named, and the ramp is ordered so its steps still read as steps with the colour taken out.

A number carries its unit.

The unit is named once at the axis rather than on every tick, the delta carries its sign before it carries a colour, and every figure is tabular so columns line up.

--chart-1 · --chart-neutral · --chart-grid · --chart-seq-1 … --chart-seq-6 · text-metric-2xl · text-delta

10 / IN SITU

Six real screens, running inside this page.

Everything above is inventory: colour, type, shape, motion, components. This is what they add up to. Each panel is a live route from the screen library, on the palette and mode you are reading in right now.

Live routesNot screenshotsTheme follows
01/05/analytics-001Open in a tab
Loading /analytics-001 …

Command centre

The reference surface: a collapsing dark rail, four charts that grey the peer series and colour the subject, and a summary row where every figure carries its unit and its comparison.

These six are a sample. The library carries 64 built screens across 13 groups, every one a route in this repository on these tokens.

Browse the screen library