Skip to the chapter
Fernando Kylas Brand System · Colour Language

Brand System · Foundation chapter

Colour Language

How colour works inside the Fernando Kylas Brand System: what each value is for, what it means, where it may not go, and why every one of those boundaries exists. Three hues, thirteen primitives, and one rule that governs all of them.

Status
Ready for review, not approved
Palette version
v3.1 · warm paper
Canonical source
foundations/colour.md
Ratios measured
2026-07-23 and 2026-07-25
How to read this chapter

This page is the colour language rendered in itself: every swatch, rule and component below is drawn with the tokens it documents, so the chapter cannot drift from the system it describes. Toggle Theme to watch the tokens invert, and toggle Greyscale test to confirm that nothing in this chapter depends on hue to be understood. The markdown at foundations/colour.md remains authoritative for the rules.

Chapter 01

Colour philosophy

Colour is the least load-bearing part of this identity, so it is given the least work to do. That is not modesty. It is the conclusion of a specific test.

Typography carries the identity

Open any page of this system and cover the colour. The identity survives: Strawford's low x-height and open counters, Geomanist's geometric evenness, the measure, the rhythm, the rules. Now do the reverse: keep the colour and replace the type with Arial. Nothing of the brand remains.

That asymmetry is the whole argument. A consultancy that publishes evidence needs its evidence legible in a photocopy, a greyscale print, a screenshot pasted into a client's deck, and a dark-mode inbox. Every one of those destroys colour. None of them destroys typography.

The governing rule

No colour carries meaning alone. Anything communicated by colour must also be carried by text, shape, or position.

Restraint is functional, not aesthetic

Three hues is not minimalism for its own sake. Each additional hue costs three specific obligations, and a palette earns a hue only by paying all three.

Obligation one

Contrast. Measured ratios against every ground it can appear on, in both themes. Two hues is 2 pairs. Six hues is 30.

Obligation two

Meaning. Readers assume a new colour means something. If it does not, it is noise. If it does, that meaning must be documented and never contradicted.

Obligation three

Reproduction. It must hold in CMYK, in greyscale, on a projector, under prefers-contrast: more, and for roughly 1 in 12 men with a colour-vision deficiency.

Why colour supports rather than dominates

The proportion below is the philosophy made measurable. Green is a punctuation mark, not a colour field. If a layout reads as "the green one", the proportion is wrong.

What we deliberately do not do

Not thisBecause
A red / amber / green status paletteFails greyscale, fails deuteranopia, and reads as a dashboard rather than a document
A 10-step tint ramp per hueNine of the ten steps have no documented role, so they become decoration
Pure black #000000See chapter 12
Pure white #FFFFFFSee chapter 12
Colour-coded chapters or sectionsPosition and typography already do this, for free, in print
A second accent "for variety"Variety is not a requirement. Clarity is

Chapter 02

Primary palette

Three brand colours. Paper, ink and one green. Everything else in the system is a neutral serving one of these, or a role that resolves to one of them.

Decided

The paper tone was decided on 23 July 2026 and is the one element of the colour system already settled. Everything else in this chapter is Ready for review.

