Design conventions
How every WDS prototype is built so they read as one set: the shared kit, the colour tokens, the hub chrome, the working rules, and how to start a new prototype.
The shared kit
Every prototype imports one stylesheet, prototypes/_kit/proto.css, the single source of truth for look-and-feel. Do not fork it per prototype: edit the kit and every prototype stays in step. Each prototype's <head> links the kit and the three type faces (Poppins for headings, Inter for text, Material Symbols for icons); nothing else styles the chrome.
Colour tokens
The kit carries the WDS colour set in three layers: the canonical registry swatches (surface scale, text, links, phase, booking status, functional states), a dark-mode binding that maps them to semantic slots, and a sampled product chrome ramp for the console surfaces. Prototypes are dark-only. Bind semantic tokens, never raw hex. Rose (#fe2767) is interactive-only; gold/champagne is non-interactive emphasis; sky is structural.
The hub chrome
A prototype is a console (.pc) assembled from the standard parts, in this order: the top navigation bar, the sub-nav pills, then per view a toolbar, an optional filter bar, a table header, the rows, and a footer. The toolbar action cluster is fixed: Search · Actions · Filter · Settings · Share · Add, with Search and Actions labelled and Filter/Settings/Share icon-only. The table header carries the count, order-by, density and view toggles. Filtering uses stacking removable chips with popovers; selection uses the bulk-select bar. Status reads through the badge set.
Working rules
No em dashes anywhere. British spelling. Always styled “Wavecast” and “WDS”. Rose is interactive-only. Keep the chrome on the kit's tokens and components, never bespoke palettes or fonts. Prototypes are dark-only for now; a light binding can be added to the kit when needed.
Naming and scoping
Reuse the kit's chrome classes as they are (nav, toolbar, pills, table header). But when a prototype adds its own component, give it a prototype-unique class name; never reuse a kit class name for a bespoke element. The kit owns ~175 class names, many short (t, v, k, on, icon, vbtn), so a bespoke element that borrows one silently inherits the kit's rules. A labelled toolbar button once reused .vbtn (the kit's small icon-only table-header toggle) and got capped to icon width, so its label overflowed and collided. Prefix bespoke classes per prototype (for example pv- for a photo viewer) so they can't clash. A linter enforces this: python3 _build/lint_prototypes.py flags any prototype that styles a kit class name, and warns about a position:fixed overlay that isn't reparented to <body>. Run it before publishing.
Full-screen overlays
The kit centres the console (.pc) with a CSS transform, and a transformed ancestor becomes the containing block for position:fixed descendants. A fixed overlay left inside .pc is therefore trapped at console width, not the viewport. Reparent any full-screen overlay to <body> on load (document.body.appendChild(el)) so it fixes to the viewport. The photo viewer does this.
Starting a new prototype
Create prototypes/<slug>/prototype.html, link the kit and the three font faces in the head, and build the console from the standard parts above. Then add one entry to the PROTOTYPES list in _build/rebuild_all.py (slug, title, type, blurb) and rebuild: the card appears in the grid automatically and opens the prototype in a new tab. Drop a thumb.png in the folder to use a static screenshot instead of the live preview. Run lint_prototypes.py before you publish.
The shared kit and rules that keep every WDS prototype part of the same set.