Semantic
Swap the green and the red on the Science Fair board and a facilitator sets up a children’s activity where the drill and the chompsaws go. The colour is carrying a fact.
Every page shares one stylesheet and one palette. What a colour means does not travel with it. This is where it holds, where it collides, and the rules that would keep it meaning something.
Nine palette colours are defined in assets/ioi.css and are identical
in light and dark. Only the neutrals move between themes. Every colour below is drawn at the three
sizes the system actually uses it: a filled block, a 2px outline, and the 12px dot that codes a card.
This is the size a card’s type dot is drawn at. Three of the nine disappear against a white page. The grey dot on the end is the fallback a card with no accent falls back to — the “no type yet” state.
One question separates them, and it can be asked of any coloured element on any page:
Swap the green and the red on the Science Fair board and a facilitator sets up a children’s activity where the drill and the chompsaws go. The colour is carrying a fact.
Swap the blue and the yellow tile on the dashboard and nothing is wrong, because nothing was claimed. The colour is stopping eight identical rectangles from reading as a wall.
Two consequences follow, and they are the whole of the argument:
| Page | What carries it | What it means |
|---|---|---|
| ELM Science Fair event board |
Card top border + dot | Station type. Green activity · purple quiet activity · blue materials area · red tools station. A key states the scheme; each card repeats it in words. |
| ELM Science Fair event board |
Timeline marker | Orange on two rows marks a requirement that comes from the venue, not from iOi. |
| Poplar 2040 | Matrix fill | Nine build themes, one colour each. The class cards below repeat their theme’s colour, so a class and its theme stay tied down the page. |
| Team ops guide | Pill fill | Green marks the windows when parents and carers are in the school. |
| Team ops guide | Cell left border | Which visitor a row belongs to. Blue and sand carry through from the timetable cells to the people cards, correctly. |
| Team ops guide | Text underline | Yellow underlines a LEGO volunteer’s name. |
| Nature’s Engineers | Diagram stroke | Dashed accent marks where paper is cut or folded; ink is the paper; grey is a tool or a surface. Three roles, no fourth. |
| Page | What carries it | What it means |
|---|---|---|
| Dashboard | Tile top border | Nothing stated. A per-project colour has emerged and mostly holds — TinkerTubs purple, website audit red, iOi in your Home charcoal all match the showcase. |
| Showcase | Card top border | Eight cards, eight colours, in palette order. |
| Ecosystem | Card top border | Rotation within each group of three. |
| Young Makers | Stat number | Six figures, six colours. Red is also used on the page for a genuine problem. |
| Materials template | Callout left border | Six callouts cycle blue, green, orange, purple, red, charcoal. Each is a rule; none differs in kind from the others. |
| Nature’s Engineers | Card top border | Yellow, red, orange on three closing cards that differ in kind but have no declared scheme. |
| Page | What carries it | What it means |
|---|---|---|
| Ten pages | Board border --bc |
Pink has become the default for a timetable board without anyone deciding it. It reads as “this is a schedule”. |
| ELM, team ops | Board border --bc |
Sand marks a second board so it does not read as the same object as the pink one. On ELM it holds the open questions. |
| Makerspace plan | Floor-plan fill | Translucent zones on an SVG. The only place in the workspace colour describes a physical area. |
A card with no accent falls back to --muted. Charcoal is a warm
neutral of almost exactly that lightness. Left to right: charcoal, no type, red. The first two are
the same object as far as a reader is concerned.
The first pass on the Science Fair board.
The fallback, --muted.
What it was changed to.
The measurement behind it: charcoal sits ΔE 6.0 from light
--muted. The next nearest palette colour is sand at 32.3. Charcoal and
sand are the only two entries with almost no chroma — 5.1 and 7.2 against 22.9 or more for
everything else. Charcoal cannot code a category anywhere the untyped state can also
appear.
On the team ops guide, green does three unrelated jobs. None is wrong on its own.
A filled pill on timetable rows.
One of nine build themes, carried from Poplar 2040.
Alongside red for iOi and blue for visitors.
This is the collision most likely to cause a real error, because red is the one colour readers arrive with an expectation about.
| ELM Science Fair | Red is the tools station — powered, cutting, supervised. A hazard reading. |
| Nature’s Engineers | Red is the callout that says the stall must not share a table with the tool area. Also a hazard reading. |
| Young Makers | Red is the callout on a scheduling problem, and also the colour of the first stat number and the first card in two rotations. |
| Team ops guide | Red is the iOi team, next to blue visitors and sand support. A category reading. |
| Poplar 2040 | Red is the Play space theme, the Sensory wall band and the Makedo technique — three meanings stacked vertically in one grid. |
| The hero rule | Every page opens with a red bar under the title. It is the house default, and carries nothing. |
The same job — colouring a card — is done two ways. .accent-*
sets the custom property --ac, which every child element reads. The
inline border-top-color sets only the border. The two cards below are
authored to be the same colour. The dot tells you they are not.
One class sets the border and everything that reads --ac.
The border is blue; the dot silently falls back to the untyped grey.
The inline form is used on the dashboard, the showcase, the ecosystem, Poplar 2040, Young Makers, the team ops pages and the day of play resources. It works today because none of those pages uses a dot, a diagram, a timeline marker or an outlined box. It breaks the first time one of them does.
--ac while this was being written. A card heading that links to
the thing it describes now takes its underline from the card’s accent. On the Science Fair
board, where the cards use .accent-*, it works. On any card coloured the
inline way, a linked heading gets a grey underline under a coloured border. The list of components
that read --ac only grows, which is the argument for rule 5.The Science Fair board states four station types in a key, then uses blue elsewhere on the same page for the Saturday timeline and for the link tile to the venue’s event page. Blue is declared to mean materials area. A reader who has just read the key has no way to know that those two are not stations.
Ratios against the surface each theme actually uses. 3.0 is the threshold for a border, a dot or any other non-text mark; 4.5 for body text.
| Colour | On white | On dark | White text on it | Reading |
|---|---|---|---|---|
| purple | 5.42 | 3.05 | 5.42 | The only one safe under white text. Weakest in dark, but still over the mark. |
| charcoal | 4.05 | 4.08 | 4.05 | Even in both themes. Fails as a category colour for the reason above, not for contrast. |
| red | 3.85 | 4.29 | 3.85 | Comfortable in both. |
| green | 2.92 | 5.66 | 2.92 | Marginal as a mark on white. Fine in dark. |
| blue | 2.47 | 6.70 | 2.47 | Under the mark on white. Reads because it is strongly hued, not because it is dark. |
| orange | 2.31 | 7.16 | 2.31 | Same. |
| sand | 1.65 | 10.02 | 1.65 | Invisible on white, glaring on dark. A ground, never a mark. |
| pink | 1.59 | 10.42 | 1.59 | Same. |
| yellow | 1.52 | 10.86 | 1.52 | Same. The worst on white of the nine. |
Three components in the stylesheet hard-set white text on a colour fill:
.matrix .m-theme, .matrix .m-band and
.gtable th. Only purple clears 4.5 against white. Every use of yellow,
pink or sand in those components therefore carries an inline
color:var(--ink) patch, written by hand each time. The stylesheet also
ends with a selector that matches board headers by substring
— [data-theme="dark"] .board[style*="--pink"] — to fix the same
problem in dark mode. Two hand-maintained lists for one rule.
color:var(--ink). But
--ink flips with the theme while the palette does not, so in dark mode
the text turns pale on a ground that stayed pale. Poplar 2040’s Schools and
Transport theme blocks, the two day of play resource pages, and the three
Roaming pills on the team ops guide all go light-on-light when the theme is switched. Text
on a palette ground has to be a literal #1a1a1a, which is what
.banner and the dark-theme board override in
ioi.css already do. This page hit the same fault while being written.| Coding | Word or shape too | |
|---|---|---|
| ELM station types | Yes | Every card prints its type beside the dot. Works printed in mono. |
| Poplar 2040 themes | Yes | The theme name is inside the coloured block. |
| Team ops — parents in | Yes | The pill says “Parents in”. |
| Team ops — which visitor | No | A 4px left border on a cell, blue or sand, with nothing naming the person it belongs to. The only coding in the workspace that rests on colour alone. |
| Team ops — LEGO volunteers | No | A yellow underline. Yellow is the lowest-contrast colour of the nine, on text, at 1px. |
Five. Each is stated as a sentence someone could apply without reading this page, followed by what adopting it would cost.
If a page carries a legend, every colour on that page must either be in the legend or be a neutral. No decorative rotation on a page that codes anything.
A coded mark always sits next to the word it means, or inside a block containing it. The key is a reminder, not the decoder.
Yellow, pink and sand are grounds — board borders, filled blocks, nothing thinner. Charcoal is a neutral and never codes a category. That leaves blue, red, green, purple and orange as the marking set.
Hazard, blocker, the thing that will go wrong. It is never handed out in a rotation and never codes an ordinary category.
Colour is set by an .accent-* class, never by an inline
border-top-color. The class sets --ac, so
border, dot, diagram and marker cannot drift apart.
A fixed meaning per colour across the whole workspace. Blue cannot be both “materials area” and “a visitor” and “the make step”, and forcing one would break more pages than it helps. The scheme belongs to the page; the discipline belongs to the system.
Three additions, shown rather than made — assets/ioi.css is not
touched by this report. Each removes a class of hand-written patch.
Replaces the inline color:var(--ink) on every pale fill, and the
substring selector at the end of the file.
/* pale grounds carry dark text; saturated grounds carry white */
.on-pale { --on: #1a1a1a; }
.matrix .m-theme, .matrix .m-band, .gtable th, .board__group { color: var(--on, #fff); }
The Makerspace floor plan hard-codes four palette hexes because it needs them at 16–20% opacity. This is why.
.tint { background: color-mix(in srgb, var(--ac) 16%, transparent); }
/* and for SVG: fill="color-mix(in srgb, var(--purple) 16%, transparent)" */
.accent-* covers all nine colours, but nothing marks a mark as
uncoded on purpose, and nothing sets the marking set apart from the fill set. If rule 3 is
adopted, the distinction belongs in the stylesheet rather than in a person’s memory.
.accent-none { --ac: var(--muted); } /* explicitly no type, not "forgot" */
/* .accent-yellow, .accent-pink, .accent-sand documented as fills only */
| volunteer-schedules.html | Links the shared sheet but hard-codes seven palette hexes and a color:#555, once per year group. A palette change would not reach it, and the grey is invisible in dark theme. |
| Nine blocks, four pages | color:var(--ink) on a pale palette ground. Correct in light, light-on-light in dark. Poplar 2040, both day of play resource pages, the team ops guide. |
| Makerspace plan.html | Four palette hexes in the floor-plan SVG, for the opacity reason above. |
| Nature in Motion, Quiet Creative Space | Untyped on the ELM board and reading as a category, because the untyped grey looks like a choice. Deliberate, and correct today — but it depends on nobody using charcoal on that page. |