One system, four identities
Structure, spacing and component behaviour stay shared. Brand colors change through a named platform theme; type pairs Poppins headlines with Figtree body text.
Shared foundations for bikeable, walkable, accessable and schoolable. The examples below use the same tokens and production components as the platform itself. Version 0.1.0, 94 tokens, 4 themes.
Structure, spacing and component behaviour stay shared. Brand colors change through a named platform theme; type pairs Poppins headlines with Figtree body text.
Prefer roles such as --color-error and --brand-strong over copying hex values into a product.
Components retain visible focus, meaningful labels, keyboard behaviour and non-color cues as part of their contract.
Choose the format that fits the consumer. All generated formats come from the same DTCG source and share version 0.1.0.
manifest.jsonDTCG tokensCanonical exchange formattokens.dtcg.jsonResolved JSONReady for scripts and applicationstokens.jsonCSS variablesReady for websitestokens.cssLLM indexShort map for agents and assistantsllms.txt<link rel="stylesheet"
href="/design-system/api/v1/tokens.css">
<body data-moveable-theme="bikeable">
…
</body>const system = await fetch(
'/design-system/api/v1/tokens.json'
).then(response => response.json())
system.platformThemes.walkable.brand.accent<ButtonPrimary>Save changes</ButtonPrimary>
<ButtonSecondary href="/spots">Cancel</ButtonSecondary>
<style>
.panel {
padding: var(--spacing-2);
border-radius: var(--radius-lg);
background: var(--color-surface);
}
</style>Every card below comes from the canonical theme tokens. Switch the active platform to preview the full page and component gallery.
accent#33bdcastrong#005579soft#c6e9ecsubtle#f0f9fapage#e9f4f5 Headline: 'Poppins', sans-serif
Body: 'Figtree', sans-serif
accent#00af7dstrong#046441soft#c3eee0subtle#F6FDFApage#ecf9f4 Headline: 'Poppins', sans-serif
Body: 'Figtree', sans-serif
accent#353DE5strong#163898soft#DBE3F8subtle#F9FAFEpage#F3F5FD Headline: 'Poppins', sans-serif
Body: 'Figtree', sans-serif
accent#F1C100strong#3F3828soft#FFF1B1subtle#FFFEF8page#fffcf2 Headline: 'Noto Serif', serif
Body: 'Figtree', sans-serif
text#000000text muted#636363surface#ffffffsuccess#2f7d08error#dc0020The CSS name is the public interface. The displayed value is generated from the matching DTCG token.
--spacing-00px--spacing-px1px--spacing-0-50.3125rem--spacing-10.625rem--spacing-1-50.9375rem--spacing-21.25rem--spacing-2-51.875rem--spacing-32.5rem--spacing-45rem--spacing-57.5rem--radius-sm0.25rem--radius-md0.375rem--radius-lg0.875rem--radius-xl1rem--radius-2xl2rem--radius-full9999px--font-size-smMoveable streets and spaces
--font-size-baseMoveable streets and spaces
--font-size-mdMoveable streets and spaces
--font-size-lgMoveable streets and spaces
--font-size-xlMoveable streets and spaces
--font-size-2xlMoveable streets and spaces
--font-size-3xlMoveable streets and spaces
--font-size-4xlMoveable streets and spaces
--font-size-5xlMoveable streets and spaces
--shadow-sm--shadow-md--shadow-lg--gutter--header-height--site-width--site-max-width-6xl--container-width-lg--container-width-md--container-width-sm--container-width-xsPoppins
Light 300Regular 400Semibold 600Bold 700
Headings, logo wordmark and display text. Upright only.
Figtree
Regular 400Semibold 600Bold 700Italic
Running text, UI labels and charts. Variable 300–900 with a true italic; base line-height 1.5.
H1: Better streets begin with people who use them every day.
H2: Make everyday journeys visible.
H3: Share what works and what needs attention.
H4: One observation can start a useful conversation.
Body: Moveable helps people document everyday mobility and improve public space together.
Long-form (spot descriptions): 18px with a 1.6 line-height and a 65ch measure keep longer reports comfortable to read. Comments and author names use 16px; metadata drops to 13px.
Supporting text uses the shared muted semantic color.
.text-link exampleARIA combobox pattern. Type to trigger autocomplete via the real API.
Accessible replacement for window.confirm(): role="alertdialog", named by its message, focus starts on the non-destructive choice, Escape cancels.
Every action button is ButtonBase or one of its wrappers (ButtonPrimary, ButtonSecondary, ButtonSubmit). Pass to or href for a link that looks like a button, and icon for a leading icon. Always set type inside a form.
A plain <button> with its own styles is right only where a button isn't an action button: icon-only buttons and close (✕), toggles and tabs, dropdown triggers, list rows and selectable tiles, and inline text-link actions ("Reply", "Show older"). Say why in a comment when it could be mistaken for one.
One shape for every badge, pill and chip: the badge() mixin (fully rounded, --font-size-sm, padding 5/10px, or 2/10px with badge(sm) in dense rows). Colours stay with each badge because they carry meaning.
BadgeTag:
bauarbeiten
status, sm:
WeitergeleitetUserImage:
LoadingSpinner is the only spinner. It announces "Loading" unless decorative is set (inside a region that already announces). Inside a filled button, set --spinner-color: currentColor.
Static examples use local placeholders and are intentionally inert, so the public guide never links to mock content.

Beispielstrasse 1, 8000 Zürich

Beispielstrasse 1, 8000 Zürich

Beispielstrasse 1, 8000 Zürich
Raster icons from public/map-icons, registered with MapLibre by loadMapIcons(). Circles mark spots at low zoom, pins take over when zoomed in.
Icon-only controls need a name on the interactive element. Form controls need a visible label and errors connected with aria-describedby.
Everything interactive must work by keyboard, expose a visible focus state and preserve expected Escape and arrow-key behaviour.
Text and UI boundaries meet their contrast targets. Status never relies on color alone, and decorative imagery stays silent.
Press Tab from the top of the page to reveal the global skip-link (rendered in app.vue). Not visible until focused.
The form of address follows the audience, and the i18n namespace decides it: premium, shares, forwarding, forwardingContacts and org_request are organisation tools; every other namespace, including error pages and the internal admin, is community.
Public pages, the account, notifications, errors and the admin use du, tu and tu: Bitte versuche es später erneut.
Premium, forwarding, the address book, shares and the partner request address the organisation with Sie, vous and voi: Ihre Organisation hat noch keine News veröffentlicht.
Buttons, placeholders and option labels carry no form of address: the infinitive in German and French (Speichern, Enregistrer), the usual imperative in Italian (Salva). English says “you” throughout.
Say “good spot” and “problem spot” (guter Ort / Problemstelle, point positif / point à améliorer, punto positivo / punto critico), from spots.type_good and spots.type_problem. Fame and shame are the API terms only; not Top/Flop, not Lob (#256).
Headings, buttons, labels and navigation capitalise only the first word and proper names: “Notification logs”, “OGC API clients”.