Links and primary buttons
Brand Guidelines · v1.0
The colour system, type scale and application rules — derived from the live product and measured against it, not sketched alongside it.
Every colour is tied to a role in the interface rather than a decorative mood. That is what stops the palette drifting as the product grows — change the value, and everything playing that role changes with it.
Ocean is a light identity. Surfaces do the work; Primary is punctuation, not a field colour. Aim for roughly this split on any given screen.
Links and primary buttons
Headings, body text, outlines
Cards and reversed text
Accents fill blocks and badges and always carry Ink type on top — all five clear AAA that way. Surfaces are the tinted section grounds that alternate down a page.
Slogan chip, feature blocks
Button hover fill
Badges and the stat circle
Secondary buttons
Review stars
Hero and section background
Alternating sections
Every colour pair the product actually renders, checked against WCAG 2.1. Thirteen pass. Two need attention, and they are called out rather than buried.
Bars are drawn against 7:1 — the AAA threshold for normal text. "Large text" means 24px, or 18.66px bold and above.
At #F5A623 on white the review stars measure 2.03:1. Graphical elements need 3:1. Darkening by 13% lightness clears it and is near-impossible to tell apart at 22px.
Primary on Canvas measures 4.41:1 — fine for the 128px hero word, just under the 4.5:1 needed at body size. Either keep Primary off 18px links on a Canvas section, or darken it fractionally and stop thinking about it.
Section tags, dropdown items, accordion labels, blockquotes, counters and form fields. Inter is the workhorse — it never competes with Syne for attention.
| Hero heading | 128 / 0.98 | display serif |
| Section heading | 96 / 80 | display serif |
| Heading 2 | 60 / 1.2 | Syne 700 |
| Card heading | 32 / 1.13 | Syne 700 |
| Body | 18 / 1.55 | Syne 400 |
| Button | 18 / 600 | Syne 600 |
| Headings sit in Ink. One word may take Primary — that is the only colour a heading gets. | ||
| Body copy is #555753, never pure Ink, so hierarchy holds without extra weight. | ||
| Sentence case everywhere except buttons and eyebrow labels. | ||
| Oversized headings need the condensed display serif — a wider substitute costs a line and breaks the hero. |
Live, not screenshots — hover anything.
| Pill buttons | 80px | 18px / 600 |
| Cards & blocks | 20–30px | |
| Chips | 5px |
The default section ground. Ink headings, grey body.
Alternate with Canvas to separate sections without drawing rules.
One feature block per screen. Any more and it stops highlighting.
Beyond the ten named colours the interface uses a long tail of soft washes — card fills, hover states, section grounds. None are chosen by hand: each is remapped onto the hue of the nearest named colour, which is what stops a rebrand leaving stray colours behind.
Generated, not curated. Don't pick from this grid by hand — add a colour to the named palette and let the tints follow.
Worth knowing before someone files them as bugs. Both are inherent to recolouring a product that was drawn in another palette.
Illustrations are bitmaps, so they can't read a colour variable. They're rotated with a filter instead — -28.9° for Ocean, saturation pulled to 0.788 so secondary hues fade rather than clash. One rotation can only be right about one hue: the primary. Photographs and the wordmark are deliberately excluded, since hue-rotating skin tones looks broken.
Four section and testimonial backgrounds are JPEG textures with the colour baked into the pixels — reachable by neither the tokens nor the artwork filter, so they keep their original tint. You can see it below: the lilac testimonial card on an otherwise all-blue page. Fixing it means re-exporting those four files.
The form-validation red is excluded from the palette by design. Rotating it with the brand turned the error message cyan on a blue identity — off-brand is survivable, an error message that doesn't read as an error is not. It stays #FF4D44 whatever the palette does.
Drop this on :root. Every rule in the stylesheet already reads these tokens, so nothing else needs editing. The 53 supporting tints derive themselves from these ten values.
/* Ocean — Remote Doers */ :root { --bk-primary: #1D6FE0; --bk-ink: #08172A; --bk-paper: #FFFFFF; --bk-mint: #8FE9FF; --bk-pink: #A9C8FF; --bk-yellow: #FFD98A; --bk-lime: #CFF2FF; --bk-star: #F5A623; --bk-cream: #EFF7FF; --bk-lilac: #E4EEFF; }
Edit the ten named values and the tints re-derive themselves. Don't hand-edit the tint list — it's generated by tools/gen_brand_kit.py and will be overwritten.
Let Canvas and Paper hold the page. Ocean reads as calm and light.
Flood a section with Primary. It stops being an accent and the hierarchy collapses.
Put Ink type on every accent block. All five clear AAA with Ink on top.
Put white type on an accent. They're light colours; white disappears.
Give one word of a heading the Primary colour, at heading size.
Use Primary for body-size text on a Canvas section — it measures 4.41:1.
Alternate Canvas and Alt canvas to separate sections without drawing rules.
Introduce a colour that isn't in the palette. Add it as a named token instead.
Keep Ink as a deep navy — it's what stops Ocean feeling like default blue-on-black.
Swap Ink for pure black. The whole palette is tuned against that navy.