Sheet A-02 / 04
Design systemsMeridian
Your maturity model speaks in positions. Meridian is the coordinate system.
A design system built from scratch for a platform that plots global capability centres on a maturity model. Every colour step is solved to a contrast target rather than chosen, so the step number is a promise a designer can rely on.
- Client
- Zinnov
- Product
- GCC Intelligence Platform
- Year
- 2026
- Scope
- 382 variables · 240 components · 45 icons
- Role
- Sole designer, system and product
Impact at a glance
- variables across six collections
- 382
- ramps and steps, generated in OKLCH
- 10 × 11
- lines of generator code
- 892
- icons drawn on a 24 grid
- 45
The situation
Zinnov’s maturity model speaks in positions: Outpost, Satellite, Portfolio Hub, Transformation Hub. The platform needed a system those positions could be plotted on. The file it had pointed every colour at a single primitive: no dark mode possible, no module theming, no way to tell decoration from meaning.
From the docs
Primitives are not for designing with. Nobody picks azure-600. They pick text/link, and the mode swaps underneath.
Before
The existing Executive Summary carries both problems: colours with no tier a mode could swap, and the harder one, a grid of equally loud tiles that cannot express consequence.
Before · the Executive Summary today
After · the Brief
- Fourteen tiles, equal weight. Vendor spend and a closing hiring window are the same size, so nothing tells the reader which one expires.
- Status, not consequence. On track, at risk and behind describe a state. None of them says what it costs or what to do.
- The agent findings sit at the bottom. Four real, specific recommendations, each rendered as a notification with a button that goes nowhere.
- Red, amber and green give way to days, dollars and expiry dates, so the semantic layer only has to supply text, surface and one accent.
The method
Every step in every ramp is solved to a contrast target, not picked by eye.
- The step number is the promise: a
600clears AA for text in every ramp, a500clears 3:1 for non-text. - Ramps are generated in OKLCH, so each step is a perceptually even move.
- Read down any column and the ratio is identical across ramps. That is the system working, not a coincidence.
Four surfaces, one token layer
Four surfaces that look nothing alike: a written brief, a forecast timeline, a decision queue, an evidence ledger. None declares a colour. All read the same semantic layer.


The rules that explain most decisions
Seven rules do most of the work, and each one is testable rather than tasteful.
| Rule | What it decides |
|---|---|
| Controls are capsules, surfaces are rounded rects | Mixing the two makes a UI read as one system dropped inside another |
| Glass goes on chrome, never on content | Nav rail, top bar, modals, menus. Never metric cards, tables or charts |
| Colour steps are promises | A step number is a contrast guarantee, not a shade |
| Status is a whole-card treatment | A severity edge, a wash, a label in the status hue, a sparkline that agrees |
| Six chart colours, in fixed order | A seventh series folds into Other, or becomes small multiples |
| Nothing below 12px exists | Removing the token beats discouraging its use |
| An AI claim ships with its evidence | Otherwise it is an assertion in a nicer box |
The calls that could have gone another way
The part that breaks if you touch it
Glass opacity is solved, not styled: each tier is composited over the worst backdrop it can float over, then checked for body text. Lower it because it looks nicer and the surface drops below AA with no visible symptom, until someone cannot read a toolbar.
How it stays maintained
Meridian is generated, not drawn, and that decides how it is maintained:
- Nobody edits the stylesheet. A value moves by moving the generator’s input; everything downstream is rebuilt.
- The contrast check runs before code is accepted. A step below target fails the build. The pipeline enforces the rule; no one has to remember it.
- Changes arrive as a diff, with a reason. A reviewer can see that azure-600 moved, and why.
- One value stays out of everyone’s hands. Glass opacity is never adjusted by eye.
Dark is a different physics
Dark mode is a tier-two override. No component knows it exists.
Light · the default
Dark · a tier-two override
- Elevation stops being a shadow. There is nothing to cast one on black, so the card lifts by luminance and a lit top edge instead.
- The figures saturate rather than pale. A contrast ratio and a perceptual weight are not the same measurement.
- The warm highlight behind the key date drops in lightness and gains chroma, so it still reads as a highlight and not as a selection.
- Hairlines invert direction: a light rule on a dark surface, at a lower delta, because the eye finds edges more easily in the dark.
No shadow casts on black, so elevation reads through a luminance lift and a lit edge. Large figures saturate rather than pale.

Revisions
- Δ1
- Palette regenerated in OKLCH, every step solved to a contrast target.
- Δ2
- Semantic tier added so no component references a primitive.
- Δ3
- Glass opacity solved by compositing against the worst-case backdrop.
- Δ4
- Chart set fixed at six colours, checked in simulation for deuteranopia, protanopia and tritanopia.
- Δ5
- Sizes below 12px removed from the scale rather than discouraged.