Paper
Name
Warm paper · token surface · primitive --fk-c-paper
Hex
#F6F4F1
RGB
rgb(246, 244, 241)
HSL
hsl(36, 22%, 95%) · L* 96.26
Purpose
The page and frame ground on light. The default state of every surface.
Meaning
Print, not screen. A document you could hold, rather than an application you operate.
Usage
Page grounds, frame fills, report backgrounds, the ground behind all long-form reading.
Avoid
As a foreground on the raised card (1.07:1) or the green wash (1.05:1), where it disappears. Never as text.
Accessibility
Carries primary ink at 18.03:1, secondary at 8.07:1, tertiary at 5.64:1. On the ink ground it reads at 18.14:1.
Ink
Name
Ink · ground --fk-c-ink #090909 · text --fk-c-ink-1 #0A0A0A
Hex
#090909 ground · #0A0A0A text
RGB
rgb(9, 9, 9) · rgb(10, 10, 10)
HSL
hsl(0, 0%, 4%) · L* 2.47 and 2.74
Purpose
The dark ground, and the primary reading tier on light. Does the most work of any value in the system.
Meaning
Authority and evidence. Every severity, every critical finding and every focus ring resolves here.
Usage
Display type, headings, body copy, meaning-bearing rules, focus rings, the first data series, and the dark theme's ground.
Avoid
Pure #000000 as a substitute; see chapter 12. Never as text on the dark ground.
Accessibility
18.03:1 on paper, 19.29:1 on the raised card, 17.13:1 on the green wash. Legal as a focus ring on every light surface in the system.
Green
Name
Green · token accent · primitive --fk-c-green
Hex
#869F75
RGB
rgb(134, 159, 117)
HSL
hsl(96, 18%, 54%) · L* 62.63
Purpose
The single accent. A signature rule, an underline, a positive finding.
Meaning
Accent, or a positive finding. Nothing else. Green never means "brand" on its own.
Usage
On light: marks only: rules, underlines, dividers, non-text accents. On dark: text and marks.
Avoid
As text on any light ground. As a focus ring on light (2.65:1). On the green wash (2.51:1). As a statistic or figure on light paper. As a logo colour on light.
Accessibility
2.65:1 on paper, failing body, large text and the 3:1 graphical-object floor. 6.86:1 on ink, passing everything. This asymmetry is deliberate; see chapter 04.

Chapter 03

Neutral palette

Ten neutrals, and not one of them is a tint ramp. Six exist only because the system has two grounds: the same job at two different ground luminances.

Light-ground neutrals

surface-raised

#FCFCFB · 1.07:1

border

#E4E3E8 · 1.16:1

text-tertiary

#616161 · 5.64:1

text-secondary

#4A4A4A · 8.07:1

text-primary

#0A0A0A · 18.03:1

Dark-ground neutrals

border · surface-raised

#2A2A2A · 1.39:1

text-tertiary

#8E8E8E · 6.08:1

text-secondary

#ADADAD · 8.87:1

text-primary

#FAFAF7 · 19.04:1

surface-accent (light only)

#EBF0E9 · 1.05:1

The neutrals are not interchangeable between grounds

Each grey belongs to exactly one ground. Using a dark-ground grey on light, or the reverse, is the most common failure in this system and it is always an accessibility failure, never just a stylistic one.

MisuseRatioCorrect token
#4A4A4A as text on ink2.25:1#ADADAD · text-secondary dark
#616161 as body text on ink3.22:1#8E8E8E · text-tertiary dark
#ADADAD as text on paper2.04:1#4A4A4A · text-secondary light
#8E8E8E anywhere on paper2.98:1#616161 · text-tertiary light

Two kinds of line, and the difference matters

This is the distinction most often collapsed in implementation. border is a whisper that groups things a reader has already understood, and at 1.16:1 it is decorative. border-strong is a statement, and it can be the only thing telling a reader where a control begins, so it is measured and it passes at 8.07:1.

border · 1.16:1

A decorative hairline. Correct for grouping. Never the sole signal that this is a control.

border-strong · 8.07:1

A meaning-bearing boundary. Correct where the edge itself carries information.

Recorded inconsistency

border #E4E3E8 is hsl(252, 10%, 90%), a violet-leaning cool grey, and the only cool value in a palette whose paper is hsl(36). It is almost certainly a survivor of the superseded cool palette. No accessibility consequence at 1.16:1, but a coherence one. Recommended fix and impact are recorded as an open item in colour.md §14.5.

Chapter 04

Accent palette

One accent, and it behaves differently on each ground. This is the system's most important asymmetry and the one most likely to be broken by someone who learned the palette on a dark template.

On light paper · 2.65:1


The rule above is green. This text is ink, because green is not a text colour here.

This line is set in green at 2.65:1. It is what the failure looks like: legible enough to pass a glance, and non-conforming.

On dark ink · 6.86:1


The rule above is green. This text is reversed off-white.

This line is set in green at 6.86:1, and it is conforming. The same hex, a different verdict, because the ground changed.

