Design reference
The Praktikal design system
The values behind the look — colour, type, spacing, shape, depth and motion — with enough detail to build a page, a deck or a product surface that sits comfortably beside ours.
Representing the brand rather than building with it? The brandbook has the logo files, colours and voice.
Principles
The page is a sheet, the rail is the frame
A product screen is one white sheet held in a frame: the navigation rail down the left, the sheet inset from the chrome by a spacing step and rounded on the corners the frame exposes. There is no bar across the top — the rail already says where you are, so a title band would say it twice. A panel that opens beside the sheet is a column of the same frame, not a layer over it, and it heads itself: the controls that belong to it move under the logo when it opens and back into the bar when it shuts.
Two borders: fields are drawn, controls are inked
Anything you type or choose in takes the light field border. Anything you press takes the ink outline — every button, in every variant, including the quiet ones. The two are a step apart on purpose: it is what lets a toolbar of buttons and a search field read as different kinds of thing at a glance, and mixing them makes a form look like a row of buttons or a toolbar look unclickable.
One look, spoken at the right volume
The marker highlights, inked outlines and hard offset shadows are the house style everywhere — a lesson editor is the same brand as a landing page, and a plain grey card is a surface we have not got to yet. What changes with the surface is how loudly the look is spoken: a dense table takes the small marker step and a tight radius, a hero takes the full one.
Green marks; it does not cover
Both greens mark the one thing that matters on a surface — the primary action, a highlighted word, the item you are on in the navigation. A layout that is mostly green has no accent left, so keep each to small, deliberate areas against paper and ink. Where the current item needs marking, the marker highlight does it: a drawn underline under the label, not a filled block behind it.
Stay on the 4px grid
Every margin, padding and gap is a step on the spacing scale. Consistent rhythm is most of what makes a layout read as ours, and it is the easiest thing to get right.
Generous measure, tight headings
Body text is set at a comfortable line height and a readable line length. Headings are the opposite: heavy, tightly tracked, and allowed to wrap in balance rather than run edge to edge.
One idea per surface
A card, a band, a panel carries a single point. When a surface needs a second, it wants to be two surfaces, separated by a step from the spacing scale rather than a divider.
Motion is feedback, not decoration
Movement confirms something happened — a hover, a state change, content arriving. It never runs on a loop, and it always respects a reduced-motion preference.
Colour tokens
The full palette with the name each colour is known by. Use the named role rather than picking a shade by eye, so the same decision lands the same way twice.
Core
Praktikal Green
- HEX
- #008243
- RGB
- 0 130 67
- CMYK
- 100 0 48 49
The primary. Every primary button, in the product and on this site. Deep enough to carry white text, which is the whole reason it and not the accent does this job.
--color-dark-greenAccent green
- HEX
- #77c043
- RGB
- 119 192 67
- CMYK
- 38 0 65 25
The logo is drawn in it, and so are marker highlights and small accents. It is a fill behind ink, never a background for white text — see the pairings below.
--color-greenInk
- HEX
- #414042
- RGB
- 65 64 66
- CMYK
- 2 3 0 74
Body text, headings, and the dark outline on cards and buttons. Also the full-bleed dark band on the public site.
--color-neutral-90Paper
- HEX
- #fafafa
- RGB
- 250 250 250
- CMYK
- 0 0 0 2
The base surface behind everything. Not pure white.
--whiteSupporting
Blue
- HEX
- #24a8de
- RGB
- 36 168 222
- CMYK
- 84 24 0 13
Section and surface accent, anywhere in the product. Informational states.
--color-blueOrange
- HEX
- #ea780e
- RGB
- 234 120 14
- CMYK
- 0 49 94 8
Section accent. Warning states in the product.
--color-orangeMagenta
- HEX
- #e85d9c
- RGB
- 232 93 156
- CMYK
- 0 60 33 9
Section and surface accent, anywhere in the product. Decorative only.
--color-decorative-magentaRed
- HEX
- #e00000
- RGB
- 224 0 0
- CMYK
- 0 100 100 12
Destructive and error states only. Never decorative.
--color-redNeutrals
Secondary text
- HEX
- #757575
- RGB
- 117 117 117
- CMYK
- 0 0 0 54
Supporting copy, footer links, captions. Build against this token, not against the product's `--color-text-secondary` alias, which currently resolves a step lighter and does not hold its contrast on Paper.
--color-neutral-70Divider
- HEX
- #e0e0e0
- RGB
- 224 224 224
- CMYK
- 0 0 0 12
Rules between rows and sections, and the edge of a panel against the surface it sits on. It separates; it does not enclose.
--color-neutral-40Field border
- HEX
- #c2c2c2
- RGB
- 194 194 194
- CMYK
- 0 0 0 24
The box around anything you type or choose in — text inputs, selects, textareas. Deliberately lighter than a control outline, so a form does not read as a row of buttons. Controls take Ink instead.
--color-neutral-50Surface
- HEX
- #f5f5f5
- RGB
- 245 245 245
- CMYK
- 0 0 0 4
Raised and inset surfaces against Paper.
--color-neutral-10Legible pairs
Which token may carry text on which. The accent is a fill behind ink, so the primary button uses the deeper Praktikal Green instead.
Ink on paper
9.9:1Passes AA
The default. Every long passage of text on our surfaces is this pair.
Ink on accent green
4.6:1Passes AA
The correct way to use the accent behind type: a highlight, a marker bar, a small filled panel.
Paper on accent green
2.1:1 Fails AA
Do not use. The accent is too light to carry white text, which is why the primary is a different green.
Paper on Praktikal Green
4.7:1Passes AA
The primary button. Use this pair wherever you need white text on green.
Paper on ink
9.9:1Passes AA
The dark band. Green stays an accent on it, never the text colour.
Ratios are measured against WCAG 2.1 AA for body text (4.5:1), and computed from the same values the swatches above publish.
Type scale
| Step | Token | Value | Used for |
|---|---|---|---|
| Display large | --font-size-display-large | clamp(2rem, 1rem + 3.5vw, 3.5rem) | Page titles and the opening statement. |
| Display medium | --font-size-display-medium | clamp(1.75rem, 1rem + 2.5vw, 2.5rem) | Section headings. |
| Heading 1 | --font-size-xxx-large | 28px | The main heading on a screen inside the product. |
| Heading 2 | --font-size-xx-large | 24px | Subsection headings. |
| Heading 3 | --font-size-x-large | 20px | Panel and dialog titles. A card in a dense grid takes a step or two below this — the title competes with its neighbours, not with the page. |
| Heading 4 | --font-size-large | 16px | The smallest heading, and long-form reading text. |
| Body | --font-size-medium | 14px | Prose, form fields, and anything read a paragraph at a time. Card titles sit here too. |
| Small | --font-size-small | 12px | The working size of the product, not an exception to it: list rows, table cells, chips, metadata and helper text. A dense surface is set here throughout rather than shrinking one label at a time. |
| Extra small | --font-size-x-small | 10px | Uppercase section labels and counters. The floor — nothing is set smaller, and nothing at this size carries meaning on its own. |
| Hero | --font-size-hero | clamp(2rem, 4.6vw, 3.5rem) | The marketing hero. Shares its bounds with display large, and differs only in how it scales between them. |
| Lead | --font-size-lead | clamp(1rem, 0.9rem + 0.5vw, 1.25rem) | Standfirst under a marketing heading. Settles at the same size as heading 3. |
| Face | Token | Weights |
|---|---|---|
| Montserrat | --font-family-display | Regular 400, Medium 500, SemiBold 600, Bold 700 |
| Nunito Sans | --font-family-body | Regular 400, SemiBold 600 |
Components
How the values above come together on the controls people actually use.
Button variants
Button sizes
Fields
Drawn in the field border, a step lighter than the ink outline on the buttons above. That difference is the whole point: it is what tells a toolbar of buttons apart from the search box beside it.
Compound control
Where two controls do one job they share one box rather than sitting side by side. The sort control is a field and its direction in a single inked outline, divided rather than doubled.
Marker highlight
The drawn underline that marks a word on the site and the current item in the product's navigation. It is a mark under the label, never a filled block behind it — a block would read as a selected row.
Lessons your students actually finish
My materialsCard
The house surface: an inked border, a marker shadow, and one of three radius steps. Pick the step from the surface's size, then hold it — and remember an inner corner owes the border a pixel.
Small radius
A dense surface in a grid or a list.
Medium radius
The default content card.
Large radius
A stage, a panel, a full-width band.
Marker shadows
Hard, zero-blur offset shadows give a surface a printed, stuck-on lift. They are a deliberate graphic effect rather than depth, so a surface never carries one of these and a soft shadow at once. A control moves between the two by state: a button rests on the soft shadow, takes the medium marker under the pointer, and drops to the small one while it is held.
Marker green
--shadow-marker-greenMarker green, medium
--shadow-marker-green-mdMarker green, small
--shadow-marker-green-smMarker pink
--shadow-marker-pinkMeasurements
Spacing
A 4px grid. Every margin, padding and gap comes from this scale — a literal pixel value in a component is a defect, not a shortcut. The reverse is a defect too: a var() naming a token this page does not list resolves to nothing and the declaration is silently dropped, so the fix is to add the step here, not to invent one at the call site.
| Token | Value | Preview |
|---|---|---|
--spacing-0 | 0 | |
--spacing-quarter | 1px | |
--spacing-half | 2px | |
--spacing-1 | 4px | |
--spacing-2 | 8px | |
--spacing-3 | 12px | |
--spacing-4 | 16px | |
--spacing-5 | 20px | |
--spacing-6 | 24px | |
--spacing-8 | 32px | |
--spacing-9 | 36px | |
--spacing-12 | 48px |
Corner radius
Small radii for controls, larger ones for surfaces. A layout picks one step for its surfaces and holds it — with one exception that comes up constantly: where a surface sits inside another, the inner corner is the outer radius minus the border between them, or the two arcs visibly disagree. Node type marks are the only shape drawn outside this scale, as a squircle.
| Token | Value | Preview |
|---|---|---|
--border-radius-xs | 2px | |
--border-radius-small | 4px | |
--border-radius-small-medium | 6px | |
--border-radius-medium | 8px | |
--border-radius-large | 12px | |
--border-radius-xlarge | 16px | |
--border-radius-pill | 999px |
Elevation
Soft, blurred shadows, for depth that should not draw attention to itself — an overlay, a menu, a toast. A surface carrying the house look takes a marker shadow instead. The two never stack, but a control does move between them: a button rests on a soft shadow and picks up a marker one under the pointer.
| Token | Value | Preview |
|---|---|---|
--box-shadow-xs | 0px 1px 2px rgba(0, 0, 0, 0.2) | |
--box-shadow-sm | 0px 2px 4px rgba(0, 0, 0, 0.2) | |
--box-shadow-md | 0px 2px 8px rgba(0, 0, 0, 0.2) | |
--box-shadow-lg | 0px 4px 12px rgba(0, 0, 0, 0.25) | |
--box-shadow-xl | 0px 8px 16px rgba(0, 0, 0, 0.25) | |
--focus-shadow | 0px 0px 2px 2px
color-mix(in srgb, var(--color-primary), transparent 60%) |
Control size
Every interactive box stands on one of these, so a row of mixed controls lines up on its own. A field and an icon button share the input height; a call to action steps up from it.
| Token | Value | Preview |
|---|---|---|
--measurement-input-size-small | 24px | |
--measurement-input-size | 36px | |
--measurement-button-size-medium | 44px | |
--measurement-button-size-large | 48px | |
--measurement-button-size-xlarge | 52px |
Frame
The product is a navigation rail down the left and the page as a white sheet on the chrome behind it, inset by one spacing step and rounded on the corners that show. The rail is not a panel over the page and the page is not a panel over the rail: they are two columns of one frame, which is why the sheet rounds only where the frame lets it.
| Token | Value |
|---|---|
--color-app-ground | #f5f5f5 |
--measurement-sidebar-width | 215px |
--measurement-header-height | 64px |
--measurement-horizontal-padding | 32px |
--border-width-thin | 1px |
Motion
Three durations, and no others. Motion is a short colour shift or a small lift, never a long or elastic movement, and it is dropped entirely when a visitor asks for reduced motion.
| Token | Value |
|---|---|
--transition-duration-fast | 0.15s |
--transition-duration-normal | 0.2s |
--transition-duration-slow | 0.3s |
Every length on this page is printed at the comfortable density. The student surface renders the same tokens a quarter larger.