Why it is built this way

This is not a component library. It is a product with its system taken out of it. Every rule here was paid for by something that shipped wrong, and each one is written down beside the measurement that produced it. There is no build step and no gate: what you write is what ships, and nothing will stop you doing the wrong thing. That is deliberate, and this page is the trade you get instead.

Five minutes gets you the shape. The contract is docs/architecture.md and the account of what each rule cost is in the two CLAUDE.md files.

49 components 1 stylesheet per screen 0 generators 0 gates

What you are looking at

Three trees and one system. The trees are the same product drawn three times, and each one owns a different half of the truth, which is why a change often belongs in a folder you were not editing.

folderwhat it ownswhat it links
wireframes/ structure and copy, in grey. A block is decided here first and the colour copy follows no stylesheet at all
ui-visual/ the visual layer only. 109 screens plus an index, one per state exactly components/index.css
ui-kit/ the vitrine. A shelf per level, a page per component, six foundations the system, plus its own stand furniture
components/ the system. 56 stylesheets, one per component plus the substrate is the thing being linked

A screen carries no styles of its own, and that is the load-bearing one. Measured by reading every stylesheet link in the painted tree: 109 of 110 documents link ../components/index.css and nothing else, and the one exception is the index of the tree rather than a screen in it. No @media, no @keyframes, no style= except a datum, the event photograph, or a value a script writes at run time. If you find yourself opening a screen file to change how something looks, the change belongs somewhere else.

A state is a page. Loading, empty, error, logged out, chosen: each is its own document in both trees. That is why there are 109 screens and not fifteen, and it is the only reason a state can be measured at all. A rule that cannot be rendered cannot be checked, and it will be wrong the day it first draws.

Five decisions that explain the rest

Almost every rule further down is a consequence of one of these. If a rule looks arbitrary, it is usually the fifth or sixth step of one of them.

1. Two token levels, and the second theme is the proof

A raw value is a primitive. A colour is a role. A component reads a role and never a colour primitive, and there is no third level. The proof that the second level is real is that a whole second theme can be written by re-declaring roles alone. A component that reaches past a role into a primitive cannot be re-themed, and it fails silently: it simply keeps its dark colour on a pale ground. Every specimen on this stand is drawn in both themes side by side for exactly that reason.

2. Green and red are outcome semantics. Brass is the brand

Vault, darkDaylight, light

Green means YES and red means NO, on a market outcome, and nowhere else. A success message is not green here and a validation error is not red. The brass is the only thing in this product that is the brand, and it carries every primary action, which is why the button beside the pair is not green. Borrow an outcome colour for an accent and you have taught a reader that a saved form is a winning bet.

3. A level is containment, not importance

An atom holds nothing from the system. A molecule holds atoms or its own named parts. An organism holds molecules or is a screen shell, and that is the ceiling. A pattern is a composition standing on three screens or more, carries arrangement only, and holds no colour, face, border or surface at all.

14atomsa control that contains nothing
16moleculesthey hold atoms, or their own parts
13organismsthey hold molecules, or they are a shell
6patternsarrangement only, three screens or more

The level is not a label on a page, it is the order of @import in components/index.css: a part is imported before the whole that holds it, so a later rule can out-specify an earlier one without either raising specificity. Moving a file between groups is a level decision, not a tidy-up. Two screens is a candidate, not a pattern, and it stays markup.

4. Three rungs, in rem, named by what arrives at them

40remDESK640px at the default browser font
47.5remDETAIL760px, where the bet panel arrives
56.25remRAIL900px, where the rail arrives

They are in rem, so a reader who set a 24px default reaches the desk at 960 and keeps one column until then. The registry in tokens.css is the instrument, because @media cannot read a var(): the literal in every query has to be a number on the list, and a number that is not on the list is a rung somebody invented quietly. Counted today: 35 width queries in the system and 0 in any painted screen. Read the whole argument on responsive.

5. Movement names its job before it is written, and there are three

response--dur-fast, .16sa control answering a finger
arrival--dur-slow, .25san element saying it is here
status--pulse-period, 1.4sa process still running. A period, not a rung

A moment for which none of the three can be named does not enter the register and never gets a movement. Under prefers-reduced-motion the tokens themselves are re-declared, so a component that reads them obeys without knowing the setting exists, and there is no blanket * net and will not be one: under it a component that reads no token is indistinguishable from one that reads every token, so the check can no longer fail. Operate the specimens on motion, because a screenshot shows a frame and never a movement.

The five minute path