GroundRatioGreen is permitted for
Light paper #F6F4F12.65:1Marks only: rules, underlines, dividers, non-text accents
Raised card #FCFCFB2.83:1Marks only
Green wash #EBF0E92.51:1Nothing. The wash is a ground for ink, never for green
Dark ink #0909096.86:1Text and marks
Dark raised #2A2A2A4.94:1Text and marks
Dark accent wash #1A1E185.82:1Text and marks
When to use green

The signature rule. A link underline. A positive finding. A section mark on a cover. Roughly 5% of a layout, chapter 01.

When not to

Any text on light. Any figure or statistic on light. A focus ring on light. A logo on light. A boundary that carries meaning on its own. As a third data series without a pattern or a label.

Why the green was not simply darkened

The obvious fix creates a worse problem.

A green at 4.5:1 on paper needs roughly L* 47 or below, around #5F7350. Measured against the ink ground it would then sit at about 2.9:1 and fail as dark-ground text, requiring a second green. Two greens means two accents, which fails the restraint argument entirely.

Keeping one green and constraining it to marks on light costs one documented rule. Darkening it costs a second hue and a second set of ratios in perpetuity. The constraint is cheaper than the fix, and it enforces the philosophy, because it is precisely what stops green creeping into text roles.

Chapter 05

Semantic colours

These are role colours, not brand colours, and every one of them resolves to an existing reading token. The system has no success-green, no warning-amber and no critical-red. Meaning is carried by shape and label; the token exists so code has a stable name to bind.

The four channels

Status is distinguished by geometry, so the signal survives greyscale, colour-vision deficiency and a photocopier. Fill, outline and half-fill distinguish values within a channel; the shape distinguishes the channel. Turn on the greyscale test and nothing below changes meaning.

Severity · square

Critical

High

Medium

Low

State · circle

Measured

Estimated

Partial

Not collected

Confidence · dots

High

Medium

Low

Coverage · bar
72%
34%
9%

Every role, and what it resolves to

Role tokenLight resolves to Dark resolves toCarried alongside by
criticaltext-primarytext-primaryFilled square + label
warningtext-primarytext-primaryHalf-filled square + label
successaccent-ink (ink)accent-ink (green)Filled circle + label
informationtext-secondarytext-secondaryOutlined circle + label
observationtext-secondarytext-secondaryOutlined circle + label
evidencesurface-raisedsurface-raisedPanel + source line
confidencetext-primarytext-primary1 to 3 filled dots of 3
disabledtext-tertiarytext-tertiaryaria-disabled + no affordance
unmeasuredtext-tertiarytext-tertiaryDashed outline + "Not collected"
Two names, one value, on purpose

observation and information resolve identically and are kept separate because they belong to different vocabularies: information is an interface notice, observation is an audit finding class. That is a documented relationship, not a duplicate: a future decision could diverge them without touching either call site. This is what the brief meant by documenting the relationship rather than inventing a colour.

Interaction

TokenLightDarkBehaviour
interactive#0A0A0A · 18.03#FAFAF7 · 19.04Link and control text
interactive-hover#0A0A0A · 18.03#FAFAF7 · 19.04Colour does not change; the underline thickens
focus-ring#0A0A0A · 18.03#FAFAF7 · 19.042 px ring, 2 px offset
surface-selected#EBF0E9 · 1.05#1A1E18 · 1.18Ground + a border-strong left rule
Hover never reduces contrast

The obvious implementation, dimming the link on hover, makes the element less legible at the moment the reader has committed attention to it. Instead the text colour holds, the underline thickens from 1 px to 2 px, and the underline may take the accent. The underline exists before hover, so the accent is never the sole carrier.

Focus is ink, not green

Green measures 2.65:1 against paper, below the 3:1 minimum for a focus indicator. Ink measures 18.03:1 on paper, 19.29:1 on the raised card and 17.13:1 on the green wash, so one ink ring is legal on every light surface in the system without a per-surface exception.

Chapter 06

Colour roles

The same thirteen primitives serve five different kinds of work. Confusing the categories is how palettes rot, so a token belongs to exactly one class, and tokens that share a hex still get different names.

