When a business signs up, Cleo reads their website and proposes a brand kit: logo, typefaces, colours. Everything Cleo makes afterwards draws on that kit, so a wrong colour here is not a cosmetic slip. It is repeated in every image, email and post that follows.
The colour reader originally worked from stylesheets. Fetch the CSS, collect the colours, rank them by how often they appear. It is a reasonable first approach, and it fails in an instructive way.
What a stylesheet actually lists
A stylesheet records every colour a site is capable of painting. It does not record which ones it does paint. Modern sites ship compiled utility classes for states most visitors never see: form errors, disabled buttons, warning banners. A black-and-white brand can carry a deep red in its CSS because the red is the colour of a validation message.
The case that made this concrete was exactly that: a monochrome brand whose proposed palette led with red. The red was real, in the CSS, for an error state. The HTML the server sent was a near-empty shell that rendered in the browser. Nobody visiting the site had ever seen that red.
Read the pixels
The fix was to look at the page the way a visitor does. The reader now renders the page, samples its pixels, and clusters the colours by painted area. A monochrome page yields a monochrome palette, and a red brand keeps its red. Anti-aliased edges, which leave a smear of in-between colours along every shape, are handled by ranking rather than by trying to identify edge pixels one at a time.
The stylesheet is still useful, as a source of exact values and names. The two are reconciled with the screen leading and the stylesheet labelling, plus one guarantee that carries the whole safety argument: a colour the stylesheet declares, and which actually paints on screen, keeps its place however small its area. A brand whose only accent is a single button may cover well under one percent of a page. Ranking by area alone would lose it.
The sampler checking itself
Before trusting the new reader, I replayed it over sixty-two existing workspaces and checked its results with a second, independent instrument: a full-resolution pixel count with no clustering at all.
The replay found three colours the sampler had declared absent that were plainly on screen, covering between about a sixth of a percent and two percent of their pages. The cause was in the clustering. Greedy merging folds a colour into a larger neighbour, so the cluster reports the neighbour's value and the declared colour matches nothing. A colour can be a real part of a page and invisible to the summary of it.
Confirmation now reads a histogram taken before any merging, which does not depend on how the clustering turned out. After the change, the independent count found no blind spots. The threshold for confirming a colour was then set from the measured populations, the smallest real colours on one side and stray traces on the other, rather than chosen by feel.
The part I keep returning to: the sampler, asked to check its own work, agreed with itself on every colour it had dropped. Only the independent instrument disagreed. That is the reason to build one.
Colours nobody chose
Two families of colour turned up in palettes that could never have been a brand decision. One is browser defaults: the bright blue of an unstyled link, its purple visited partner, the bare keyword colours. These appear when a stylesheet says nothing at all. The other is embedded third-party chrome, a video player or a map, painting its own colours into the page. Eight of a hundred and twenty workspaces held one of these as a brand colour.
They are now named in a short, exact-match list. The scan does not write them to the kit, and the onboarding screen shows them unticked rather than hiding them, so a business that genuinely uses that blue can keep it with one press. The filter runs before colour roles are assigned, because a role is a position in the list. A colour nobody chose does not merely take a slot. It becomes primary.
A framework's default blue is not on the list. Choosing your framework's default is still choosing.
Invert is not darken
One last case from the same fortnight. To show a logo on a dark background, the code inverted marks that would otherwise disappear. An inversion flips each colour channel, which turns black to white and also turns every hue into its opposite. A black wordmark with a single pink dot came back with a green dot.
The check had decided on luminance alone, and a small coloured detail barely moves average luminance, so the mark measured as dark and was inverted, brand colour and all. It now measures saturation in the same pass. A mark with a meaningful share of coloured ink is never inverted. A logo that reads poorly on one background is a legibility problem the owner can see and solve. A logo whose brand colour has been silently replaced is a far worse error, and it would be repeated in everything made from it.