In this order. Each step ends in something you can look at rather than something you have to take on trust.

  1. 1Open a finished screen and view its source. One stylesheet link, and no rules of its own. That is the whole boundary between the product and the system, and everything else follows from it.
  2. 2Open its grey twin in another tab. Same blocks, same words, no colour. The grey tree decides what is on the page and the painted tree decides what it looks like, so a disagreement between them is always a defect in the paint.
  3. 3Pick one thing on that screen, say a card, and open its page. Every component has one: what it IS, its anatomy, every state in both themes, its rule and its anti-rule, which is the component you should have used instead.
  4. 4Open components/card.css and read only the header. It names every class the file styles, every token it reads, its page on this stand, and how many screens carry it. That header is a contract: if a class is listed there and the file does not style it, that is a defect, and the sweep for it runs to zero today.
  5. 5Read docs/architecture.md, sections 10 to 13: the fifteen prohibitions, how to add a component, how to add a pattern, and where a change goes. That is the part you actually need before touching anything.
  6. 6When something behaves strangely, read components/CLAUDE.md before debugging. It is a list of things that were true and looked fine, and there is a real chance yours is already in it.

What will bite you

Four of these cost this repository days rather than hours. They share one shape: a rule that was present, correct, and not applying, which is the failure no test reports because nothing throws.

A declaration replaces, it does not extend

Write transition on a face and it replaces the list the atom declared, silently dropping every property the atom named. Sign-in buttons lost color and box-shadow that way. The response belongs to the control: one declaration on the atom, carrying the union of what any face changes.

A fade is a stacking context

A box whose opacity is under 1 is a stacking context, so a panel fading in has its own z-index resolved inside that group for as long as the fade runs. Menus opened under the first card for 160ms and then jumped on top. The lift belongs to the box the fade turns into a context, not to the panel inside it.

A missing value is a value

An SVG with no fill is black. A link with no colour is the browser's blue. A class the system does not define takes the user agent's own button, which is grey 239 in Chromium and 192 in WebKit. Reading the source cannot see any of it. Read the computed page, in a browser, in both engines.

A count is right and the thing is wrong

A component page said "242 placements" and drew one glyph; the 242 are three different marks, one of which does not exist on a phone. A verdict about a component is a statement about the SET of its placements, and where placements disagree you say so rather than picking one.

An id is a promise a component stands once

Nine declarations were keyed to a document-unique id, so two of the components could not be placed twice in one document by anybody. Nothing was broken until a stand tried to show one component twice. No component in a design system may make that promise.

A class with no rule looks exactly like a class with one

The markup renders either way. The only licence a class has to draw nothing is a Script hooks: line in the owning stylesheet's header, and four files carry one. Anything else that answers to no selector is a defect wearing a component's name.

There is no build, so this is how a thing is checked

The vitrine that stood here had 41 gates, 54 generators and 145 MB of screenshots, and it was deleted in one commit without the product moving a pixel. The measurement had become a machine that was re-paid on every edit. So every check is an ACT: write the script in a scratch folder, run it, write down what it said, and delete it. What stays is the report and the reason.

  1. 1Read the instrument before the finding. Measure the same thing twice unchanged and the difference has to be zero. Throw the first pass away: a cold pass resolves fonts and stylesheets for the first time and differs from every pass after it. A number that moves when nothing moved is a reading of the instrument.
  2. 2Give it something it must see. A reading that cannot come back red is a reading of the guard. Inject a box wider than the window, or a rule that disobeys, and confirm the probe reports it before you believe a zero.
  3. 3Assert the branch you are measuring is on. A headless browser is pointer:fine, so a tap-target sweep without touch emulation measures a product with the 44px floor switched off, and every number it prints is about a page that does not exist.
  4. 4Two engines, and disk as well as server. Chromium has agreed with a visibly broken page three times here. Over file:// every document has its own opaque origin, so anything fetched in CORS mode never arrives.
  5. 5Measure at the rungs and one pixel either side, not at 390 and 1280. A defect can live entirely between the two widths everybody reads, and one did: 73 documents scrolled sideways at exactly one width while every sweep reported zero.
  6. 6Read the set, not the document. Every instrument here reads one page, so a fact that stands on two pages is owned by neither. Three markets were Open on one tab and WON on the tab beside it, and 868 renders reported nothing.

All six are in the root CLAUDE.md with the measurement that produced each, and section 14 of the contract is the short form.

Where everything lives

A fact written twice is a fact that will drift, so each of these is written in one place and referred to from everywhere else. If you find the same number in two files, one of them is already wrong.

questionowner
how the system is entered, and what you may not doui-kit/docs/architecture.md
what each rule cost, dated, with the measurementCLAUDE.md and components/CLAUDE.md
the visual language and why each choice was madeDESIGN.md
what the product is, and the market catalogPRODUCT.md
every component's level, placements and behaviour on widthdocs/inventory.md
the ladder, and the audit for every screendocs/responsive.md
the motion transcript, the moments and the rulingsdocs/motion.md
the system read against the productdocs/consistency.md
every string the product saysvoice/docs/microcopy.md
where a reader can go, and the SEO layeria/docs/
what was done and why, newest firstdocs/decisions.md
what is still opendocs/backlog.md
which stage is donethe status table in README.md
where a file livesSTRUCTURE.md

One last thing, and it is the habit rather than a rule. Every number on this page was measured on the day it was written and says so. A count typed into prose is a count that goes stale, and this repository has caught itself doing it often enough to stop trusting any figure that does not name the day it was taken. When a number here disagrees with the repository, the repository is right.