Role classWhat it does TokensGoverning constraint
BrandMakes the system recognisable surface, text-primary, accent Never changes without a DECISIONS.md entry
InterfaceMakes controls operable interactive, focus-ring, border-strong, disabled, surface-selected 3:1 for the component, 4.5:1 for its label
EditorialMakes long-form reading comfortable text-primary/secondary/tertiary, border, surface-raised, rule-accent Reading hierarchy must survive greyscale
DataDistinguishes quantities data-1, data-2, data-accent 3:1 against the ground and 3:1 against each other
StatusClassifies findings critical, warning, success, information, confidence, unmeasured Never hue alone; shape and label mandatory
One hex, three names

accent is brand. rule-accent is editorial. data-accent is data. All three resolve to #869F75 and obey different rules, which is exactly why they have different names.

Why only two data series

A data mark must clear 3:1 against the ground and 3:1 against every other mark it can be confused with. On light paper those two requirements collide, and the collision has an exact answer.

The proof

The ground is #F6F4F1, luminance Y = 0.90645. A mark clears 3:1 against it when

(0.90645 + 0.05) / (Y + 0.05)  is 3 or more     so     Y is at most 0.26882

Every usable mark on light paper therefore sits in the band Y from 0 to 0.26882, which is why #8E8E8E (Y = 0.27050) misses at 2.98:1 and green (Y = 0.31149) misses at 2.65:1. Now fit marks inside that band, each 3:1 from the next:

mark 1:  Y = 0            Y + 0.05 = 0.05
mark 2:  Y + 0.05 is 0.15 or more     so  Y is 0.10 or more
mark 3:  Y + 0.05 is 0.45 or more     so Y is 0.40 or more, exceeding the 0.26882 ceiling

Three tone-only series at 3:1 mutual separation are mathematically impossible on light paper. The same calculation on the ink ground gives a floor of Y = 0.10819 and the identical result.

The permitted pair

data-1 and data-2 · mutual separation 3.20:1 on light, 3.13:1 on dark. Both clear 3:1 against their ground.

Beyond two series

Pattern fill: hatching or stippling, which survives greyscale.

Direct labelling: the series name on the series, removing the legend entirely.

Small multiples: one chart per series, which needs no distinguishing at all.

data-accent is available as a third series only with a pattern or a direct label.

Chapter 07

Design tokens

A token name states the job, never the colour. That is the whole grammar, and it is what makes a single component render correctly on both grounds.

The grammar
--fk-<role>                  semantic token: bind to this
--fk-<role>-<variant>        a qualified variant of the same role
--fk-c-<primitive>           raw primitive: reference only, never bind

--fk-text-secondary is correct because it stays correct when the ground inverts and the value changes from #4A4A4A to #ADADAD. --fk-grey-700 would be a lie in one of the two themes.

There are no numeric-scale names in this system: no green-500, no grey-700, no accent-80. A number implies a position on a ramp; a ramp implies nine unused siblings; unused siblings become decoration. Where numeric-scale styles were found in Figma, they were retired; chapter 13.

Vocabulary mapping

For anyone arriving from the Figma variable names or from the naming form proposed in the brief. All three columns name the same job.

This systemFigma variableBrief's proposed form
--fk-surfacesurface--colour-background
--fk-surface-raisedsurface-raised--colour-panel
--fk-text-primarytext-primary--colour-reading-primary
--fk-text-secondarytext-secondary--colour-reading-secondary
--fk-text-tertiarytext-tertiary--colour-reading-tertiary
--fk-accentaccent--colour-accent
--fk-borderborder--colour-divider
--fk-successsuccess--colour-success
--fk-warningwarning--colour-warning
--fk-criticalcritical--colour-critical
Open item: the token prefix is Fernando's call

The brief proposed --colour-reading-primary. The recommendation is to keep --fk-<role>: it is already fully semantic, it is implemented across the Report Engine's seven stylesheets, five templates and validated PDF output, and its product prefix prevents collision inside a consuming application. A rename would touch every rendered artefact and every Figma variable for no gain in clarity or accessibility. Recorded, not resolved, colour.md §4.1.

Chapter 08

Light theme

