The xSwarm Style Guide
The single source for colour and material, what "slightly skeuomorphic" means in tokens, and the two rules an audit enforces so this stays true.
Chad, 2026-09-17: “I asked for a stunning, slightly skeumophic, award-winning design for the tickets and the web interface. and I got a 1px line red box. That was a serious UI fail.”
It was, and the cause was not taste. It was that there was no style guide, so there was nothing
for anyone — human or agent — to build to. Measured across packages/web/src the day this was
written:
Svelte components with no <style> block at all |
16 of 37 |
hard-coded colour literals outside theme.css |
1,909 |
| files carrying them | 82 |
| design tokens already defined and bypassed | 68 |
A component with no styles renders as raw markup — a thin bordered box. That is the red box. It was not designed badly; it was not designed.
One source, and it already exists
packages/web/src/styles/theme.css is the only place a colour or a material value is defined.
Nothing else declares one. Not a component, not a page, not a second stylesheet.
Every semantic value is a light-dark() pair, because the two modes are not the same design:
--color-surface: light-dark(rgb(249 250 251), rgb(39 39 42));
--shadow-raised: light-dark(0 2px 4px rgba(17 24 39 / 0.08), 0 2px 6px rgba(0 0 0 / 0.5));
Write var(--color-surface). Never #f9fafb, never rgb(249 250 251), and never a dark: prefix
— the pair is the definition, so there is no second ruleset to keep in sync and no way for the two
modes to drift apart.
If a value you need does not exist, add it to theme.css. That is a smaller change than
inlining it, and it is the only version of the change that helps the next component.
What “slightly skeuomorphic” means here
Material honesty, not ornament. A raised surface catches light along its top edge and casts a shadow below. A pressed one inverts both. That is the entire vocabulary, and it is four tokens:
.card {
background: var(--color-surface);
background-image: var(--surface-raised); /* a <3% top lift, not a gradient you can see */
box-shadow: var(--shadow-raised), var(--highlight-top);
border-radius: var(--radius-md);
}
.card:active { box-shadow: var(--shadow-pressed); }
--highlight-top is the token that matters. A 1px inner light line along the top edge is what
makes a surface look lifted rather than merely outlined — it is the difference between this and the
flat box that prompted the guide.
Three elevations only: --shadow-resting, --shadow-raised, --shadow-floating. A fourth is
decoration. One radius scale, so a card and the button inside it cannot disagree by a pixel.
Restraint is the “slightly”. Bevels under 1px of light, gradients under 3%, no inner glows on text, no drop shadows on type. If a surface’s depth is the first thing you notice about a screen, it is too much.
Components own their styles
From CLAUDE.md, and it is load-bearing rather than stylistic:
- Self-contained. All styles in the component’s own
<style>block. No external CSS file per component. - Generic, not content-specific.
Chart, notTokenChart. Variants via props, not new files. - One file per component.
Card variant="tiny", neverCardTiny.svelte.
A component with no <style> block is not “using the defaults”. There are no defaults. It is
unstyled, and it will look like the red box.
What is enforced, and where
A rule nothing checks is a wish. CLAUDE.md has said “semantic colors only” and “single source”
for a long time, and the count above is 1,909 — so this guide ships with an audit rather than
hoping.
quality/ui-audit.mjs reports two things, and the quality gate ratchets both: the number can hold
or improve, never regress.
unstyled-component— a.sveltecomponent with no<style>block.hard-coded-colour— a hex,rgb(),rgba()orhsl()literal anywhere underpackages/web/srcexcepttheme.css.
The refactor stage runs the whole suite, so a ticket that adds either one is caught inside the ticket that added it — which is the only moment the person who wrote it still remembers why.
Neither number has to reach zero to be useful. Both are debt with a direction, and the ratchet is what makes the direction real.