The rules
Sections 17 and 18 of the Brand Guide, plus the product rules this system adds. These are hard stops, not preferences.
Never
| Rule | Why |
|---|---|
Never a raw hex on a shadcn token ( --card, --primary, --border…) | The light/dark flip lives in the semantic layer; a hex breaks the other mode silently |
Never a colour outside the palette | Every value you need has a token. If you cannot find it, ask |
Never mix two vertical accents (sky + orange) on one surface | It breaks the brand architecture |
Never a coloured top or left border on a callout | Callouts are bracket corners. The warning Alert is the one exception |
Never pure black text or pure white surfaces | #1C1C1E on cream, warm white on charcoal |
Never a pure white card on cream | Cream or warm white |
Never the display font for body copy | DM Sans is display; Inter is the workhorse |
Never more than three weights on a screen, or two families in a paragraph | |
Never emoji or a second icon pack as icons | lucide only, stroke 2 |
Never mix filled and line icons in one component | |
Never a fifth button variant, a third product radius, a fourth font | Each is a decision already made |
Never a rainbow or multi-stop gradient | One soft accent glow, or the vertical fade |
Never two textures stacked | Grid or dots, never both |
Never navigation in the account menu | It holds appearance and sign-out |
Never a second list of what exists | One PRODUCTS, rendered three ways |
Never a redirect table for moved routes | A 404 that names the move is honest; a redirect rots |
Never a disabled control without its reason | Use a badge, or a tooltip |
Never a toast as the only record of a failure | It disappears with the evidence |
Never colour a figure to mean "good" | Colour states, not numbers |
Never em-dashes or en-dashes in copy | Commas, periods, or "to" for ranges |
Never the parent wordmark on a vertical surface | Use the vertical's own mark |
Always
| Rule | What it means |
|---|---|
One primary action per surface | Everything else is quiet |
One <h1> per screen, and it is PageHeader's | |
Figures are mono and tabular | So columns can be scanned |
Every table pins its header and sorts every column | Enforced by tools/standards.mjs in CI. An exemption must argue itself in a comment |
Every component comes through shadcn | shadcn add @8020iq/<item>. Never hand-copied, never a second source |
Every column that counts something says what it counts | info on the header |
Every stat has a qualifier line | A number alone is not a fact |
Labels are mono caps | Type marks a section, not a coloured rule |
Hit targets are 44px | Even when the visual box is smaller |
Focus is visible, always | 3px ring, never removed |
Both themes work | Both attributes are read; test in both |
The accent is the subject, semantics are states | Do not swap their jobs |
Copy is short, English, and reads like a tool | Caveats live in the docs, not the chrome |
Say what the data is | A record of sign-ins is not a roster |
When you disagree with a rule
Say so, name the cost, and get a decision. Do not route around it silently — every rule in this file is here because routing around it cost somebody a day.