The default. A warm, slightly dark paper that lets the primary ink sit at 18.03:1 without the harsh edge that pure black on pure white produces at 21:1.

LayerTokenValueBehaviour
Groundsurface#F6F4F1Warm, low-glare, print-led
Raisesurface-raised#FCFCFB · 1.07:1A suggestion of a card, not a box
Highlightsurface-accent#EBF0E9 · 1.05:1The quietest possible emphasis
Reading3 tiers18.03 · 8.07 · 5.64A wide, legible span
Accentaccent#869F75 · 2.65:1Marks only. Figures and text take ink

Background hierarchy

Three grounds separated by 1.07:1 and 1.05:1. Deliberately almost invisible: the raise suggests grouping, it does not draw a box. Note that both separations fall far below the 3:1 threshold for a graphical object, which is permitted for decoration and forbidden for meaning.

surface · #F6F4F1

surface-raised · #FCFCFB · 1.07:1

surface-accent · #EBF0E9 · 1.05:1

Ink on the wash reads at 17.13:1. Text on these surfaces is never the problem; the surfaces' separation from each other is.

Reading hierarchy

Primary ink at 18.03:1

Secondary at 8.07:1 carries supporting copy and long-form body. It is a full reading tier, not a de-emphasis; a paragraph set here is as readable as one set in primary ink.

Tertiary at 5.64:1: captions, labels and metadata only. Never body copy.

Accent behaviour on light

Fernando Kylas

The signature contract: a green rule, a 24 px gap, the name in ink. The rule is a mark at 2.65:1 and carries no meaning alone; the name carries the meaning at 18.03:1.

Chapter 09

Dark theme

Not an inversion. Four things change behaviour, one of them fundamentally: green becomes a text colour.

LayerTokenValueBehaviour
Groundsurface#090909Near-black, never pure
Raisesurface-raised#2A2A2A · 1.39:1More separation than light, still decorative
Highlightsurface-accentrgba(134,159,117,.14)A wash over ink, never a solid pale fill
Reading3 tiers19.04 · 8.87 · 6.08Compressed at the top, wider at the bottom
Accentaccent#869F75 · 6.86:1Text-capable. Gains a role it lacks on light
How contrast is preserved

1 · Green becomes text. 2.65:1 becomes 6.86:1. accent-ink follows it, so a component written once renders ink on light and green on dark.

2 · The tertiary tier gains headroom. #8E8E8E at 6.08:1 on dark is more comfortable than #616161 at 5.64:1 on light.

3 · Surfaces separate more. 1.07:1 becomes 1.39:1, because a raise reads less on a dark ground.

4 · Washes are translucent, never pale. A solid pale panel on a dark page is a hole punched in the document.

What must never happen
#4A4A4A as text on ink2.25:1
#616161 as body on ink3.22:1
A solid pale green panel on ink
Inverting by overriding a fill
Theme inversion is a single-class contract

A surface goes dark by one route: the theme attribute. Never by an inline background, and never by a second mechanism. The moment a surface can go dark by a second route, every token hung off that class silently detaches.

In the previous specimen, two carousel slides set their ground with an inline style="background:var(--ink)" instead of the theme class. The descendant rules never fired, light-paper text values leaked onto a dark ground, and body text rendered at 2.25:1. Treat an inline background on a themed container as a lint error.

The only sanctioned route
<!-- correct: a nested inverted panel inside a light page -->
<aside data-theme="dark"> … </aside>

<!-- lint error: the tokens silently detach -->
<aside style="background: var(--fk-c-ink)"> … </aside>

The dark theme, rendered

The panel below is a nested data-theme="dark" region, the sanctioned route. It renders dark regardless of the page theme, and every value inside it comes from a token.

surface · #090909

Reversed primary at 19.04:1

Secondary at 8.87:1. Below it, green set as text: legal here at 6.86:1, and illegal on the light ground three chapters above.

Green as text at 6.86:1, conforming.

surface-raised · #2A2A2A · 1.39:1

Primary on the raised surface reads at 13.73:1.

Recorded defect

Dark tertiary text on a dark raised surface fails body contrast

