Skip to main content

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-green

Accent 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-green

Ink

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-90

Paper

HEX
#fafafa
RGB
250 250 250
CMYK
0 0 0 2

The base surface behind everything. Not pure white.

--white

Supporting

Blue

HEX
#24a8de
RGB
36 168 222
CMYK
84 24 0 13

Section and surface accent, anywhere in the product. Informational states.

--color-blue

Orange

HEX
#ea780e
RGB
234 120 14
CMYK
0 49 94 8

Section accent. Warning states in the product.

--color-orange

Magenta

HEX
#e85d9c
RGB
232 93 156
CMYK
0 60 33 9

Section and surface accent, anywhere in the product. Decorative only.

--color-decorative-magenta

Red

HEX
#e00000
RGB
224 0 0
CMYK
0 100 100 12

Destructive and error states only. Never decorative.

--color-red

Neutrals

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-70

Divider

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-40

Field 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-50

Surface

HEX
#f5f5f5
RGB
245 245 245
CMYK
0 0 0 4

Raised and inset surfaces against Paper.

--color-neutral-10

Legible 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

The fluid steps as the tokens define them.
StepTokenValueUsed for
Display large--font-size-display-largeclamp(2rem, 1rem + 3.5vw, 3.5rem)Page titles and the opening statement.
Display medium--font-size-display-mediumclamp(1.75rem, 1rem + 2.5vw, 2.5rem)Section headings.
Heading 1--font-size-xxx-large28pxThe main heading on a screen inside the product.
Heading 2--font-size-xx-large24pxSubsection headings.
Heading 3--font-size-x-large20pxPanel 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-large16pxThe smallest heading, and long-form reading text.
Body--font-size-medium14pxProse, form fields, and anything read a paragraph at a time. Card titles sit here too.
Small--font-size-small12pxThe 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-small10pxUppercase section labels and counters. The floor — nothing is set smaller, and nothing at this size carries meaning on its own.
Hero--font-size-heroclamp(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-leadclamp(1rem, 0.9rem + 0.5vw, 1.25rem)Standfirst under a marketing heading. Settles at the same size as heading 3.
The two families and the weights we use.
FaceTokenWeights
Montserrat--font-family-displayRegular 400, Medium 500, SemiBold 600, Bold 700
Nunito Sans--font-family-bodyRegular 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 materials

Card

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-green

Marker green, medium

--shadow-marker-green-md

Marker green, small

--shadow-marker-green-sm

Marker pink

--shadow-marker-pink

Measurements

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.

TokenValuePreview
--spacing-00
--spacing-quarter1px
--spacing-half2px
--spacing-14px
--spacing-28px
--spacing-312px
--spacing-416px
--spacing-520px
--spacing-624px
--spacing-832px
--spacing-936px
--spacing-1248px

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.

TokenValuePreview
--border-radius-xs2px
--border-radius-small4px
--border-radius-small-medium6px
--border-radius-medium8px
--border-radius-large12px
--border-radius-xlarge16px
--border-radius-pill999px

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.

TokenValuePreview
--box-shadow-xs0px 1px 2px rgba(0, 0, 0, 0.2)
--box-shadow-sm0px 2px 4px rgba(0, 0, 0, 0.2)
--box-shadow-md0px 2px 8px rgba(0, 0, 0, 0.2)
--box-shadow-lg0px 4px 12px rgba(0, 0, 0, 0.25)
--box-shadow-xl0px 8px 16px rgba(0, 0, 0, 0.25)
--focus-shadow0px 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.

TokenValuePreview
--measurement-input-size-small24px
--measurement-input-size36px
--measurement-button-size-medium44px
--measurement-button-size-large48px
--measurement-button-size-xlarge52px

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.

TokenValue
--color-app-ground#f5f5f5
--measurement-sidebar-width215px
--measurement-header-height64px
--measurement-horizontal-padding32px
--border-width-thin1px

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.

TokenValue
--transition-duration-fast0.15s
--transition-duration-normal0.2s
--transition-duration-slow0.3s

Every length on this page is printed at the comfortable density. The student surface renders the same tokens a quarter larger.