Design system
The UI has a semantic token layer (ui/src/app.css — --color-* surfaces/text/accents, the --fs-* type scale, --status-*/--wash-*) and a live reference page that documents it plus the canonical component recipes: /design-system (ui/src/routes/design-system/+page.svelte). It exists to stop design drift — every session re-inventing buttons, spacing and colors.
No automated gate flags off-token colors. This rule and review are the only enforcement.
- Consult
/design-systemfirst. It renders the live tokens (swatches read straight offapp.css, so they can’t drift) plus the button / form-field / badge / panel / scrim recipes, each with a when-to-use note and copy-paste markup. - Use the tokens, never literals. Every color is
var(--color-*); every font size isvar(--fs-*). Never introduce a raw hex,rgba(), or ad-hocpxfont size — if you reach for one, the token you need already exists (or belongs inapp.css). - Reuse a recipe before authoring a new component. Match the existing
.gbtn/ field /.badge/.panelconventions; don’t grow a per-element Tailwind utility stack for headings or buttons. - Accent hues are semantic, not decorative — pick by meaning.
--color-greenis reserved for genuinely actionable-complete (READY); a finished-but-parked session is slate (--status-done), never green. - Every blocking (modal) dialog/drawer dims and blurs what’s behind it — when a surface seizes interaction and app content stays visible behind it, that surface must read as the focus (desktop and mobile alike). Use the canonical backdrop from
app.css: the global.scrimclass (full primitive) for a new backdrop, orclass="overlay"for modal overlays (which inherit the same blur). Never ship such a surface with a fully-lit background or a hand-rolled backdrop without the blur. See the Modal & scrim recipe on/design-system. Two scope notes so the rule isn’t over-applied:- Exempt — opaque full-cover view-swaps: an
aria-modalsurface that fully covers its area (e.g. BacklogView’s mobile master→detail.mobile-detail-overlay, a solid--color-insetpanel that replaces the list in-place) — there is nothing visible behind it to dim, and a translucent scrim would only let the covered view bleed through. The rule is about visible-background floating surfaces, not full-bleed navigation. - Exempt — small anchored, non-blocking popovers: a
role="dialog"that is notaria-modaland floats anchored to a trigger (e.g. AutomationPanel’s.auto-pop, EmojiPicker’s.ep) does not seize the app or warrant a full-screen backdrop — no scrim, dismiss on outside-click/Esc instead.
- Exempt — opaque full-cover view-swaps: an
The /design-system page is a developer/agent-facing internal reference (unlinked from the app), so it is exempt from i18n and the feature catalog.