text-tertiary #8E8E8E on surface-raised #2A2A2A measures 4.38:1 against a 4.5:1 requirement. Captions, labels and metadata are small text, so a caption inside a dark card is currently non-conforming. Headings and rules are unaffected; they pass the large-text and UI thresholds.

Recommended fix: on surface-raised in the dark theme, promote text-tertiary to #ADADAD (6.40:1). One scoped rule, no new primitive, no change to light.

Not applied here. It changes the rendering of report output already validated and issued as PDF, including an issued client review set. That is a rendering change and wants a DECISIONS.md entry, not a quiet edit. Blocking for any new dark-theme card work.

Print forces light

Print renders the light theme regardless of the reader's screen theme, because ink on paper has no dark mode and a dark-ground PDF wastes toner and photocopies poorly. Colour is otherwise identical: no separate CMYK palette, no print-only accent.

Chapter 10

Accessibility

Accessibility is a gate, not a note. No colour pair enters this system without a measured ratio, and no ratio in this chapter was transcribed from another document.

Thresholds

ElementMinimumNotes
Body text4.5:1Anything below 24 px, or below 18.66 px bold
Large text3:124 px and above, or 18.66 px bold and above
UI components, graphical objects3:1Includes a meaning-bearing rule or icon
Focus indicator3:1Against adjacent colours, both the ring and what it sits on
Data marks3:1Against the ground and against each other
Decorative surface or rulenoneBut it may not be the sole carrier of anything
Disabled controlnoneExempt, but text-tertiary clears 4.5:1 anyway

Contrast matrix: on light paper #F6F4F1

ForegroundRoleRatioBodyLargeUI
#0A0A0Atext-primary, interactive, focus-ring, data-118.03PassPassPass
#090909ink ground used as a mark18.14PassPassPass
#4A4A4Atext-secondary, border-strong8.07PassPassPass
#616161text-tertiary, disabled, data-25.64PassPassPass
#8E8E8Emisuse, dark-ground grey2.98FailFailFail
#869F75accent, marks only2.65FailFailFail
#ADADADmisuse, dark-ground grey2.04FailFailFail
#E4E3E8border, decorative1.16FailFailFail
#FCFCFBsurface-raised, decorative1.07FailFailFail
#EBF0E9surface-accent, decorative1.05FailFailFail

Contrast matrix: on dark ink #090909

ForegroundRoleRatioBodyLargeUI
#FAFAF7text-primary, interactive, focus-ring, data-119.04PassPassPass
#F6F4F1paper used as a mark18.14PassPassPass
#ADADADtext-secondary, border-strong8.87PassPassPass
#869F75accent, accent-ink, success6.86PassPassPass
#8E8E8Etext-tertiary, disabled, data-26.08PassPassPass
#616161misuse, light-ground grey3.22FailPassPass
#4A4A4Athe inline-background regression2.25FailFailFail
#2A2A2Aborder, surface-raised, decorative1.39FailFailFail

On the raised card and the wash

PairRatio
#0A0A0A on #FCFCFB19.29
#4A4A4A on #FCFCFB8.63
#616161 on #FCFCFB6.03
#869F75 on #FCFCFB2.83 · fail
#0A0A0A on #EBF0E917.13
#4A4A4A on #EBF0E97.67
#616161 on #EBF0E95.36
#869F75 on #EBF0E92.51 · fail

On dark surfaces

PairRatio
#FAFAF7 on #2A2A2A13.73
#ADADAD on #2A2A2A6.40
#869F75 on #2A2A2A4.94
#8E8E8E on #2A2A2A4.38 · fail body
#FAFAF7 on #1A1E1816.16
#ADADAD on #1A1E187.53
#869F75 on #1A1E185.82
#8E8E8E on #1A1E185.16

#1A1E18 is the dark surface-accent rgba(134,159,117,.14) composited over ink. A translucent token must be measured composited, never as its own hex.

Beyond contrast

Focus

2 px focus-ring, 2 px offset. Never outline: none without a replacement measuring 3:1 against adjacent colours. Try tabbing through this page.

Increased contrast

Under prefers-contrast: more, secondary and tertiary rise to primary and border is promoted to border-strong. No new colours are introduced.

Meaning-bearing boundaries

A card whose only boundary is border at 1.16:1 is not perceivable as a control. Give it border-strong at 8.07:1, a label, or both.

Never colour alone

Selection pairs surface-selected with a border-strong left rule and aria-selected. Status pairs a token with a shape and a text label.

The greyscale test

Any layout must be readable when every colour is replaced by its lightness value. In practice: print it in black and white. If two things that mean different things become the same thing, the layout is wrong, not the printer.

Chapter 11

Examples

Three Report Engine compositions, graded. Each verdict is a measured claim, not an opinion. Read them for behaviour rather than appearance: the question is never whether a composition looks right, but what survives when a channel is taken away.

Example one

A finding block

Good
NAB-SV-004

The product catalogue exposes 26 characters of text

Critical

The catalogue is delivered as a flipbook. Across 127 products, a crawler can read 26 characters in total. No structured data is present on any product.

Measured

High confidence

Crawl sample, 35 of 362 URLs · 2026-07-22

Why it is good

Zero hue is used, so nothing here can be lost. Severity is a filled square and the word; state is a circle and the word; confidence is three dots and the word. Every signal is carried twice, so removing either channel leaves the finding fully readable. The left rule is border-strong at 8.07:1, legal as a meaning-bearing boundary, where border at 1.16:1 would not be. The test is not whether it reads clearly now; it is whether it still reads clearly after a photocopier, a projector and deuteranopia have each removed something.

Example two

A summary card with a green rule

Acceptable

Clicks · 90 days

11,243

Google Search Console

Impressions

149,633

Google Search Console

Average position

8.2

Google Search Console

Why it is acceptable rather than good

The green rule above each value is decoration; the label, the value and the source carry everything, so the 2.65:1 green is legal precisely because it means nothing on its own. The figures are ink, never green: the exact failure a previous specimen made and corrected, and the reason accent-ink exists at all.

It falls short of good because the card's only boundary is surface-raised at 1.07:1, a separation a reader senses rather than sees. That is legal for decoration and would be illegal the moment the boundary had to mean something. Acceptable is what you get when every rule is obeyed and one signal is still doing less work than it could.

Example three

A three-series chart with a colour-only legend

Poor
Organic Referral Direct
Three separate failures
FailureMeasuredRequired
Series 1 against series 2 (#0A0A0A vs #4A4A4A)2.233.00
Series 2 against series 3 (#4A4A4A vs #869F75)2.713.00
Series 3 against the ground (#869F75 on #F6F4F1)2.653.00

And a fourth, of a different kind entirely: the legend is colour-only. Turn on the greyscale test and the three swatches collapse into one and the chart stops meaning anything, because colour was the sole carrier of which series is which. The three ratio failures make the chart hard to read. This one makes it impossible, and no amount of adjusting the hues would repair it.

Fix: two series using data-1 and data-2 at 3.20:1 mutual separation, labelled directly on the marks rather than in a legend. If three series are genuinely required, use small multiples or add a pattern fill.

Chapter 12

Design decisions

Every decision below can be interrogated. That is the point: a consultancy that sells judgement cannot afford a document whose choices are unexplainable.

Decision 01

Why we avoid pure black.

  1. It is not a printing ink. A rich black on press is a four-colour build; a single-channel #000 prints as a flat, slightly dusty grey. Ink at L* 2.47 is honest about what paper does.
  2. It creates halation on screen. Maximum-contrast black on near-white causes visible edge shimmer at small sizes, especially with Geomanist's even stroke weights. #0A0A0A on #F6F4F1 at 18.03:1 is fully compliant and visibly calmer than 21:1.
  3. It has nowhere to go. With #000 as the darkest value, no darker tone exists for a rule, a shadow or an emphasis.
  4. It reads as default. #000 is what a page looks like before anyone made a decision.
Decision 02

Why we avoid pure white.

Symmetrically: #FFFFFF is a screen artefact, not a paper. Real paper is warm and absorbs light. #F6F4F1 at L* 96.26 reduces glare in long-form reading, flatters both typefaces, and makes the raised card #FCFCFB possible, because a card cannot be lighter than white. The reversed text #FAFAF7 carries the same warmth so a dark page does not read as a different brand.

Decision 03

Why Sage is restrained.

The green is muted (L* 62.63, low chroma) rather than saturated, because a saturated accent competes with the type for attention, and this identity is carried by type. Its 5% proportion is what makes it legible as a signal: an accent that appears constantly stops being an accent.

Its 2.65:1 on paper is not a flaw to be fixed. It is the reason green cannot creep into text roles, which is the main way restrained palettes decay. The constraint enforces the philosophy.

Decision 04

Why semantic colours exist, given they resolve to ink.

A reasonable objection: if critical is just text-primary, why name it? Three reasons.

Intent is recorded. A reader of the code learns that this ink is a severity signal, not a heading. Change has one site. If a future decision gives critical findings a distinct treatment, one token changes rather than every call site. The vocabulary is a checklist. unmeasured and confidence exist because a real-data validation proved reports need to say "not collected" honestly, and a named token makes that state impossible to forget.

Decision 05

Why colour is never decoration.

A consultancy sells judgement. A document that decorates itself invites the question of what else was decided for appearance rather than reason. Every colour in this system can be interrogated: this ink because it is the primary reading tier at 18.03:1; this green because the finding was positive; this grey because it is metadata. Nothing is here because it looked better.

Decision 06

Why three reading tiers and not five.

Measured, the span 18.03 to 8.07 to 5.64 is already fine-grained. A fourth tier would sit where readers cannot perceive a difference but authors must still choose. Hierarchy beyond three tiers is carried by size and weight, which cost nothing in contrast and survive greyscale perfectly.

Chapter 13

Figma parity

The repository is canonical for rules. Figma is canonical for geometry. Where they diverge, the markdown wins and Figma is corrected, and this chapter exists partly because they had diverged.

The contract

Every semantic token exists as a Figma Colour Stylebound to the matching variable, so one style resolves in both modes

Every Colour Style corresponds to a documented tokenno orphans in either direction

Primitives are separated and marked reference-onlynever applied directly to a node

A dark ground is set by mode, never by a fill overridethe single-class contract, chapter 09

Retired 2026-07-25

The file carried fifteen styles that no document referenced: white-100 to white-60, black-100 to black-60, accent-100 to accent-60. A style no document claims is a style no one owns, and an unowned style drifts. All fifteen were retired, on three separate counts:

Fifteen numeric-scale Colour Styles carrying superseded values

ProblemEvidence
Superseded values black-100 was #09090B and white-90 was #FAFAFA, precisely the cool pairing this chapter supersedes. white-80/70/60 and black-90/80/70/60 were a cool grey ramp belonging to no Fernando Kylas palette.
Drifted values accent-100 was #879F75, one hex digit from the canonical #869F75. accent-70 was #EBF0E8 against the canonical #EBF0E9. Small enough to survive review, large enough to prove the styles had no authority.
Numeric names accent-80 states a ramp position, not a job: exactly the form chapter 07 forbids.

169 nodes had to be rebound to semantic styles before a single style could be deleted: 168 logo vectors and the cover ground. The drift had travelled further than the styles that caused it, which is the argument for a standing parity contract rather than a periodic audit. Recorded in DECISIONS.md; recoverable from Figma version history.

Three hues. One rule that governs all of them. Everything else is measurement.

Fernando Kylas

Provenance

Canonical source. foundations/colour.md, authoritative for every rule on this page.

Ratios. Computed 2026-07-23 (v3.1 palette) and 2026-07-25 (states, interaction, composites, data series, surface matrices) using WCAG 2.x relative luminance over sRGB. Not transcribed.

Rendered with. The Report Engine design system at platform/design-system/css/, the reference implementation of these tokens. Every component on this page is a real engine component.

Figma. File 8THxEHQJfyzTAdJbd83YcO, page 05 — Colour System. Audited 2026-07-25.

Status. Ready for review, not approved, except the paper tone. Passing review or QA is evidence of readiness, not approval.

Related. Identity System · foundations/typography.md · foundations/accessibility.md